1 diff -Nrup a/fs/yaffs2/devextras.h b/fs/yaffs2/devextras.h
2 --- a/fs/yaffs2/devextras.h 2010-10-03 17:48:22.704000363 +0300
3 +++ b/fs/yaffs2/devextras.h 2010-10-03 18:03:47.537000367 +0300
6 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8 - * Copyright (C) 2002-2007 Aleph One Ltd.
9 + * Copyright (C) 2002-2010 Aleph One Ltd.
10 * for Toby Churchill Ltd and Brightstar Engineering
12 * Created by Charles Manning <charles@aleph1.co.uk>
17 +#include "yportenv.h"
19 #if !(defined __KERNEL__)
21 /* Definition of types */
22 @@ -33,103 +35,6 @@ typedef unsigned __u32;
27 - * This is a simple doubly linked list implementation that matches the
28 - * way the Linux kernel doubly linked list implementation works.
32 - struct ylist_head *next; /* next in chain */
33 - struct ylist_head *prev; /* previous in chain */
37 -/* Initialise a static list */
38 -#define YLIST_HEAD(name) \
39 -struct ylist_head name = { &(name), &(name)}
43 -/* Initialise a list head to an empty list */
44 -#define YINIT_LIST_HEAD(p) \
51 -/* Add an element to a list */
52 -static __inline__ void ylist_add(struct ylist_head *newEntry,
53 - struct ylist_head *list)
55 - struct ylist_head *listNext = list->next;
57 - list->next = newEntry;
58 - newEntry->prev = list;
59 - newEntry->next = listNext;
60 - listNext->prev = newEntry;
64 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
65 - struct ylist_head *list)
67 - struct ylist_head *listPrev = list->prev;
69 - list->prev = newEntry;
70 - newEntry->next = list;
71 - newEntry->prev = listPrev;
72 - listPrev->next = newEntry;
77 -/* Take an element out of its current list, with or without
78 - * reinitialising the links.of the entry*/
79 -static __inline__ void ylist_del(struct ylist_head *entry)
81 - struct ylist_head *listNext = entry->next;
82 - struct ylist_head *listPrev = entry->prev;
84 - listNext->prev = listPrev;
85 - listPrev->next = listNext;
89 -static __inline__ void ylist_del_init(struct ylist_head *entry)
92 - entry->next = entry->prev = entry;
96 -/* Test if the list is empty */
97 -static __inline__ int ylist_empty(struct ylist_head *entry)
99 - return (entry->next == entry);
103 -/* ylist_entry takes a pointer to a list entry and offsets it to that
104 - * we can find a pointer to the object it is embedded in.
108 -#define ylist_entry(entry, type, member) \
109 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
112 -/* ylist_for_each and list_for_each_safe iterate over lists.
113 - * ylist_for_each_safe uses temporary storage to make the list delete safe
116 -#define ylist_for_each(itervar, list) \
117 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
119 -#define ylist_for_each_safe(itervar, saveVar, list) \
120 - for (itervar = (list)->next, saveVar = (list)->next->next; \
121 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
124 #if !(defined __KERNEL__)
126 diff -Nrup a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
127 --- a/fs/yaffs2/Kconfig 2010-10-03 17:48:22.704000363 +0300
128 +++ b/fs/yaffs2/Kconfig 2010-10-03 18:03:47.461000368 +0300
129 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
133 -config YAFFS_DISABLE_LAZY_LOAD
134 - bool "Disable lazy loading"
135 - depends on YAFFS_YAFFS2
136 +config YAFFS_DISABLE_TAGS_ECC
137 + bool "Disable YAFFS from doing ECC on tags by default"
138 + depends on YAFFS_FS && YAFFS_YAFFS2
141 - "Lazy loading" defers loading file details until they are
142 - required. This saves mount time, but makes the first look-up
145 - Lazy loading will only happen if enabled by this option being 'n'
146 - and if the appropriate tags are available, else yaffs2 will
147 - automatically fall back to immediate loading and do the right
150 - Lazy laoding will be required by checkpointing.
152 - Setting this to 'y' will disable lazy loading.
153 + This defaults Yaffs to using its own ECC calculations on tags instead of
154 + just relying on the MTD.
155 + This behavior can also be overridden with tags_ecc_on and
156 + tags_ecc_off mount options.
160 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
161 but makes look-ups faster.
165 +config YAFFS_EMPTY_LOST_AND_FOUND
166 + bool "Empty lost and found on boot"
167 + depends on YAFFS_FS
170 + If this is enabled then the contents of lost and found is
171 + automatically dumped at mount.
175 +config YAFFS_DISABLE_BLOCK_REFRESHING
176 + bool "Disable yaffs2 block refreshing"
177 + depends on YAFFS_FS
180 + If this is set, then block refreshing is disabled.
181 + Block refreshing infrequently refreshes the oldest block in
182 + a yaffs2 file system. This mechanism helps to refresh flash to
183 + mitigate against data loss. This is particularly useful for MLC.
187 +config YAFFS_DISABLE_BACKGROUND
188 + bool "Disable yaffs2 background processing"
189 + depends on YAFFS_FS
192 + If this is set, then background processing is disabled.
193 + Background processing makes many foreground activities faster.
198 + bool "Enable yaffs2 xattr support"
199 + depends on YAFFS_FS
202 + If this is set then yaffs2 will provide xattr support.
206 diff -Nrup a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
207 --- a/fs/yaffs2/Makefile 2010-10-03 17:48:22.705000363 +0300
208 +++ b/fs/yaffs2/Makefile 2010-10-03 18:03:47.460000369 +0300
211 obj-$(CONFIG_YAFFS_FS) += yaffs.o
213 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
214 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
215 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
216 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
217 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
218 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
219 +yaffs-y += yaffs_nameval.o
220 +yaffs-y += yaffs_allocator.o
221 +yaffs-y += yaffs_yaffs1.o
222 +yaffs-y += yaffs_yaffs2.o
223 +yaffs-y += yaffs_bitmap.o
224 +yaffs-y += yaffs_verify.o
226 diff -Nrup a/fs/yaffs2/moduleconfig.h b/fs/yaffs2/moduleconfig.h
227 --- a/fs/yaffs2/moduleconfig.h 2010-10-03 17:48:22.705000363 +0300
228 +++ b/fs/yaffs2/moduleconfig.h 2010-10-03 18:03:47.538000366 +0300
231 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
233 - * Copyright (C) 2002-2007 Aleph One Ltd.
234 + * Copyright (C) 2002-2010 Aleph One Ltd.
235 * for Toby Churchill Ltd and Brightstar Engineering
237 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
239 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
240 /* #define CONFIG_YAFFS_DOES_ECC */
242 +/* Default: Selected */
243 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
244 +#define CONFIG_YAFFS_DOES_TAGS_ECC
246 /* Default: Not selected */
247 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
248 /* CONFIG_YAFFS_DOES_ECC is set */
249 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
251 -/* Default: Selected */
252 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
253 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
254 +/* Default: Not selected */
255 +/* Meaning: Always test whether chunks are erased before writing to them.
256 + Use during mtd debugging and init. */
257 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
259 +/* Default: Not Selected */
260 +/* Meaning: At mount automatically empty all files from lost and found. */
261 +/* This is done to fix an old problem where rmdir was not checking for an */
262 +/* empty directory. This can also be achieved with a mount option. */
263 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
265 /* Default: Selected */
266 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
267 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
270 -/* Meaning: set the count of blocks to reserve for checkpointing */
271 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
272 +/* Default: Unselected */
273 +/* Meaning: Select to disable block refreshing. */
274 +/* Block Refreshing periodically rewrites the oldest block. */
275 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
277 +/* Default: Unselected */
278 +/* Meaning: Select to disable background processing */
279 +/* #define CONFIG_DISABLE_BACKGROUND */
282 +/* Default: Selected */
283 +/* Meaning: Enable XATTR support */
284 +#define CONFIG_YAFFS_XATTR
287 Older-style on-NAND data format has a "pageStatus" byte to record
288 diff -Nrup a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c
289 --- a/fs/yaffs2/yaffs_allocator.c 1970-01-01 02:00:00.000000000 +0200
290 +++ b/fs/yaffs2/yaffs_allocator.c 2010-10-03 18:03:47.504000356 +0300
293 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
295 + * Copyright (C) 2002-2010 Aleph One Ltd.
296 + * for Toby Churchill Ltd and Brightstar Engineering
298 + * Created by Charles Manning <charles@aleph1.co.uk>
300 + * This program is free software; you can redistribute it and/or modify
301 + * it under the terms of the GNU Lesser General Public License version 2.1 as
302 + * published by the Free Software Foundation.
304 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
308 +#include "yaffs_allocator.h"
309 +#include "yaffs_guts.h"
310 +#include "yaffs_trace.h"
311 +#include "yportenv.h"
313 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
315 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
320 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
325 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
327 + return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
330 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
336 +void yaffs_InitialiseRawObjects(yaffs_Device *dev)
341 +void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
346 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
349 + return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
353 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
362 +struct yaffs_TnodeList_struct {
363 + struct yaffs_TnodeList_struct *next;
364 + yaffs_Tnode *tnodes;
367 +typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
369 +struct yaffs_ObjectList_struct {
370 + yaffs_Object *objects;
371 + struct yaffs_ObjectList_struct *next;
374 +typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
377 +struct yaffs_AllocatorStruct {
378 + int nTnodesCreated;
379 + yaffs_Tnode *freeTnodes;
381 + yaffs_TnodeList *allocatedTnodeList;
383 + int nObjectsCreated;
384 + yaffs_Object *freeObjects;
387 + yaffs_ObjectList *allocatedObjectList;
390 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
393 +static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
396 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
398 + yaffs_TnodeList *tmp;
405 + while (allocator->allocatedTnodeList) {
406 + tmp = allocator->allocatedTnodeList->next;
408 + YFREE(allocator->allocatedTnodeList->tnodes);
409 + YFREE(allocator->allocatedTnodeList);
410 + allocator->allocatedTnodeList = tmp;
414 + allocator->freeTnodes = NULL;
415 + allocator->nFreeTnodes = 0;
416 + allocator->nTnodesCreated = 0;
419 +static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
421 + yaffs_Allocator *allocator = dev->allocator;
424 + allocator->allocatedTnodeList = NULL;
425 + allocator->freeTnodes = NULL;
426 + allocator->nFreeTnodes = 0;
427 + allocator->nTnodesCreated = 0;
432 +static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
434 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
436 + yaffs_Tnode *newTnodes;
440 + yaffs_TnodeList *tnl;
451 + /* make these things */
453 + newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
454 + mem = (__u8 *)newTnodes;
457 + T(YAFFS_TRACE_ERROR,
458 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
462 + /* New hookup for wide tnodes */
463 + for (i = 0; i < nTnodes - 1; i++) {
464 + curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
465 + next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
466 + curr->internal[0] = next;
469 + curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
470 + curr->internal[0] = allocator->freeTnodes;
471 + allocator->freeTnodes = (yaffs_Tnode *)mem;
473 + allocator->nFreeTnodes += nTnodes;
474 + allocator->nTnodesCreated += nTnodes;
476 + /* Now add this bunch of tnodes to a list for freeing up.
477 + * NB If we can't add this to the management list it isn't fatal
478 + * but it just means we can't free this bunch of tnodes later.
481 + tnl = YMALLOC(sizeof(yaffs_TnodeList));
483 + T(YAFFS_TRACE_ERROR,
485 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
488 + tnl->tnodes = newTnodes;
489 + tnl->next = allocator->allocatedTnodeList;
490 + allocator->allocatedTnodeList = tnl;
493 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
499 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
501 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
502 + yaffs_Tnode *tn = NULL;
509 + /* If there are none left make more */
510 + if (!allocator->freeTnodes)
511 + yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
513 + if (allocator->freeTnodes) {
514 + tn = allocator->freeTnodes;
515 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
516 + allocator->nFreeTnodes--;
522 +/* FreeTnode frees up a tnode and puts it back on the free list */
523 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
525 + yaffs_Allocator *allocator = dev->allocator;
533 + tn->internal[0] = allocator->freeTnodes;
534 + allocator->freeTnodes = tn;
535 + allocator->nFreeTnodes++;
537 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
542 +static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
544 + yaffs_Allocator *allocator = dev->allocator;
547 + allocator->allocatedObjectList = NULL;
548 + allocator->freeObjects = NULL;
549 + allocator->nFreeObjects = 0;
554 +static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
556 + yaffs_Allocator *allocator = dev->allocator;
557 + yaffs_ObjectList *tmp;
564 + while (allocator->allocatedObjectList) {
565 + tmp = allocator->allocatedObjectList->next;
566 + YFREE(allocator->allocatedObjectList->objects);
567 + YFREE(allocator->allocatedObjectList);
569 + allocator->allocatedObjectList = tmp;
572 + allocator->freeObjects = NULL;
573 + allocator->nFreeObjects = 0;
574 + allocator->nObjectsCreated = 0;
578 +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
580 + yaffs_Allocator *allocator = dev->allocator;
583 + yaffs_Object *newObjects;
584 + yaffs_ObjectList *list;
594 + /* make these things */
595 + newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
596 + list = YMALLOC(sizeof(yaffs_ObjectList));
598 + if (!newObjects || !list) {
607 + T(YAFFS_TRACE_ALLOCATE,
608 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
612 + /* Hook them into the free list */
613 + for (i = 0; i < nObjects - 1; i++) {
614 + newObjects[i].siblings.next =
615 + (struct ylist_head *)(&newObjects[i + 1]);
618 + newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
619 + allocator->freeObjects = newObjects;
620 + allocator->nFreeObjects += nObjects;
621 + allocator->nObjectsCreated += nObjects;
623 + /* Now add this bunch of Objects to a list for freeing up. */
625 + list->objects = newObjects;
626 + list->next = allocator->allocatedObjectList;
627 + allocator->allocatedObjectList = list;
632 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
634 + yaffs_Object *obj = NULL;
635 + yaffs_Allocator *allocator = dev->allocator;
642 + /* If there are none left make more */
643 + if (!allocator->freeObjects)
644 + yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
646 + if (allocator->freeObjects) {
647 + obj = allocator->freeObjects;
648 + allocator->freeObjects =
649 + (yaffs_Object *) (allocator->freeObjects->siblings.next);
650 + allocator->nFreeObjects--;
657 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
660 + yaffs_Allocator *allocator = dev->allocator;
665 + /* Link into the free list. */
666 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
667 + allocator->freeObjects = obj;
668 + allocator->nFreeObjects++;
672 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
674 + if(dev->allocator){
675 + yaffs_DeinitialiseRawTnodes(dev);
676 + yaffs_DeinitialiseRawObjects(dev);
678 + YFREE(dev->allocator);
679 + dev->allocator=NULL;
684 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
686 + yaffs_Allocator *allocator;
688 + if(!dev->allocator){
689 + allocator = YMALLOC(sizeof(yaffs_Allocator));
691 + dev->allocator = allocator;
692 + yaffs_InitialiseRawTnodes(dev);
693 + yaffs_InitialiseRawObjects(dev);
701 diff -Nrup a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h
702 --- a/fs/yaffs2/yaffs_allocator.h 1970-01-01 02:00:00.000000000 +0200
703 +++ b/fs/yaffs2/yaffs_allocator.h 2010-10-03 18:03:47.538000366 +0300
706 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
708 + * Copyright (C) 2002-2010 Aleph One Ltd.
709 + * for Toby Churchill Ltd and Brightstar Engineering
711 + * Created by Charles Manning <charles@aleph1.co.uk>
713 + * This program is free software; you can redistribute it and/or modify
714 + * it under the terms of the GNU Lesser General Public License version 2.1 as
715 + * published by the Free Software Foundation.
717 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
720 +#ifndef __YAFFS_ALLOCATOR_H__
721 +#define __YAFFS_ALLOCATOR_H__
723 +#include "yaffs_guts.h"
725 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
726 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
728 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
729 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
731 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
732 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
735 diff -Nrup a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c
736 --- a/fs/yaffs2/yaffs_bitmap.c 1970-01-01 02:00:00.000000000 +0200
737 +++ b/fs/yaffs2/yaffs_bitmap.c 2010-10-03 18:03:47.505000364 +0300
740 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
742 + * Copyright (C) 2002-2010 Aleph One Ltd.
743 + * for Toby Churchill Ltd and Brightstar Engineering
745 + * Created by Charles Manning <charles@aleph1.co.uk>
747 + * This program is free software; you can redistribute it and/or modify
748 + * it under the terms of the GNU General Public License version 2 as
749 + * published by the Free Software Foundation.
752 +#include "yaffs_bitmap.h"
753 +#include "yaffs_trace.h"
755 + * Chunk bitmap manipulations
758 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
760 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
761 + T(YAFFS_TRACE_ERROR,
762 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
766 + return dev->chunkBits +
767 + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
770 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
772 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
773 + chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
774 + T(YAFFS_TRACE_ERROR,
775 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
781 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
783 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
785 + memset(blkBits, 0, dev->chunkBitmapStride);
788 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
790 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
792 + yaffs_VerifyChunkBitId(dev, blk, chunk);
794 + blkBits[chunk / 8] &= ~(1 << (chunk & 7));
797 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
799 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
801 + yaffs_VerifyChunkBitId(dev, blk, chunk);
803 + blkBits[chunk / 8] |= (1 << (chunk & 7));
806 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
808 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
809 + yaffs_VerifyChunkBitId(dev, blk, chunk);
811 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
814 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
816 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
818 + for (i = 0; i < dev->chunkBitmapStride; i++) {
826 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
828 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
831 + for (i = 0; i < dev->chunkBitmapStride; i++) {
844 diff -Nrup a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h
845 --- a/fs/yaffs2/yaffs_bitmap.h 1970-01-01 02:00:00.000000000 +0200
846 +++ b/fs/yaffs2/yaffs_bitmap.h 2010-10-03 18:03:47.539000363 +0300
849 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
851 + * Copyright (C) 2002-2010 Aleph One Ltd.
852 + * for Toby Churchill Ltd and Brightstar Engineering
854 + * Created by Charles Manning <charles@aleph1.co.uk>
856 + * This program is free software; you can redistribute it and/or modify
857 + * it under the terms of the GNU General Public License version 2 as
858 + * published by the Free Software Foundation.
862 + * Chunk bitmap manipulations
865 +#ifndef __YAFFS_BITMAP_H__
866 +#define __YAFFS_BITMAP_H__
868 +#include "yaffs_guts.h"
870 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
871 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
872 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
873 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
874 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
875 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
876 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
879 diff -Nrup a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
880 --- a/fs/yaffs2/yaffs_checkptrw.c 2010-10-03 17:48:22.706000363 +0300
881 +++ b/fs/yaffs2/yaffs_checkptrw.c 2010-10-03 18:03:47.505000364 +0300
884 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
886 - * Copyright (C) 2002-2007 Aleph One Ltd.
887 + * Copyright (C) 2002-2010 Aleph One Ltd.
888 * for Toby Churchill Ltd and Brightstar Engineering
890 * Created by Charles Manning <charles@aleph1.co.uk>
892 * published by the Free Software Foundation.
895 -const char *yaffs_checkptrw_c_version =
896 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
899 #include "yaffs_checkptrw.h"
900 #include "yaffs_getblockinfo.h"
902 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
903 +static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev)
905 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
906 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
908 T(YAFFS_TRACE_CHECKPOINT,
909 (TSTR("checkpt blocks available = %d" TENDSTR),
910 @@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs
914 -static int yaffs_CheckpointErase(yaffs_Device *dev)
915 +static int yaffs2_CheckpointErase(yaffs_Device *dev)
919 - if (!dev->eraseBlockInNAND)
920 + if (!dev->param.eraseBlockInNAND)
922 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
923 dev->internalStartBlock, dev->internalEndBlock));
924 @@ -43,12 +39,15 @@ static int yaffs_CheckpointErase(yaffs_D
925 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
926 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
927 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
928 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
930 + dev->nBlockErasures++;
932 + if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
933 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
934 dev->nErasedBlocks++;
935 - dev->nFreeChunks += dev->nChunksPerBlock;
936 + dev->nFreeChunks += dev->param.nChunksPerBlock;
938 - dev->markNANDBlockBad(dev, i);
939 + dev->param.markNANDBlockBad(dev, i);
940 bi->blockState = YAFFS_BLOCK_STATE_DEAD;
943 @@ -60,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_D
947 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
948 +static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev)
951 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
952 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
953 T(YAFFS_TRACE_CHECKPOINT,
954 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
955 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
956 + dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
958 if (dev->checkpointNextBlock >= 0 &&
959 dev->checkpointNextBlock <= dev->internalEndBlock &&
960 @@ -88,7 +87,7 @@ static void yaffs_CheckpointFindNextEras
961 dev->checkpointCurrentBlock = -1;
964 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
965 +static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
968 yaffs_ExtendedTags tags;
969 @@ -98,10 +97,10 @@ static void yaffs_CheckpointFindNextChec
971 if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
972 for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
973 - int chunk = i * dev->nChunksPerBlock;
974 + int chunk = i * dev->param.nChunksPerBlock;
975 int realignedChunk = chunk - dev->chunkOffset;
977 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
978 + dev->param.readChunkWithTagsFromNAND(dev, realignedChunk,
980 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
981 i, tags.objectId, tags.sequenceNumber, tags.eccResult));
982 @@ -124,29 +123,29 @@ static void yaffs_CheckpointFindNextChec
986 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
987 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting)
991 + dev->checkpointOpenForWrite = forWriting;
993 /* Got the functions we need? */
994 - if (!dev->writeChunkWithTagsToNAND ||
995 - !dev->readChunkWithTagsFromNAND ||
996 - !dev->eraseBlockInNAND ||
997 - !dev->markNANDBlockBad)
998 + if (!dev->param.writeChunkWithTagsToNAND ||
999 + !dev->param.readChunkWithTagsFromNAND ||
1000 + !dev->param.eraseBlockInNAND ||
1001 + !dev->param.markNANDBlockBad)
1004 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
1005 + if (forWriting && !yaffs2_CheckpointSpaceOk(dev))
1008 if (!dev->checkpointBuffer)
1009 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1010 + dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk);
1011 if (!dev->checkpointBuffer)
1015 dev->checkpointPageSequence = 0;
1017 - dev->checkpointOpenForWrite = forWriting;
1019 dev->checkpointByteCount = 0;
1020 dev->checkpointSum = 0;
1021 dev->checkpointXor = 0;
1022 @@ -158,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1024 memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1025 dev->checkpointByteOffset = 0;
1026 - return yaffs_CheckpointErase(dev);
1027 + return yaffs2_CheckpointErase(dev);
1030 /* Set to a value that will kick off a read */
1031 @@ -168,6 +167,9 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1032 dev->blocksInCheckpoint = 0;
1033 dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1034 dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1035 + if(!dev->checkpointBlockList)
1038 for (i = 0; i < dev->checkpointMaxBlocks; i++)
1039 dev->checkpointBlockList[i] = -1;
1041 @@ -175,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1045 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1046 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1049 compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1050 @@ -183,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device
1054 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1055 +static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev)
1059 @@ -191,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(y
1060 yaffs_ExtendedTags tags;
1062 if (dev->checkpointCurrentBlock < 0) {
1063 - yaffs_CheckpointFindNextErasedBlock(dev);
1064 + yaffs2_CheckpointFindNextErasedBlock(dev);
1065 dev->checkpointCurrentChunk = 0;
1068 @@ -211,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(y
1069 dev->blocksInCheckpoint++;
1072 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1073 + chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk;
1076 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1077 @@ -219,12 +221,14 @@ static int yaffs_CheckpointFlushBuffer(y
1079 realignedChunk = chunk - dev->chunkOffset;
1081 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1082 + dev->nPageWrites++;
1084 + dev->param.writeChunkWithTagsToNAND(dev, realignedChunk,
1085 dev->checkpointBuffer, &tags);
1086 dev->checkpointByteOffset = 0;
1087 dev->checkpointPageSequence++;
1088 dev->checkpointCurrentChunk++;
1089 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1090 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) {
1091 dev->checkpointCurrentChunk = 0;
1092 dev->checkpointCurrentBlock = -1;
1094 @@ -234,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(y
1098 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1099 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1103 @@ -263,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *
1105 if (dev->checkpointByteOffset < 0 ||
1106 dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1107 - ok = yaffs_CheckpointFlushBuffer(dev);
1108 + ok = yaffs2_CheckpointFlushBuffer(dev);
1114 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1115 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1119 @@ -294,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1120 dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1122 if (dev->checkpointCurrentBlock < 0) {
1123 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1124 + yaffs2_CheckpointFindNextCheckpointBlock(dev);
1125 dev->checkpointCurrentChunk = 0;
1128 @@ -302,14 +306,16 @@ int yaffs_CheckpointRead(yaffs_Device *d
1131 chunk = dev->checkpointCurrentBlock *
1132 - dev->nChunksPerBlock +
1133 + dev->param.nChunksPerBlock +
1134 dev->checkpointCurrentChunk;
1136 realignedChunk = chunk - dev->chunkOffset;
1138 + dev->nPageReads++;
1140 /* read in the next chunk */
1141 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1142 - dev->readChunkWithTagsFromNAND(dev,
1143 + dev->param.readChunkWithTagsFromNAND(dev,
1145 dev->checkpointBuffer,
1147 @@ -323,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1148 dev->checkpointPageSequence++;
1149 dev->checkpointCurrentChunk++;
1151 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1152 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock)
1153 dev->checkpointCurrentBlock = -1;
1156 @@ -342,17 +348,20 @@ int yaffs_CheckpointRead(yaffs_Device *d
1160 -int yaffs_CheckpointClose(yaffs_Device *dev)
1161 +int yaffs2_CheckpointClose(yaffs_Device *dev)
1164 if (dev->checkpointOpenForWrite) {
1165 if (dev->checkpointByteOffset != 0)
1166 - yaffs_CheckpointFlushBuffer(dev);
1168 + yaffs2_CheckpointFlushBuffer(dev);
1169 + } else if(dev->checkpointBlockList){
1171 for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1172 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1173 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1174 + int blk = dev->checkpointBlockList[i];
1175 + yaffs_BlockInfo *bi = NULL;
1176 + if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
1177 + bi = yaffs_GetBlockInfo(dev, blk);
1178 + if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1179 bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1181 /* Todo this looks odd... */
1182 @@ -362,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *
1183 dev->checkpointBlockList = NULL;
1186 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1187 + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock;
1188 dev->nErasedBlocks -= dev->blocksInCheckpoint;
1191 @@ -378,16 +387,14 @@ int yaffs_CheckpointClose(yaffs_Device *
1195 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1196 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev)
1198 - /* Erase the first checksum block */
1200 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1201 + /* Erase the checkpoint data */
1203 - if (!yaffs_CheckpointSpaceOk(dev))
1205 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1206 + dev->blocksInCheckpoint));
1208 - return yaffs_CheckpointErase(dev);
1209 + return yaffs2_CheckpointErase(dev);
1213 diff -Nrup a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h
1214 --- a/fs/yaffs2/yaffs_checkptrw.h 2010-10-03 17:48:22.706000363 +0300
1215 +++ b/fs/yaffs2/yaffs_checkptrw.h 2010-10-03 18:03:47.540000359 +0300
1218 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1220 - * Copyright (C) 2002-2007 Aleph One Ltd.
1221 + * Copyright (C) 2002-2010 Aleph One Ltd.
1222 * for Toby Churchill Ltd and Brightstar Engineering
1224 * Created by Charles Manning <charles@aleph1.co.uk>
1227 #include "yaffs_guts.h"
1229 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1230 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting);
1232 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1233 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1235 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1236 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1238 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1239 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1241 -int yaffs_CheckpointClose(yaffs_Device *dev);
1242 +int yaffs2_CheckpointClose(yaffs_Device *dev);
1244 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1245 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev);
1250 diff -Nrup a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c
1251 --- a/fs/yaffs2/yaffs_ecc.c 2010-10-03 17:48:22.706000363 +0300
1252 +++ b/fs/yaffs2/yaffs_ecc.c 2010-10-03 18:03:47.509000373 +0300
1255 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1257 - * Copyright (C) 2002-2007 Aleph One Ltd.
1258 + * Copyright (C) 2002-2010 Aleph One Ltd.
1259 * for Toby Churchill Ltd and Brightstar Engineering
1261 * Created by Charles Manning <charles@aleph1.co.uk>
1263 * this bytes influence on the line parity.
1266 -const char *yaffs_ecc_c_version =
1267 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1269 #include "yportenv.h"
1271 #include "yaffs_ecc.h"
1272 diff -Nrup a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h
1273 --- a/fs/yaffs2/yaffs_ecc.h 2010-10-03 17:48:22.707000363 +0300
1274 +++ b/fs/yaffs2/yaffs_ecc.h 2010-10-03 18:03:47.541000359 +0300
1277 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1279 - * Copyright (C) 2002-2007 Aleph One Ltd.
1280 + * Copyright (C) 2002-2010 Aleph One Ltd.
1281 * for Toby Churchill Ltd and Brightstar Engineering
1283 * Created by Charles Manning <charles@aleph1.co.uk>
1284 diff -Nrup a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
1285 --- a/fs/yaffs2/yaffs_fs.c 2010-10-03 17:48:22.708000363 +0300
1286 +++ b/fs/yaffs2/yaffs_fs.c 1970-01-01 02:00:00.000000000 +0200
1289 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1291 - * Copyright (C) 2002-2009 Aleph One Ltd.
1292 - * for Toby Churchill Ltd and Brightstar Engineering
1294 - * Created by Charles Manning <charles@aleph1.co.uk>
1295 - * Acknowledgements:
1296 - * Luc van OostenRyck for numerous patches.
1297 - * Nick Bane for numerous patches.
1298 - * Nick Bane for 2.5/2.6 integration.
1299 - * Andras Toth for mknod rdev issue.
1300 - * Michael Fischer for finding the problem with inode inconsistency.
1301 - * Some code bodily lifted from JFFS
1303 - * This program is free software; you can redistribute it and/or modify
1304 - * it under the terms of the GNU General Public License version 2 as
1305 - * published by the Free Software Foundation.
1310 - * This is the file system front-end to YAFFS that hooks it up to
1314 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1316 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1318 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1321 -const char *yaffs_fs_c_version =
1322 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1323 -extern const char *yaffs_guts_c_version;
1325 -#include <linux/version.h>
1326 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1327 -#include <linux/config.h>
1329 -#include <linux/kernel.h>
1330 -#include <linux/module.h>
1331 -#include <linux/slab.h>
1332 -#include <linux/init.h>
1333 -#include <linux/fs.h>
1334 -#include <linux/proc_fs.h>
1335 -#include <linux/smp_lock.h>
1336 -#include <linux/pagemap.h>
1337 -#include <linux/mtd/mtd.h>
1338 -#include <linux/interrupt.h>
1339 -#include <linux/string.h>
1340 -#include <linux/ctype.h>
1342 -#include "asm/div64.h"
1344 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1346 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1347 -#include <linux/statfs.h>
1348 -#define UnlockPage(p) unlock_page(p)
1349 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1351 -/* FIXME: use sb->s_id instead ? */
1352 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1356 -#include <linux/locks.h>
1357 -#define BDEVNAME_SIZE 0
1358 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1360 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1361 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1367 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1368 -#define YPROC_ROOT (&proc_root)
1370 -#define YPROC_ROOT NULL
1373 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1374 -#define WRITE_SIZE_STR "writesize"
1375 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1377 -#define WRITE_SIZE_STR "oobblock"
1378 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1381 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1382 -#define YAFFS_USE_WRITE_BEGIN_END 1
1384 -#define YAFFS_USE_WRITE_BEGIN_END 0
1387 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1388 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1390 - uint64_t result = partition_size;
1391 - do_div(result, block_size);
1392 - return (uint32_t)result;
1395 -#define YCALCBLOCKS(s, b) ((s)/(b))
1398 -#include <linux/uaccess.h>
1400 -#include "yportenv.h"
1401 -#include "yaffs_guts.h"
1403 -#include <linux/mtd/mtd.h>
1404 -#include "yaffs_mtdif.h"
1405 -#include "yaffs_mtdif1.h"
1406 -#include "yaffs_mtdif2.h"
1408 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1409 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1410 -unsigned int yaffs_auto_checkpoint = 1;
1412 -/* Module Parameters */
1413 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1414 -module_param(yaffs_traceMask, uint, 0644);
1415 -module_param(yaffs_wr_attempts, uint, 0644);
1416 -module_param(yaffs_auto_checkpoint, uint, 0644);
1418 -MODULE_PARM(yaffs_traceMask, "i");
1419 -MODULE_PARM(yaffs_wr_attempts, "i");
1420 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1423 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1424 -/* use iget and read_inode */
1425 -#define Y_IGET(sb, inum) iget((sb), (inum))
1426 -static void yaffs_read_inode(struct inode *inode);
1429 -/* Call local equivalent */
1430 -#define YAFFS_USE_OWN_IGET
1431 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1433 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1436 -/*#define T(x) printk x */
1438 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1439 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1441 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1444 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1445 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1447 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1448 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1450 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1453 -static void yaffs_put_super(struct super_block *sb);
1455 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1457 -static ssize_t yaffs_hold_space(struct file *f);
1458 -static void yaffs_release_space(struct file *f);
1460 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1461 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1463 -static int yaffs_file_flush(struct file *file);
1466 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1469 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1471 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1472 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1473 - struct nameidata *n);
1474 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1475 - struct nameidata *n);
1477 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1478 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1480 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1481 - struct dentry *dentry);
1482 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1483 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1484 - const char *symname);
1485 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1487 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1488 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1491 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1494 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1495 - struct inode *new_dir, struct dentry *new_dentry);
1496 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1498 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1499 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1500 -static void yaffs_write_super(struct super_block *sb);
1502 -static int yaffs_sync_fs(struct super_block *sb);
1503 -static int yaffs_write_super(struct super_block *sb);
1506 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1507 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1508 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1509 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1511 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1514 -#ifdef YAFFS_HAS_PUT_INODE
1515 -static void yaffs_put_inode(struct inode *inode);
1518 -static void yaffs_delete_inode(struct inode *);
1519 -static void yaffs_clear_inode(struct inode *);
1521 -static int yaffs_readpage(struct file *file, struct page *page);
1522 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1523 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1525 -static int yaffs_writepage(struct page *page);
1529 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1530 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1531 - loff_t pos, unsigned len, unsigned flags,
1532 - struct page **pagep, void **fsdata);
1533 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1534 - loff_t pos, unsigned len, unsigned copied,
1535 - struct page *pg, void *fsdadata);
1537 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1538 - unsigned offset, unsigned to);
1539 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1544 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1546 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1547 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1549 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1552 -static struct address_space_operations yaffs_file_address_operations = {
1553 - .readpage = yaffs_readpage,
1554 - .writepage = yaffs_writepage,
1555 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1556 - .write_begin = yaffs_write_begin,
1557 - .write_end = yaffs_write_end,
1559 - .prepare_write = yaffs_prepare_write,
1560 - .commit_write = yaffs_commit_write,
1564 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1565 -static const struct file_operations yaffs_file_operations = {
1566 - .read = do_sync_read,
1567 - .write = do_sync_write,
1568 - .aio_read = generic_file_aio_read,
1569 - .aio_write = generic_file_aio_write,
1570 - .mmap = generic_file_mmap,
1571 - .flush = yaffs_file_flush,
1572 - .fsync = yaffs_sync_object,
1573 - .splice_read = generic_file_splice_read,
1574 - .splice_write = generic_file_splice_write,
1575 - .llseek = generic_file_llseek,
1578 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1580 -static const struct file_operations yaffs_file_operations = {
1581 - .read = do_sync_read,
1582 - .write = do_sync_write,
1583 - .aio_read = generic_file_aio_read,
1584 - .aio_write = generic_file_aio_write,
1585 - .mmap = generic_file_mmap,
1586 - .flush = yaffs_file_flush,
1587 - .fsync = yaffs_sync_object,
1588 - .sendfile = generic_file_sendfile,
1593 -static const struct file_operations yaffs_file_operations = {
1594 - .read = generic_file_read,
1595 - .write = generic_file_write,
1596 - .mmap = generic_file_mmap,
1597 - .flush = yaffs_file_flush,
1598 - .fsync = yaffs_sync_object,
1599 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1600 - .sendfile = generic_file_sendfile,
1605 -static const struct inode_operations yaffs_file_inode_operations = {
1606 - .setattr = yaffs_setattr,
1609 -static const struct inode_operations yaffs_symlink_inode_operations = {
1610 - .readlink = yaffs_readlink,
1611 - .follow_link = yaffs_follow_link,
1612 - .setattr = yaffs_setattr,
1615 -static const struct inode_operations yaffs_dir_inode_operations = {
1616 - .create = yaffs_create,
1617 - .lookup = yaffs_lookup,
1618 - .link = yaffs_link,
1619 - .unlink = yaffs_unlink,
1620 - .symlink = yaffs_symlink,
1621 - .mkdir = yaffs_mkdir,
1622 - .rmdir = yaffs_unlink,
1623 - .mknod = yaffs_mknod,
1624 - .rename = yaffs_rename,
1625 - .setattr = yaffs_setattr,
1628 -static const struct file_operations yaffs_dir_operations = {
1629 - .read = generic_read_dir,
1630 - .readdir = yaffs_readdir,
1631 - .fsync = yaffs_sync_object,
1634 -static const struct super_operations yaffs_super_ops = {
1635 - .statfs = yaffs_statfs,
1637 -#ifndef YAFFS_USE_OWN_IGET
1638 - .read_inode = yaffs_read_inode,
1640 -#ifdef YAFFS_HAS_PUT_INODE
1641 - .put_inode = yaffs_put_inode,
1643 - .put_super = yaffs_put_super,
1644 - .delete_inode = yaffs_delete_inode,
1645 - .clear_inode = yaffs_clear_inode,
1646 - .sync_fs = yaffs_sync_fs,
1647 - .write_super = yaffs_write_super,
1650 -static void yaffs_GrossLock(yaffs_Device *dev)
1652 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
1653 - down(&dev->grossLock);
1654 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
1657 -static void yaffs_GrossUnlock(yaffs_Device *dev)
1659 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
1660 - up(&dev->grossLock);
1663 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1666 - unsigned char *alias;
1669 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1671 - yaffs_GrossLock(dev);
1673 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1675 - yaffs_GrossUnlock(dev);
1680 - ret = vfs_readlink(dentry, buffer, buflen, alias);
1685 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1686 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1688 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1691 - unsigned char *alias;
1693 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1695 - yaffs_GrossLock(dev);
1697 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1699 - yaffs_GrossUnlock(dev);
1706 - ret = vfs_follow_link(nd, alias);
1709 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1710 - return ERR_PTR(ret);
1716 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1717 - yaffs_Object *obj);
1720 - * Lookup is used to find objects in the fs
1722 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1724 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1725 - struct nameidata *n)
1727 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
1730 - yaffs_Object *obj;
1731 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
1733 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
1735 - yaffs_GrossLock(dev);
1738 - ("yaffs_lookup for %d:%s\n",
1739 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
1741 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
1742 - dentry->d_name.name);
1744 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
1746 - /* Can't hold gross lock when calling yaffs_get_inode() */
1747 - yaffs_GrossUnlock(dev);
1751 - ("yaffs_lookup found %d\n", obj->objectId));
1753 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1757 - ("yaffs_loookup dentry \n"));
1758 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
1759 - * d_add even if NULL inode */
1761 - /*dget(dentry); // try to solve directory bug */
1762 - d_add(dentry, inode);
1764 - /* return dentry; */
1770 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
1774 -/* added NCB for 2.5/6 compatability - forces add even if inode is
1775 - * NULL which creates dentry hash */
1776 - d_add(dentry, inode);
1782 -#ifdef YAFFS_HAS_PUT_INODE
1784 -/* For now put inode is just for debugging
1785 - * Put inode is called when the inode **structure** is put.
1787 -static void yaffs_put_inode(struct inode *inode)
1790 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
1791 - atomic_read(&inode->i_count)));
1796 -/* clear is called to tell the fs to release any per-inode data it holds */
1797 -static void yaffs_clear_inode(struct inode *inode)
1799 - yaffs_Object *obj;
1800 - yaffs_Device *dev;
1802 - obj = yaffs_InodeToObject(inode);
1805 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1806 - atomic_read(&inode->i_count),
1807 - obj ? "object exists" : "null object"));
1811 - yaffs_GrossLock(dev);
1813 - /* Clear the association between the inode and
1814 - * the yaffs_Object.
1816 - obj->myInode = NULL;
1817 - yaffs_InodeToObjectLV(inode) = NULL;
1819 - /* If the object freeing was deferred, then the real
1820 - * free happens now.
1821 - * This should fix the inode inconsistency problem.
1824 - yaffs_HandleDeferedFree(obj);
1826 - yaffs_GrossUnlock(dev);
1831 -/* delete is called when the link count is zero and the inode
1832 - * is put (ie. nobody wants to know about it anymore, time to
1833 - * delete the file).
1834 - * NB Must call clear_inode()
1836 -static void yaffs_delete_inode(struct inode *inode)
1838 - yaffs_Object *obj = yaffs_InodeToObject(inode);
1839 - yaffs_Device *dev;
1842 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1843 - atomic_read(&inode->i_count),
1844 - obj ? "object exists" : "null object"));
1848 - yaffs_GrossLock(dev);
1849 - yaffs_DeleteObject(obj);
1850 - yaffs_GrossUnlock(dev);
1852 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1853 - truncate_inode_pages(&inode->i_data, 0);
1855 - clear_inode(inode);
1858 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1859 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
1861 -static int yaffs_file_flush(struct file *file)
1864 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1866 - yaffs_Device *dev = obj->myDev;
1869 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
1870 - obj->dirty ? "dirty" : "clean"));
1872 - yaffs_GrossLock(dev);
1874 - yaffs_FlushFile(obj, 1);
1876 - yaffs_GrossUnlock(dev);
1881 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
1883 - /* Lifted from jffs2 */
1885 - yaffs_Object *obj;
1886 - unsigned char *pg_buf;
1889 - yaffs_Device *dev;
1891 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
1892 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
1893 - (unsigned)PAGE_CACHE_SIZE));
1895 - obj = yaffs_DentryToObject(f->f_dentry);
1899 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1900 - BUG_ON(!PageLocked(pg));
1902 - if (!PageLocked(pg))
1906 - pg_buf = kmap(pg);
1907 - /* FIXME: Can kmap fail? */
1909 - yaffs_GrossLock(dev);
1911 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
1912 - pg->index << PAGE_CACHE_SHIFT,
1915 - yaffs_GrossUnlock(dev);
1921 - ClearPageUptodate(pg);
1924 - SetPageUptodate(pg);
1925 - ClearPageError(pg);
1928 - flush_dcache_page(pg);
1931 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
1935 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1937 - int ret = yaffs_readpage_nolock(f, pg);
1942 -static int yaffs_readpage(struct file *f, struct page *pg)
1944 - return yaffs_readpage_unlock(f, pg);
1947 -/* writepage inspired by/stolen from smbfs */
1949 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1950 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1952 -static int yaffs_writepage(struct page *page)
1955 - struct address_space *mapping = page->mapping;
1956 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
1957 - struct inode *inode;
1958 - unsigned long end_index;
1960 - yaffs_Object *obj;
1966 - inode = mapping->host;
1970 - if (offset > inode->i_size) {
1972 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
1973 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
1974 - (unsigned)inode->i_size));
1976 - (" -> don't care!!\n"));
1977 - unlock_page(page);
1981 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1984 - if (page->index < end_index)
1985 - nBytes = PAGE_CACHE_SIZE;
1987 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
1991 - buffer = kmap(page);
1993 - obj = yaffs_InodeToObject(inode);
1994 - yaffs_GrossLock(obj->myDev);
1997 - ("yaffs_writepage at %08x, size %08x\n",
1998 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
2000 - ("writepag0: obj = %05x, ino = %05x\n",
2001 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2003 - nWritten = yaffs_WriteDataToFile(obj, buffer,
2004 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
2007 - ("writepag1: obj = %05x, ino = %05x\n",
2008 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2010 - yaffs_GrossUnlock(obj->myDev);
2013 - SetPageUptodate(page);
2017 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2021 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2022 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2023 - loff_t pos, unsigned len, unsigned flags,
2024 - struct page **pagep, void **fsdata)
2026 - struct page *pg = NULL;
2027 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2028 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2029 - uint32_t to = offset + len;
2032 - int space_held = 0;
2034 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2036 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2037 - pg = grab_cache_page_write_begin(mapping, index, flags);
2039 - pg = __grab_cache_page(mapping, index);
2047 - /* Get fs space */
2048 - space_held = yaffs_hold_space(filp);
2050 - if (!space_held) {
2055 - /* Update page if required */
2057 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2058 - ret = yaffs_readpage_nolock(filp, pg);
2063 - /* Happy path return */
2064 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2069 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2071 - yaffs_release_space(filp);
2074 - page_cache_release(pg);
2081 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2082 - unsigned offset, unsigned to)
2084 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2086 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2087 - return yaffs_readpage_nolock(f, pg);
2092 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2093 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2094 - loff_t pos, unsigned len, unsigned copied,
2095 - struct page *pg, void *fsdadata)
2099 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2102 - addr = kva + offset_into_page;
2105 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2107 - (int)pos, copied));
2109 - ret = yaffs_file_write(filp, addr, copied, &pos);
2111 - if (ret != copied) {
2113 - ("yaffs_write_end not same size ret %d copied %d\n",
2116 - ClearPageUptodate(pg);
2118 - SetPageUptodate(pg);
2123 - yaffs_release_space(filp);
2125 - page_cache_release(pg);
2130 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2135 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2136 - int nBytes = to - offset;
2139 - unsigned spos = pos;
2143 - addr = kva + offset;
2145 - saddr = (unsigned) addr;
2148 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2149 - saddr, spos, nBytes));
2151 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2153 - if (nWritten != nBytes) {
2155 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2156 - nWritten, nBytes));
2158 - ClearPageUptodate(pg);
2160 - SetPageUptodate(pg);
2166 - ("yaffs_commit_write returning %d\n",
2167 - nWritten == nBytes ? 0 : nWritten));
2169 - return nWritten == nBytes ? 0 : nWritten;
2174 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2176 - if (inode && obj) {
2179 - /* Check mode against the variant type and attempt to repair if broken. */
2180 - __u32 mode = obj->yst_mode;
2181 - switch (obj->variantType) {
2182 - case YAFFS_OBJECT_TYPE_FILE:
2183 - if (!S_ISREG(mode)) {
2184 - obj->yst_mode &= ~S_IFMT;
2185 - obj->yst_mode |= S_IFREG;
2189 - case YAFFS_OBJECT_TYPE_SYMLINK:
2190 - if (!S_ISLNK(mode)) {
2191 - obj->yst_mode &= ~S_IFMT;
2192 - obj->yst_mode |= S_IFLNK;
2196 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2197 - if (!S_ISDIR(mode)) {
2198 - obj->yst_mode &= ~S_IFMT;
2199 - obj->yst_mode |= S_IFDIR;
2203 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2204 - case YAFFS_OBJECT_TYPE_HARDLINK:
2205 - case YAFFS_OBJECT_TYPE_SPECIAL:
2211 - inode->i_flags |= S_NOATIME;
2213 - inode->i_ino = obj->objectId;
2214 - inode->i_mode = obj->yst_mode;
2215 - inode->i_uid = obj->yst_uid;
2216 - inode->i_gid = obj->yst_gid;
2217 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2218 - inode->i_blksize = inode->i_sb->s_blocksize;
2220 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2222 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2223 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2224 - inode->i_atime.tv_nsec = 0;
2225 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2226 - inode->i_mtime.tv_nsec = 0;
2227 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2228 - inode->i_ctime.tv_nsec = 0;
2230 - inode->i_rdev = obj->yst_rdev;
2231 - inode->i_atime = obj->yst_atime;
2232 - inode->i_mtime = obj->yst_mtime;
2233 - inode->i_ctime = obj->yst_ctime;
2235 - inode->i_size = yaffs_GetObjectFileLength(obj);
2236 - inode->i_blocks = (inode->i_size + 511) >> 9;
2238 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2241 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2242 - inode->i_mode, inode->i_uid, inode->i_gid,
2243 - (int)inode->i_size, atomic_read(&inode->i_count)));
2245 - switch (obj->yst_mode & S_IFMT) {
2246 - default: /* fifo, device or socket */
2247 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2248 - init_special_inode(inode, obj->yst_mode,
2249 - old_decode_dev(obj->yst_rdev));
2251 - init_special_inode(inode, obj->yst_mode,
2252 - (dev_t) (obj->yst_rdev));
2255 - case S_IFREG: /* file */
2256 - inode->i_op = &yaffs_file_inode_operations;
2257 - inode->i_fop = &yaffs_file_operations;
2258 - inode->i_mapping->a_ops =
2259 - &yaffs_file_address_operations;
2261 - case S_IFDIR: /* directory */
2262 - inode->i_op = &yaffs_dir_inode_operations;
2263 - inode->i_fop = &yaffs_dir_operations;
2265 - case S_IFLNK: /* symlink */
2266 - inode->i_op = &yaffs_symlink_inode_operations;
2270 - yaffs_InodeToObjectLV(inode) = obj;
2272 - obj->myInode = inode;
2276 - ("yaffs_FileInode invalid parameters\n"));
2281 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2282 - yaffs_Object *obj)
2284 - struct inode *inode;
2288 - ("yaffs_get_inode for NULL super_block!!\n"));
2295 - ("yaffs_get_inode for NULL object!!\n"));
2301 - ("yaffs_get_inode for object %d\n", obj->objectId));
2303 - inode = Y_IGET(sb, obj->objectId);
2304 - if (IS_ERR(inode))
2307 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2308 - /* iget also increments the inode's i_count */
2309 - /* NB You can't be holding grossLock or deadlock will happen! */
2314 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2317 - yaffs_Object *obj;
2318 - int nWritten, ipos;
2319 - struct inode *inode;
2320 - yaffs_Device *dev;
2322 - obj = yaffs_DentryToObject(f->f_dentry);
2326 - yaffs_GrossLock(dev);
2328 - inode = f->f_dentry->d_inode;
2330 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2331 - ipos = inode->i_size;
2337 - ("yaffs_file_write: hey obj is null!\n"));
2340 - ("yaffs_file_write about to write writing %zu bytes"
2341 - "to object %d at %d\n",
2342 - n, obj->objectId, ipos));
2344 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2347 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2348 - n, nWritten, ipos));
2350 - if (nWritten > 0) {
2353 - if (ipos > inode->i_size) {
2354 - inode->i_size = ipos;
2355 - inode->i_blocks = (ipos + 511) >> 9;
2358 - ("yaffs_file_write size updated to %d bytes, "
2360 - ipos, (int)(inode->i_blocks)));
2364 - yaffs_GrossUnlock(dev);
2365 - return nWritten == 0 ? -ENOSPC : nWritten;
2368 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2369 -/* For now we just assume few parallel writes and check against a small number. */
2370 -/* Todo: need to do this with a counter to handle parallel reads better */
2372 -static ssize_t yaffs_hold_space(struct file *f)
2374 - yaffs_Object *obj;
2375 - yaffs_Device *dev;
2380 - obj = yaffs_DentryToObject(f->f_dentry);
2384 - yaffs_GrossLock(dev);
2386 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2388 - yaffs_GrossUnlock(dev);
2390 - return (nFreeChunks > 20) ? 1 : 0;
2393 -static void yaffs_release_space(struct file *f)
2395 - yaffs_Object *obj;
2396 - yaffs_Device *dev;
2399 - obj = yaffs_DentryToObject(f->f_dentry);
2403 - yaffs_GrossLock(dev);
2406 - yaffs_GrossUnlock(dev);
2409 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2411 - yaffs_Object *obj;
2412 - yaffs_Device *dev;
2413 - struct inode *inode = f->f_dentry->d_inode;
2414 - unsigned long offset, curoffs;
2415 - struct ylist_head *i;
2418 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2420 - obj = yaffs_DentryToObject(f->f_dentry);
2423 - yaffs_GrossLock(dev);
2425 - offset = f->f_pos;
2427 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2429 - if (offset == 0) {
2431 - ("yaffs_readdir: entry . ino %d \n",
2432 - (int)inode->i_ino));
2433 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2438 - if (offset == 1) {
2440 - ("yaffs_readdir: entry .. ino %d \n",
2441 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2442 - if (filldir(dirent, "..", 2, offset,
2443 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2451 - /* If the directory has changed since the open or last call to
2452 - readdir, rewind to after the 2 canned entries. */
2454 - if (f->f_version != inode->i_version) {
2456 - f->f_pos = offset;
2457 - f->f_version = inode->i_version;
2460 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2462 - if (curoffs >= offset) {
2463 - l = ylist_entry(i, yaffs_Object, siblings);
2465 - yaffs_GetObjectName(l, name,
2466 - YAFFS_MAX_NAME_LENGTH + 1);
2468 - ("yaffs_readdir: %s inode %d\n", name,
2469 - yaffs_GetObjectInode(l)));
2471 - if (filldir(dirent,
2475 - yaffs_GetObjectInode(l),
2476 - yaffs_GetObjectType(l)) < 0)
2486 - yaffs_GrossUnlock(dev);
2492 - * File creation. Allocate an inode, and we're done..
2495 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2498 -#define YCRED(x) (x->cred)
2501 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2502 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2505 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2509 - struct inode *inode;
2511 - yaffs_Object *obj = NULL;
2512 - yaffs_Device *dev;
2514 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2516 - int error = -ENOSPC;
2517 - uid_t uid = YCRED(current)->fsuid;
2518 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2520 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2525 - ("yaffs_mknod: parent object %d type %d\n",
2526 - parent->objectId, parent->variantType));
2529 - ("yaffs_mknod: could not get parent object\n"));
2533 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2534 - "mode %x dev %x\n",
2535 - dentry->d_name.name, mode, rdev));
2537 - dev = parent->myDev;
2539 - yaffs_GrossLock(dev);
2541 - switch (mode & S_IFMT) {
2543 - /* Special (socket, fifo, device...) */
2544 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2545 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2546 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2547 - gid, old_encode_dev(rdev));
2549 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2553 - case S_IFREG: /* file */
2554 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2555 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2558 - case S_IFDIR: /* directory */
2560 - ("yaffs_mknod: making directory\n"));
2561 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2564 - case S_IFLNK: /* symlink */
2565 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2566 - obj = NULL; /* Do we ever get here? */
2570 - /* Can not call yaffs_get_inode() with gross lock held */
2571 - yaffs_GrossUnlock(dev);
2574 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2575 - d_instantiate(dentry, inode);
2577 - ("yaffs_mknod created object %d count = %d\n",
2578 - obj->objectId, atomic_read(&inode->i_count)));
2582 - ("yaffs_mknod failed making object\n"));
2589 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2592 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2593 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2597 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2598 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2599 - struct nameidata *n)
2601 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2604 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
2605 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
2608 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
2612 - yaffs_Device *dev;
2615 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
2616 - dentry->d_name.name));
2618 - dev = yaffs_InodeToObject(dir)->myDev;
2620 - yaffs_GrossLock(dev);
2622 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
2624 - if (retVal == YAFFS_OK) {
2625 - dentry->d_inode->i_nlink--;
2627 - yaffs_GrossUnlock(dev);
2628 - mark_inode_dirty(dentry->d_inode);
2631 - yaffs_GrossUnlock(dev);
2632 - return -ENOTEMPTY;
2636 - * Create a link...
2638 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
2639 - struct dentry *dentry)
2641 - struct inode *inode = old_dentry->d_inode;
2642 - yaffs_Object *obj = NULL;
2643 - yaffs_Object *link = NULL;
2644 - yaffs_Device *dev;
2646 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
2648 - obj = yaffs_InodeToObject(inode);
2651 - yaffs_GrossLock(dev);
2653 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
2654 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
2658 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2659 - d_instantiate(dentry, old_dentry->d_inode);
2660 - atomic_inc(&old_dentry->d_inode->i_count);
2662 - ("yaffs_link link count %d i_count %d\n",
2663 - old_dentry->d_inode->i_nlink,
2664 - atomic_read(&old_dentry->d_inode->i_count)));
2667 - yaffs_GrossUnlock(dev);
2675 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
2676 - const char *symname)
2678 - yaffs_Object *obj;
2679 - yaffs_Device *dev;
2680 - uid_t uid = YCRED(current)->fsuid;
2681 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2683 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
2685 - dev = yaffs_InodeToObject(dir)->myDev;
2686 - yaffs_GrossLock(dev);
2687 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
2688 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
2689 - yaffs_GrossUnlock(dev);
2692 - struct inode *inode;
2694 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2695 - d_instantiate(dentry, inode);
2696 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
2699 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
2705 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
2709 - yaffs_Object *obj;
2710 - yaffs_Device *dev;
2712 - obj = yaffs_DentryToObject(dentry);
2716 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
2717 - yaffs_GrossLock(dev);
2718 - yaffs_FlushFile(obj, 1);
2719 - yaffs_GrossUnlock(dev);
2724 - * The VFS layer already does all the dentry stuff for rename.
2726 - * NB: POSIX says you can rename an object over an old object of the same name
2728 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
2729 - struct inode *new_dir, struct dentry *new_dentry)
2731 - yaffs_Device *dev;
2732 - int retVal = YAFFS_FAIL;
2733 - yaffs_Object *target;
2735 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
2736 - dev = yaffs_InodeToObject(old_dir)->myDev;
2738 - yaffs_GrossLock(dev);
2740 - /* Check if the target is an existing directory that is not empty. */
2741 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
2742 - new_dentry->d_name.name);
2746 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
2747 - !ylist_empty(&target->variant.directoryVariant.children)) {
2749 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
2751 - retVal = YAFFS_FAIL;
2753 - /* Now does unlinking internally using shadowing mechanism */
2754 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
2756 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
2757 - old_dentry->d_name.name,
2758 - yaffs_InodeToObject(new_dir),
2759 - new_dentry->d_name.name);
2761 - yaffs_GrossUnlock(dev);
2763 - if (retVal == YAFFS_OK) {
2765 - new_dentry->d_inode->i_nlink--;
2766 - mark_inode_dirty(new_dentry->d_inode);
2771 - return -ENOTEMPTY;
2775 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
2777 - struct inode *inode = dentry->d_inode;
2779 - yaffs_Device *dev;
2782 - ("yaffs_setattr of object %d\n",
2783 - yaffs_InodeToObject(inode)->objectId));
2785 - error = inode_change_ok(inode, attr);
2787 - dev = yaffs_InodeToObject(inode)->myDev;
2788 - yaffs_GrossLock(dev);
2789 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
2795 - yaffs_GrossUnlock(dev);
2797 - error = inode_setattr(inode, attr);
2802 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2803 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
2805 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2806 - struct super_block *sb = dentry->d_sb;
2807 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2808 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
2810 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2812 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
2814 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2817 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
2819 - yaffs_GrossLock(dev);
2821 - buf->f_type = YAFFS_MAGIC;
2822 - buf->f_bsize = sb->s_blocksize;
2823 - buf->f_namelen = 255;
2825 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
2826 - /* Do this if chunk size is not a power of 2 */
2828 - uint64_t bytesInDev;
2829 - uint64_t bytesFree;
2831 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
2832 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
2834 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
2835 - buf->f_blocks = bytesInDev;
2837 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
2838 - ((uint64_t)(dev->nDataBytesPerChunk));
2840 - do_div(bytesFree, sb->s_blocksize);
2842 - buf->f_bfree = bytesFree;
2844 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
2847 - (dev->endBlock - dev->startBlock + 1) *
2848 - dev->nChunksPerBlock /
2849 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2851 - yaffs_GetNumberOfFreeChunks(dev) /
2852 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2855 - (dev->endBlock - dev->startBlock + 1) *
2856 - dev->nChunksPerBlock *
2857 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2860 - yaffs_GetNumberOfFreeChunks(dev) *
2861 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2866 - buf->f_bavail = buf->f_bfree;
2868 - yaffs_GrossUnlock(dev);
2873 -static int yaffs_do_sync_fs(struct super_block *sb)
2876 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2877 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
2880 - yaffs_GrossLock(dev);
2883 - yaffs_FlushEntireDeviceCache(dev);
2884 - yaffs_CheckpointSave(dev);
2887 - yaffs_GrossUnlock(dev);
2895 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2896 -static void yaffs_write_super(struct super_block *sb)
2898 -static int yaffs_write_super(struct super_block *sb)
2902 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
2903 - if (yaffs_auto_checkpoint >= 2)
2904 - yaffs_do_sync_fs(sb);
2905 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
2911 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2912 -static int yaffs_sync_fs(struct super_block *sb, int wait)
2914 -static int yaffs_sync_fs(struct super_block *sb)
2917 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
2919 - if (yaffs_auto_checkpoint >= 1)
2920 - yaffs_do_sync_fs(sb);
2925 -#ifdef YAFFS_USE_OWN_IGET
2927 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
2929 - struct inode *inode;
2930 - yaffs_Object *obj;
2931 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2934 - ("yaffs_iget for %lu\n", ino));
2936 - inode = iget_locked(sb, ino);
2938 - return ERR_PTR(-ENOMEM);
2939 - if (!(inode->i_state & I_NEW))
2942 - /* NB This is called as a side effect of other functions, but
2943 - * we had to release the lock to prevent deadlocks, so
2944 - * need to lock again.
2947 - yaffs_GrossLock(dev);
2949 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2951 - yaffs_FillInodeFromObject(inode, obj);
2953 - yaffs_GrossUnlock(dev);
2955 - unlock_new_inode(inode);
2961 -static void yaffs_read_inode(struct inode *inode)
2963 - /* NB This is called as a side effect of other functions, but
2964 - * we had to release the lock to prevent deadlocks, so
2965 - * need to lock again.
2968 - yaffs_Object *obj;
2969 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
2972 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
2974 - yaffs_GrossLock(dev);
2976 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2978 - yaffs_FillInodeFromObject(inode, obj);
2980 - yaffs_GrossUnlock(dev);
2985 -static YLIST_HEAD(yaffs_dev_list);
2987 -#if 0 /* not used */
2988 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
2990 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2992 - if (*flags & MS_RDONLY) {
2993 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
2996 - ("yaffs_remount_fs: %s: RO\n", dev->name));
2998 - yaffs_GrossLock(dev);
3000 - yaffs_FlushEntireDeviceCache(dev);
3002 - yaffs_CheckpointSave(dev);
3007 - yaffs_GrossUnlock(dev);
3010 - ("yaffs_remount_fs: %s: RW\n", dev->name));
3017 -static void yaffs_put_super(struct super_block *sb)
3019 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3021 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3023 - yaffs_GrossLock(dev);
3025 - yaffs_FlushEntireDeviceCache(dev);
3027 - yaffs_CheckpointSave(dev);
3029 - if (dev->putSuperFunc)
3030 - dev->putSuperFunc(sb);
3032 - yaffs_Deinitialise(dev);
3034 - yaffs_GrossUnlock(dev);
3036 - /* we assume this is protected by lock_kernel() in mount/umount */
3037 - ylist_del(&dev->devList);
3039 - if (dev->spareBuffer) {
3040 - YFREE(dev->spareBuffer);
3041 - dev->spareBuffer = NULL;
3048 -static void yaffs_MTDPutSuper(struct super_block *sb)
3050 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3055 - put_mtd_device(mtd);
3059 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3061 - struct super_block *sb = (struct super_block *)vsb;
3063 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3070 - int skip_checkpoint_read;
3071 - int skip_checkpoint_write;
3075 -#define MAX_OPT_LEN 20
3076 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3078 - char cur_opt[MAX_OPT_LEN + 1];
3082 - /* Parse through the options which is a comma seperated list */
3084 - while (options_str && *options_str && !error) {
3085 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3088 - while (*options_str && *options_str != ',') {
3089 - if (p < MAX_OPT_LEN) {
3090 - cur_opt[p] = *options_str;
3096 - if (!strcmp(cur_opt, "inband-tags"))
3097 - options->inband_tags = 1;
3098 - else if (!strcmp(cur_opt, "no-cache"))
3099 - options->no_cache = 1;
3100 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3101 - options->skip_checkpoint_read = 1;
3102 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3103 - options->skip_checkpoint_write = 1;
3104 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3105 - options->skip_checkpoint_read = 1;
3106 - options->skip_checkpoint_write = 1;
3108 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3117 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3118 - struct super_block *sb,
3119 - void *data, int silent)
3122 - struct inode *inode = NULL;
3123 - struct dentry *root;
3124 - yaffs_Device *dev = 0;
3125 - char devname_buf[BDEVNAME_SIZE + 1];
3126 - struct mtd_info *mtd;
3128 - char *data_str = (char *)data;
3130 - yaffs_options options;
3132 - sb->s_magic = YAFFS_MAGIC;
3133 - sb->s_op = &yaffs_super_ops;
3134 - sb->s_flags |= MS_NOATIME;
3137 - printk(KERN_INFO "yaffs: sb is NULL\n");
3138 - else if (!sb->s_dev)
3139 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3140 - else if (!yaffs_devname(sb, devname_buf))
3141 - printk(KERN_INFO "yaffs: devname is NULL\n");
3143 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3145 - yaffs_devname(sb, devname_buf));
3150 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3152 - memset(&options, 0, sizeof(options));
3154 - if (yaffs_parse_options(&options, data_str)) {
3155 - /* Option parsing failed */
3160 - sb->s_blocksize = PAGE_CACHE_SIZE;
3161 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3162 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3164 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3166 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3168 - ("yaffs: Write verification disabled. All guarantees "
3169 - "null and void\n"));
3172 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3174 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3175 - yaffs_devname(sb, devname_buf)));
3177 - /* Check it's an mtd device..... */
3178 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3179 - return NULL; /* This isn't an mtd device */
3181 - /* Get the device */
3182 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3184 - T(YAFFS_TRACE_ALWAYS,
3185 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3186 - MINOR(sb->s_dev)));
3189 - /* Check it's NAND */
3190 - if (mtd->type != MTD_NANDFLASH) {
3191 - T(YAFFS_TRACE_ALWAYS,
3192 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3196 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3197 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3198 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3199 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3200 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3201 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3202 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3203 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3204 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3205 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3206 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3207 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3209 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3212 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3214 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3215 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3219 - /* Added NCB 26/5/2006 for completeness */
3220 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3221 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3227 - if (yaffsVersion == 2) {
3228 - /* Check for version 2 style functions */
3229 - if (!mtd->erase ||
3230 - !mtd->block_isbad ||
3231 - !mtd->block_markbad ||
3234 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3235 - !mtd->read_oob || !mtd->write_oob) {
3237 - !mtd->write_ecc ||
3238 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3240 - T(YAFFS_TRACE_ALWAYS,
3241 - ("yaffs: MTD device does not support required "
3246 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3247 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3248 - !options.inband_tags) {
3249 - T(YAFFS_TRACE_ALWAYS,
3250 - ("yaffs: MTD device does not have the "
3251 - "right page sizes\n"));
3255 - /* Check for V1 style functions */
3256 - if (!mtd->erase ||
3259 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3260 - !mtd->read_oob || !mtd->write_oob) {
3262 - !mtd->write_ecc ||
3263 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3265 - T(YAFFS_TRACE_ALWAYS,
3266 - ("yaffs: MTD device does not support required "
3271 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3272 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3273 - T(YAFFS_TRACE_ALWAYS,
3274 - ("yaffs: MTD device does not support have the "
3275 - "right page sizes\n"));
3280 - /* OK, so if we got here, we have an MTD that's NAND and looks
3281 - * like it has the right capabilities
3282 - * Set the yaffs_Device up for mtd
3285 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3286 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3288 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3291 - /* Deep shit could not allocate device structure */
3292 - T(YAFFS_TRACE_ALWAYS,
3293 - ("yaffs_read_super: Failed trying to allocate "
3294 - "yaffs_Device. \n"));
3298 - memset(dev, 0, sizeof(yaffs_Device));
3299 - dev->genericDevice = mtd;
3300 - dev->name = mtd->name;
3302 - /* Set up the memory size parameters.... */
3304 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3306 - dev->startBlock = 0;
3307 - dev->endBlock = nBlocks - 1;
3308 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3309 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3310 - dev->nReservedBlocks = 5;
3311 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3312 - dev->inbandTags = options.inband_tags;
3314 - /* ... and the functions. */
3315 - if (yaffsVersion == 2) {
3316 - dev->writeChunkWithTagsToNAND =
3317 - nandmtd2_WriteChunkWithTagsToNAND;
3318 - dev->readChunkWithTagsFromNAND =
3319 - nandmtd2_ReadChunkWithTagsFromNAND;
3320 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3321 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3322 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3323 - dev->isYaffs2 = 1;
3324 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3325 - dev->totalBytesPerChunk = mtd->writesize;
3326 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3328 - dev->totalBytesPerChunk = mtd->oobblock;
3329 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3331 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3333 - dev->startBlock = 0;
3334 - dev->endBlock = nBlocks - 1;
3336 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3337 - /* use the MTD interface in yaffs_mtdif1.c */
3338 - dev->writeChunkWithTagsToNAND =
3339 - nandmtd1_WriteChunkWithTagsToNAND;
3340 - dev->readChunkWithTagsFromNAND =
3341 - nandmtd1_ReadChunkWithTagsFromNAND;
3342 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3343 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3345 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3346 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3348 - dev->isYaffs2 = 0;
3350 - /* ... and common functions */
3351 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3352 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3354 - dev->putSuperFunc = yaffs_MTDPutSuper;
3356 - dev->superBlock = (void *)sb;
3357 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3360 -#ifndef CONFIG_YAFFS_DOES_ECC
3361 - dev->useNANDECC = 1;
3364 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3365 - dev->wideTnodesDisabled = 1;
3368 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3369 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3371 - /* we assume this is protected by lock_kernel() in mount/umount */
3372 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3374 - init_MUTEX(&dev->grossLock);
3376 - yaffs_GrossLock(dev);
3378 - err = yaffs_GutsInitialise(dev);
3381 - ("yaffs_read_super: guts initialised %s\n",
3382 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3384 - /* Release lock before yaffs_get_inode() */
3385 - yaffs_GrossUnlock(dev);
3387 - /* Create root inode */
3388 - if (err == YAFFS_OK)
3389 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3395 - inode->i_op = &yaffs_dir_inode_operations;
3396 - inode->i_fop = &yaffs_dir_operations;
3398 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3400 - root = d_alloc_root(inode);
3402 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3408 - sb->s_root = root;
3409 - sb->s_dirt = !dev->isCheckpointed;
3410 - T(YAFFS_TRACE_ALWAYS,
3411 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3413 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3418 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3419 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3422 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3425 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3426 -static int yaffs_read_super(struct file_system_type *fs,
3427 - int flags, const char *dev_name,
3428 - void *data, struct vfsmount *mnt)
3431 - return get_sb_bdev(fs, flags, dev_name, data,
3432 - yaffs_internal_read_super_mtd, mnt);
3435 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3436 - int flags, const char *dev_name,
3440 - return get_sb_bdev(fs, flags, dev_name, data,
3441 - yaffs_internal_read_super_mtd);
3445 -static struct file_system_type yaffs_fs_type = {
3446 - .owner = THIS_MODULE,
3448 - .get_sb = yaffs_read_super,
3449 - .kill_sb = kill_block_super,
3450 - .fs_flags = FS_REQUIRES_DEV,
3453 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3456 - return yaffs_internal_read_super(1, sb, data, silent);
3459 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3464 -#ifdef CONFIG_YAFFS_YAFFS2
3466 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3467 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3470 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3473 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3474 -static int yaffs2_read_super(struct file_system_type *fs,
3475 - int flags, const char *dev_name, void *data,
3476 - struct vfsmount *mnt)
3478 - return get_sb_bdev(fs, flags, dev_name, data,
3479 - yaffs2_internal_read_super_mtd, mnt);
3482 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3483 - int flags, const char *dev_name,
3487 - return get_sb_bdev(fs, flags, dev_name, data,
3488 - yaffs2_internal_read_super_mtd);
3492 -static struct file_system_type yaffs2_fs_type = {
3493 - .owner = THIS_MODULE,
3495 - .get_sb = yaffs2_read_super,
3496 - .kill_sb = kill_block_super,
3497 - .fs_flags = FS_REQUIRES_DEV,
3500 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3501 - void *data, int silent)
3503 - return yaffs_internal_read_super(2, sb, data, silent);
3506 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3510 -#endif /* CONFIG_YAFFS_YAFFS2 */
3512 -static struct proc_dir_entry *my_proc_entry;
3514 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3516 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3517 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3518 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3519 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3520 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3521 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3522 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3523 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3524 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3525 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3526 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3527 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3528 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3529 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3530 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3531 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3532 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3533 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3534 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3535 - buf += sprintf(buf, "passiveGCs......... %d\n",
3536 - dev->passiveGarbageCollections);
3537 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3538 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3539 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3540 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3541 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3542 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3543 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3544 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3545 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3546 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3548 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3549 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3550 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3551 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3556 -static int yaffs_proc_read(char *page,
3558 - off_t offset, int count, int *eof, void *data)
3560 - struct ylist_head *item;
3562 - int step = offset;
3565 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3566 - * We use 'offset' (*ppos) to indicate where we are in devList.
3567 - * This also assumes the user has posted a read buffer large
3568 - * enough to hold the complete output; but that's life in /proc.
3571 - *(int *)start = 1;
3573 - /* Print header first */
3575 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3576 - "\n%s\n%s\n", yaffs_fs_c_version,
3577 - yaffs_guts_c_version);
3580 - /* hold lock_kernel while traversing yaffs_dev_list */
3583 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3584 - ylist_for_each(item, &yaffs_dev_list) {
3585 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3590 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3591 - buf = yaffs_dump_dev(buf, dev);
3596 - return buf - page < count ? buf - page : count;
3600 - * Set the verbosity of the warnings and error messages.
3602 - * Note that the names can only be a..z or _ with the current code.
3607 - unsigned mask_bitfield;
3609 - {"allocate", YAFFS_TRACE_ALLOCATE},
3610 - {"always", YAFFS_TRACE_ALWAYS},
3611 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3612 - {"buffers", YAFFS_TRACE_BUFFERS},
3613 - {"bug", YAFFS_TRACE_BUG},
3614 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
3615 - {"deletion", YAFFS_TRACE_DELETION},
3616 - {"erase", YAFFS_TRACE_ERASE},
3617 - {"error", YAFFS_TRACE_ERROR},
3618 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
3619 - {"gc", YAFFS_TRACE_GC},
3620 - {"mtd", YAFFS_TRACE_MTD},
3621 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
3622 - {"os", YAFFS_TRACE_OS},
3623 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
3624 - {"scan", YAFFS_TRACE_SCAN},
3625 - {"tracing", YAFFS_TRACE_TRACING},
3627 - {"verify", YAFFS_TRACE_VERIFY},
3628 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
3629 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
3630 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
3632 - {"write", YAFFS_TRACE_WRITE},
3633 - {"all", 0xffffffff},
3638 -#define MAX_MASK_NAME_LENGTH 40
3639 -static int yaffs_proc_write(struct file *file, const char *buf,
3640 - unsigned long count, void *data)
3642 - unsigned rg = 0, mask_bitfield;
3646 - char substring[MAX_MASK_NAME_LENGTH + 1];
3652 - rg = yaffs_traceMask;
3654 - while (!done && (pos < count)) {
3656 - while ((pos < count) && isspace(buf[pos]))
3659 - switch (buf[pos]) {
3673 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
3675 - if (end > buf + pos) {
3676 - mask_name = "numeral";
3677 - len = end - (buf + pos);
3681 - for (x = buf + pos, i = 0;
3682 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
3683 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
3684 - substring[i] = *x;
3685 - substring[i] = '\0';
3687 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3688 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
3689 - mask_name = mask_flags[i].mask_name;
3690 - mask_bitfield = mask_flags[i].mask_bitfield;
3697 - if (mask_name != NULL) {
3701 - rg &= ~mask_bitfield;
3704 - rg |= mask_bitfield;
3707 - rg = mask_bitfield;
3710 - rg |= mask_bitfield;
3716 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
3718 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
3720 - if (rg & YAFFS_TRACE_ALWAYS) {
3721 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3723 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
3724 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
3731 -/* Stuff to handle installation of file systems */
3732 -struct file_system_to_install {
3733 - struct file_system_type *fst;
3737 -static struct file_system_to_install fs_to_install[] = {
3738 - {&yaffs_fs_type, 0},
3739 - {&yaffs2_fs_type, 0},
3743 -static int __init init_yaffs_fs(void)
3746 - struct file_system_to_install *fsinst;
3748 - T(YAFFS_TRACE_ALWAYS,
3749 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
3751 - /* Install the proc_fs entry */
3752 - my_proc_entry = create_proc_entry("yaffs",
3753 - S_IRUGO | S_IFREG,
3756 - if (my_proc_entry) {
3757 - my_proc_entry->write_proc = yaffs_proc_write;
3758 - my_proc_entry->read_proc = yaffs_proc_read;
3759 - my_proc_entry->data = NULL;
3763 - /* Now add the file system entries */
3765 - fsinst = fs_to_install;
3767 - while (fsinst->fst && !error) {
3768 - error = register_filesystem(fsinst->fst);
3770 - fsinst->installed = 1;
3774 - /* Any errors? uninstall */
3776 - fsinst = fs_to_install;
3778 - while (fsinst->fst) {
3779 - if (fsinst->installed) {
3780 - unregister_filesystem(fsinst->fst);
3781 - fsinst->installed = 0;
3790 -static void __exit exit_yaffs_fs(void)
3793 - struct file_system_to_install *fsinst;
3795 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
3796 - " removing. \n"));
3798 - remove_proc_entry("yaffs", YPROC_ROOT);
3800 - fsinst = fs_to_install;
3802 - while (fsinst->fst) {
3803 - if (fsinst->installed) {
3804 - unregister_filesystem(fsinst->fst);
3805 - fsinst->installed = 0;
3811 -module_init(init_yaffs_fs)
3812 -module_exit(exit_yaffs_fs)
3814 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
3815 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
3816 -MODULE_LICENSE("GPL");
3817 diff -Nrup a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h
3818 --- a/fs/yaffs2/yaffs_getblockinfo.h 2010-10-03 17:48:22.710000363 +0300
3819 +++ b/fs/yaffs2/yaffs_getblockinfo.h 2010-10-03 18:03:47.542000362 +0300
3822 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3824 - * Copyright (C) 2002-2007 Aleph One Ltd.
3825 + * Copyright (C) 2002-2010 Aleph One Ltd.
3826 * for Toby Churchill Ltd and Brightstar Engineering
3828 * Created by Charles Manning <charles@aleph1.co.uk>
3830 #define __YAFFS_GETBLOCKINFO_H__
3832 #include "yaffs_guts.h"
3833 +#include "yaffs_trace.h"
3835 /* Function to manipulate block info */
3836 static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
3837 diff -Nrup a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
3838 --- a/fs/yaffs2/yaffs_guts.c 2010-10-03 17:48:22.715000364 +0300
3839 +++ b/fs/yaffs2/yaffs_guts.c 2010-10-03 18:03:47.518000364 +0300
3842 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3844 - * Copyright (C) 2002-2007 Aleph One Ltd.
3845 + * Copyright (C) 2002-2010 Aleph One Ltd.
3846 * for Toby Churchill Ltd and Brightstar Engineering
3848 * Created by Charles Manning <charles@aleph1.co.uk>
3850 * it under the terms of the GNU General Public License version 2 as
3851 * published by the Free Software Foundation.
3854 -const char *yaffs_guts_c_version =
3855 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
3857 #include "yportenv.h"
3858 +#include "yaffs_trace.h"
3860 #include "yaffsinterface.h"
3861 #include "yaffs_guts.h"
3862 @@ -22,22 +19,28 @@ const char *yaffs_guts_c_version =
3863 #include "yaffs_getblockinfo.h"
3865 #include "yaffs_tagscompat.h"
3866 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
3867 -#include "yaffs_qsort.h"
3870 #include "yaffs_nand.h"
3872 -#include "yaffs_checkptrw.h"
3873 +#include "yaffs_yaffs1.h"
3874 +#include "yaffs_yaffs2.h"
3875 +#include "yaffs_bitmap.h"
3876 +#include "yaffs_verify.h"
3878 #include "yaffs_nand.h"
3879 #include "yaffs_packedtags2.h"
3881 +#include "yaffs_nameval.h"
3882 +#include "yaffs_allocator.h"
3884 -#define YAFFS_PASSIVE_GC_CHUNKS 2
3885 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
3886 +#define YAFFS_GC_GOOD_ENOUGH 2
3887 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
3889 #include "yaffs_ecc.h"
3893 /* Robustification (if it ever comes about...) */
3894 static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
3895 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
3896 @@ -49,33 +52,26 @@ static void yaffs_HandleUpdateChunk(yaff
3897 const yaffs_ExtendedTags *tags);
3899 /* Other local prototypes */
3900 +static void yaffs_UpdateParent(yaffs_Object *obj);
3901 static int yaffs_UnlinkObject(yaffs_Object *obj);
3902 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
3904 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
3906 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
3908 yaffs_ExtendedTags *tags,
3910 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
3911 - int chunkInNAND, int inScan);
3914 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
3915 yaffs_ObjectType type);
3916 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
3917 - yaffs_Object *obj);
3918 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
3919 - int force, int isShrink, int shadows);
3922 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
3924 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
3925 static int yaffs_CheckStructures(void);
3926 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
3927 - int chunkOffset, int *limit);
3928 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
3930 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
3933 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
3936 @@ -87,30 +83,22 @@ static int yaffs_TagsMatch(const yaffs_E
3937 static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
3938 yaffs_BlockInfo **blockUsedPtr);
3940 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
3942 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
3944 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
3945 -#ifdef YAFFS_PARANOID
3946 -static int yaffs_CheckFileSanity(yaffs_Object *in);
3948 -#define yaffs_CheckFileSanity(in)
3951 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
3952 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
3954 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
3956 static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
3957 yaffs_ExtendedTags *tags);
3959 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
3961 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
3962 - yaffs_FileStructure *fStruct,
3964 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
3967 + yaffs_ExtendedTags *tags);
3970 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
3971 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
3974 /* Function to calculate chunk and offset */
3975 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
3977 static __u32 Shifts(__u32 x)
3984 @@ -203,7 +191,7 @@ static int yaffs_InitialiseTempBuffers(y
3985 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
3986 dev->tempBuffer[i].line = 0; /* not in use */
3987 dev->tempBuffer[i].buffer = buf =
3988 - YMALLOC_DMA(dev->totalBytesPerChunk);
3989 + YMALLOC_DMA(dev->param.totalBytesPerChunk);
3992 return buf ? YAFFS_OK : YAFFS_FAIL;
3993 @@ -286,7 +274,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
3997 - for (i = 0; i < dev->nShortOpCaches; i++) {
3998 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
3999 if (dev->srCache[i].data == buffer)
4002 @@ -299,6374 +287,4183 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
4009 - * Chunk bitmap manipulations
4010 + * Verification code
4013 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
4015 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4016 - T(YAFFS_TRACE_ERROR,
4017 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4021 - return dev->chunkBits +
4022 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4025 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4027 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4028 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4029 - T(YAFFS_TRACE_ERROR,
4030 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4036 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4038 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4040 - memset(blkBits, 0, dev->chunkBitmapStride);
4043 + * Simple hash function. Needs to have a reasonable spread
4046 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4047 +static Y_INLINE int yaffs_HashFunction(int n)
4049 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4051 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4053 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4055 + return n % YAFFS_NOBJECT_BUCKETS;
4058 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4060 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4062 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4064 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4067 + * Access functions to useful fake objects.
4068 + * Note that root might have a presence in NAND if permissions are set.
4071 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4072 +yaffs_Object *yaffs_Root(yaffs_Device *dev)
4074 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4075 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4077 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4078 + return dev->rootDir;
4081 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4082 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4084 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4086 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4092 + return dev->lostNFoundDir;
4095 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4097 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4100 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4101 - __u8 x = *blkBits;
4114 - * Verification code
4115 + * Erased NAND checking functions
4118 -static int yaffs_SkipVerification(yaffs_Device *dev)
4120 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4123 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4125 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4128 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4129 +int yaffs_CheckFF(__u8 *buffer, int nBytes)
4131 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4132 + /* Horrible, slow implementation */
4133 + while (nBytes--) {
4134 + if (*buffer != 0xFF)
4141 -static const char *blockStateName[] = {
4154 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4155 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4160 + int retval = YAFFS_OK;
4161 + __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4162 + yaffs_ExtendedTags tags;
4165 - if (yaffs_SkipVerification(dev))
4167 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4169 - /* Report illegal runtime states */
4170 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4171 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4172 + if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4173 + retval = YAFFS_FAIL;
4175 - switch (bi->blockState) {
4176 - case YAFFS_BLOCK_STATE_UNKNOWN:
4177 - case YAFFS_BLOCK_STATE_SCANNING:
4178 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4179 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4180 - n, blockStateName[bi->blockState]));
4181 + if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4182 + T(YAFFS_TRACE_NANDACCESS,
4183 + (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
4184 + retval = YAFFS_FAIL;
4187 - /* Check pages in use and soft deletions are legal */
4189 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4191 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4192 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4193 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4194 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4195 - n, bi->pagesInUse, bi->softDeletions));
4197 + yaffs_ReleaseTempBuffer(dev, data, __LINE__);
4199 - /* Check chunk bitmap legal */
4200 - inUse = yaffs_CountChunkBits(dev, n);
4201 - if (inUse != bi->pagesInUse)
4202 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4203 - n, bi->pagesInUse, inUse));
4206 - /* Check that the sequence number is valid.
4207 - * Ten million is legal, but is very unlikely
4209 - if (dev->isYaffs2 &&
4210 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4211 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4212 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4213 - n, bi->sequenceNumber));
4216 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4219 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
4222 + yaffs_ExtendedTags *tags)
4224 - yaffs_VerifyBlock(dev, bi, n);
4225 + int retval = YAFFS_OK;
4226 + yaffs_ExtendedTags tempTags;
4227 + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
4230 + result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
4231 + if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
4232 + tempTags.objectId != tags->objectId ||
4233 + tempTags.chunkId != tags->chunkId ||
4234 + tempTags.byteCount != tags->byteCount)
4235 + retval = YAFFS_FAIL;
4237 - /* After collection the block should be in the erased state */
4238 - /* This will need to change if we do partial gc */
4239 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4241 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4242 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4243 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4244 - n, bi->blockState));
4249 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4250 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
4252 + yaffs_ExtendedTags *tags,
4256 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4257 - int nIllegalBlockStates = 0;
4259 - if (yaffs_SkipVerification(dev))
4262 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4264 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4265 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4266 - yaffs_VerifyBlock(dev, bi, i);
4268 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4269 - nBlocksPerState[bi->blockState]++;
4271 - nIllegalBlockStates++;
4277 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4278 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4279 + yaffs2_InvalidateCheckpoint(dev);
4281 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4282 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4283 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4285 + yaffs_BlockInfo *bi = 0;
4288 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4289 - T(YAFFS_TRACE_VERIFY,
4290 - (TSTR("%s %d blocks"TENDSTR),
4291 - blockStateName[i], nBlocksPerState[i]));
4292 + chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
4298 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4299 - T(YAFFS_TRACE_VERIFY,
4300 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4301 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4302 + /* First check this chunk is erased, if it needs
4303 + * checking. The checking policy (unless forced
4304 + * always on) is as follows:
4306 + * Check the first page we try to write in a block.
4307 + * If the check passes then we don't need to check any
4308 + * more. If the check fails, we check again...
4309 + * If the block has been erased, we don't need to check.
4311 + * However, if the block has been prioritised for gc,
4312 + * then we think there might be something odd about
4313 + * this block and stop using it.
4315 + * Rationale: We should only ever see chunks that have
4316 + * not been erased if there was a partially written
4317 + * chunk due to power loss. This checking policy should
4318 + * catch that case with very few checks and thus save a
4319 + * lot of checks that are most likely not needed.
4321 + * Mods to the above
4322 + * If an erase check fails or the write fails we skip the
4323 + * rest of the block.
4326 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4327 - T(YAFFS_TRACE_VERIFY,
4328 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4329 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4330 + /* let's give it a try */
4333 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4334 - T(YAFFS_TRACE_VERIFY,
4335 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4336 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4337 + if(dev->param.alwaysCheckErased)
4338 + bi->skipErasedCheck = 0;
4340 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4341 + if (!bi->skipErasedCheck) {
4342 + erasedOk = yaffs_CheckChunkErased(dev, chunk);
4343 + if (erasedOk != YAFFS_OK) {
4344 + T(YAFFS_TRACE_ERROR,
4345 + (TSTR("**>> yaffs chunk %d was not erased"
4346 + TENDSTR), chunk));
4349 + /* If not erased, delete this one,
4350 + * skip rest of block and
4351 + * try another chunk */
4352 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4353 + yaffs_SkipRestOfBlock(dev);
4359 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4360 - * case those tests will not be performed.
4362 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4364 - if (obj && yaffs_SkipVerification(obj->myDev))
4366 + writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
4369 - if (!(tags && obj && oh)) {
4370 - T(YAFFS_TRACE_VERIFY,
4371 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4372 - (__u32)tags, (__u32)obj, (__u32)oh));
4375 + if(!bi->skipErasedCheck)
4376 + writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
4378 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4379 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4380 - T(YAFFS_TRACE_VERIFY,
4381 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4382 - tags->objectId, oh->type));
4383 + if (writeOk != YAFFS_OK) {
4384 + /* Clean up aborted write, skip to next block and
4385 + * try another chunk */
4386 + yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
4390 - if (tags->objectId != obj->objectId)
4391 - T(YAFFS_TRACE_VERIFY,
4392 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4393 - tags->objectId, obj->objectId));
4394 + bi->skipErasedCheck = 1;
4396 + /* Copy the data into the robustification buffer */
4397 + yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
4400 - * Check that the object's parent ids match if parentCheck requested.
4402 - * Tests do not apply to the root object.
4404 + } while (writeOk != YAFFS_OK &&
4405 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4407 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4408 - T(YAFFS_TRACE_VERIFY,
4409 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4410 - tags->objectId, oh->parentObjectId));
4414 - if (parentCheck && obj->parent &&
4415 - oh->parentObjectId != obj->parent->objectId &&
4416 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
4417 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
4418 - T(YAFFS_TRACE_VERIFY,
4419 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
4420 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
4421 + if (attempts > 1) {
4422 + T(YAFFS_TRACE_ERROR,
4423 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
4426 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
4427 - T(YAFFS_TRACE_VERIFY,
4428 - (TSTR("Obj %d header name is NULL"TENDSTR),
4430 + dev->nRetriedWrites += (attempts - 1);
4433 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
4434 - T(YAFFS_TRACE_VERIFY,
4435 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
4443 + * Block retiring for handling a broken block.
4446 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
4447 - __u32 level, int chunkOffset)
4448 +static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
4451 - yaffs_Device *dev = obj->myDev;
4453 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4457 + yaffs2_InvalidateCheckpoint(dev);
4459 + yaffs2_ClearOldestDirtySequence(dev,bi);
4461 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
4462 - if (tn->internal[i]) {
4463 - ok = yaffs_VerifyTnodeWorker(obj,
4466 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
4469 - } else if (level == 0) {
4470 + if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
4471 + if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
4472 + T(YAFFS_TRACE_ALWAYS, (TSTR(
4473 + "yaffs: Failed to mark bad and erase block %d"
4474 + TENDSTR), blockInNAND));
4476 yaffs_ExtendedTags tags;
4477 - __u32 objectId = obj->objectId;
4478 + int chunkId = blockInNAND * dev->param.nChunksPerBlock;
4480 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
4481 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4483 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
4484 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4485 + memset(buffer, 0xff, dev->nDataBytesPerChunk);
4486 + yaffs_InitialiseTags(&tags);
4487 + tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
4488 + if (dev->param.writeChunkWithTagsToNAND(dev, chunkId -
4489 + dev->chunkOffset, buffer, &tags) != YAFFS_OK)
4490 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
4491 + TCONT("write bad block marker to block %d")
4492 + TENDSTR), blockInNAND));
4494 - if (theChunk > 0) {
4495 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
4496 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4497 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
4498 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4499 - objectId, chunkOffset, theChunk,
4500 - tags.objectId, tags.chunkId));
4505 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4510 + bi->blockState = YAFFS_BLOCK_STATE_DEAD;
4511 + bi->gcPrioritise = 0;
4512 + bi->needsRetiring = 0;
4514 + dev->nRetiredBlocks++;
4518 + * Functions for robustisizing TODO
4522 -static void yaffs_VerifyFile(yaffs_Object *obj)
4523 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4525 + const yaffs_ExtendedTags *tags)
4527 - int requiredTallness;
4528 - int actualTallness;
4532 - yaffs_Device *dev;
4533 - yaffs_ExtendedTags tags;
4537 + chunkInNAND=chunkInNAND;
4544 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4545 + const yaffs_ExtendedTags *tags)
4548 + chunkInNAND=chunkInNAND;
4552 - if (yaffs_SkipVerification(obj->myDev))
4554 +void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
4556 + if (!bi->gcPrioritise) {
4557 + bi->gcPrioritise = 1;
4558 + dev->hasPendingPrioritisedGCs = 1;
4559 + bi->chunkErrorStrikes++;
4562 - objectId = obj->objectId;
4563 + if (bi->chunkErrorStrikes > 3) {
4564 + bi->needsRetiring = 1; /* Too many stikes, so retire this */
4565 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
4567 - /* Check file size is consistent with tnode depth */
4568 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
4569 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
4570 - requiredTallness = 0;
4572 - x >>= YAFFS_TNODES_INTERNAL_BITS;
4573 - requiredTallness++;
4578 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4581 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
4582 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4584 - actualTallness = obj->variant.fileVariant.topLevel;
4585 + yaffs_HandleChunkError(dev, bi);
4587 - if (requiredTallness > actualTallness)
4588 - T(YAFFS_TRACE_VERIFY,
4589 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
4590 - obj->objectId, actualTallness, requiredTallness));
4592 + /* Was an actual write failure, so mark the block for retirement */
4593 + bi->needsRetiring = 1;
4594 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4595 + (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
4598 + /* Delete the chunk */
4599 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
4600 + yaffs_SkipRestOfBlock(dev);
4604 - /* Check that the chunks in the tnode tree are all correct.
4605 - * We do this by scanning through the tnode tree and
4606 - * checking the tags for every chunk match.
4608 +/*---------------- Name handling functions ------------*/
4610 - if (yaffs_SkipNANDVerification(dev))
4612 +static __u16 yaffs_CalcNameSum(const YCHAR *name)
4617 - for (i = 1; i <= lastChunk; i++) {
4618 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
4619 + const YUCHAR *bname = (const YUCHAR *) name;
4621 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
4624 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4625 - if (theChunk > 0) {
4626 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
4627 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4628 - if (tags.objectId != objectId || tags.chunkId != i) {
4629 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4630 - objectId, i, theChunk,
4631 - tags.objectId, tags.chunkId));
4634 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4635 + sum += yaffs_toupper(*bname) * i;
4637 + sum += (*bname) * i;
4647 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
4648 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
4650 - if (obj && yaffs_SkipVerification(obj->myDev))
4652 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
4653 + memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
4654 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
4655 + yaffs_strcpy(obj->shortName, name);
4657 + obj->shortName[0] = _Y('\0');
4659 + obj->sum = yaffs_CalcNameSum(name);
4662 - /* Verify sane equivalent object */
4663 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
4665 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
4666 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
4667 + memset(tmpName,0,sizeof(tmpName));
4668 + yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
4669 + yaffs_SetObjectName(obj,tmpName);
4671 + yaffs_SetObjectName(obj,oh->name);
4675 -static void yaffs_VerifySymlink(yaffs_Object *obj)
4676 +/*-------------------- TNODES -------------------
4678 + * List of spare tnodes
4679 + * The list is hooked together using the first pointer
4684 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
4686 - if (obj && yaffs_SkipVerification(obj->myDev))
4688 + yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev);
4690 + memset(tn, 0, dev->tnodeSize);
4694 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4696 - /* Verify symlink string */
4700 -static void yaffs_VerifySpecial(yaffs_Object *obj)
4701 +/* FreeTnode frees up a tnode and puts it back on the free list */
4702 +static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
4704 - if (obj && yaffs_SkipVerification(obj->myDev))
4706 + yaffs_FreeRawTnode(dev,tn);
4708 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4711 -static void yaffs_VerifyObject(yaffs_Object *obj)
4712 +static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev)
4714 - yaffs_Device *dev;
4720 - __u32 chunkInRange;
4721 - __u32 chunkShouldNotBeDeleted;
4726 + yaffs_DeinitialiseRawTnodesAndObjects(dev);
4727 + dev->nObjects = 0;
4731 - if (obj->beingCreated)
4735 +void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
4738 + __u32 *map = (__u32 *)tn;
4744 - if (yaffs_SkipVerification(dev))
4746 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4747 + val >>= dev->chunkGroupBits;
4749 - /* Check sane object header chunk */
4750 + bitInMap = pos * dev->tnodeWidth;
4751 + wordInMap = bitInMap / 32;
4752 + bitInWord = bitInMap & (32 - 1);
4754 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
4755 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
4756 + mask = dev->tnodeMask << bitInWord;
4758 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
4759 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
4760 - chunkValid = chunkInRange &&
4761 - yaffs_CheckChunkBit(dev,
4762 - obj->hdrChunk / dev->nChunksPerBlock,
4763 - obj->hdrChunk % dev->nChunksPerBlock);
4764 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
4765 + map[wordInMap] &= ~mask;
4766 + map[wordInMap] |= (mask & (val << bitInWord));
4769 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
4770 - T(YAFFS_TRACE_VERIFY,
4771 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
4772 - obj->objectId, obj->hdrChunk,
4773 - chunkIdOk ? "" : ",out of range",
4774 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
4775 + if (dev->tnodeWidth > (32 - bitInWord)) {
4776 + bitInWord = (32 - bitInWord);
4778 + mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
4779 + map[wordInMap] &= ~mask;
4780 + map[wordInMap] |= (mask & (val >> bitInWord));
4784 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
4785 - yaffs_ExtendedTags tags;
4786 - yaffs_ObjectHeader *oh;
4787 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4789 - oh = (yaffs_ObjectHeader *)buffer;
4790 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4793 + __u32 *map = (__u32 *)tn;
4799 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
4801 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4803 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
4804 + bitInMap = pos * dev->tnodeWidth;
4805 + wordInMap = bitInMap / 32;
4806 + bitInWord = bitInMap & (32 - 1);
4808 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4810 + val = map[wordInMap] >> bitInWord;
4812 - /* Verify it has a parent */
4813 - if (obj && !obj->fake &&
4814 - (!obj->parent || obj->parent->myDev != dev)) {
4815 - T(YAFFS_TRACE_VERIFY,
4816 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
4817 - obj->objectId, obj->parent));
4818 + if (dev->tnodeWidth > (32 - bitInWord)) {
4819 + bitInWord = (32 - bitInWord);
4821 + val |= (map[wordInMap] << bitInWord);
4824 - /* Verify parent is a directory */
4825 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
4826 - T(YAFFS_TRACE_VERIFY,
4827 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
4828 - obj->objectId, obj->parent->variantType));
4830 + val &= dev->tnodeMask;
4831 + val <<= dev->chunkGroupBits;
4833 - switch (obj->variantType) {
4834 - case YAFFS_OBJECT_TYPE_FILE:
4835 - yaffs_VerifyFile(obj);
4837 - case YAFFS_OBJECT_TYPE_SYMLINK:
4838 - yaffs_VerifySymlink(obj);
4840 - case YAFFS_OBJECT_TYPE_DIRECTORY:
4841 - yaffs_VerifyDirectory(obj);
4843 - case YAFFS_OBJECT_TYPE_HARDLINK:
4844 - yaffs_VerifyHardLink(obj);
4846 - case YAFFS_OBJECT_TYPE_SPECIAL:
4847 - yaffs_VerifySpecial(obj);
4849 - case YAFFS_OBJECT_TYPE_UNKNOWN:
4851 - T(YAFFS_TRACE_VERIFY,
4852 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
4853 - obj->objectId, obj->variantType));
4859 -static void yaffs_VerifyObjects(yaffs_Device *dev)
4860 +/* ------------------- End of individual tnode manipulation -----------------*/
4862 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
4863 + * The look up tree is represented by the top tnode and the number of topLevel
4864 + * in the tree. 0 means only the level 0 tnode is in the tree.
4867 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
4868 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4869 + yaffs_FileStructure *fStruct,
4872 - yaffs_Object *obj;
4874 - struct ylist_head *lh;
4875 + yaffs_Tnode *tn = fStruct->top;
4877 + int requiredTallness;
4878 + int level = fStruct->topLevel;
4880 - if (yaffs_SkipVerification(dev))
4884 - /* Iterate through the objects in each hash entry */
4885 + /* Check sane level and chunk Id */
4886 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
4889 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
4890 - ylist_for_each(lh, &dev->objectBucket[i].list) {
4892 - obj = ylist_entry(lh, yaffs_Object, hashLink);
4893 - yaffs_VerifyObject(obj);
4896 + if (chunkId > YAFFS_MAX_CHUNK_ID)
4899 + /* First check we're tall enough (ie enough topLevel) */
4901 + i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
4902 + requiredTallness = 0;
4904 + i >>= YAFFS_TNODES_INTERNAL_BITS;
4905 + requiredTallness++;
4909 + if (requiredTallness > fStruct->topLevel)
4910 + return NULL; /* Not tall enough, so we can't find it */
4913 - * Simple hash function. Needs to have a reasonable spread
4915 + /* Traverse down to level 0 */
4916 + while (level > 0 && tn) {
4917 + tn = tn->internal[(chunkId >>
4918 + (YAFFS_TNODES_LEVEL0_BITS +
4920 + YAFFS_TNODES_INTERNAL_BITS)) &
4921 + YAFFS_TNODES_INTERNAL_MASK];
4925 -static Y_INLINE int yaffs_HashFunction(int n)
4928 - return n % YAFFS_NOBJECT_BUCKETS;
4933 - * Access functions to useful fake objects.
4934 - * Note that root might have a presence in NAND if permissions are set.
4935 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
4936 + * This happens in two steps:
4937 + * 1. If the tree isn't tall enough, then make it taller.
4938 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
4940 + * Used when modifying the tree.
4942 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
4943 + * be plugged into the ttree.
4946 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
4947 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
4948 + yaffs_FileStructure *fStruct,
4950 + yaffs_Tnode *passedTn)
4952 - return dev->rootDir;
4954 + int requiredTallness;
4959 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4961 - return dev->lostNFoundDir;
4967 - * Erased NAND checking functions
4969 + /* Check sane level and page Id */
4970 + if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
4973 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
4975 - /* Horrible, slow implementation */
4976 - while (nBytes--) {
4977 - if (*buffer != 0xFF)
4984 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4987 - int retval = YAFFS_OK;
4988 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4989 - yaffs_ExtendedTags tags;
4992 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4994 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4995 - retval = YAFFS_FAIL;
4997 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4998 - T(YAFFS_TRACE_NANDACCESS,
4999 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
5000 - retval = YAFFS_FAIL;
5003 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
5009 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
5011 - yaffs_ExtendedTags *tags,
5018 - yaffs_InvalidateCheckpoint(dev);
5021 - yaffs_BlockInfo *bi = 0;
5024 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5030 - /* First check this chunk is erased, if it needs
5031 - * checking. The checking policy (unless forced
5032 - * always on) is as follows:
5034 - * Check the first page we try to write in a block.
5035 - * If the check passes then we don't need to check any
5036 - * more. If the check fails, we check again...
5037 - * If the block has been erased, we don't need to check.
5039 - * However, if the block has been prioritised for gc,
5040 - * then we think there might be something odd about
5041 - * this block and stop using it.
5043 - * Rationale: We should only ever see chunks that have
5044 - * not been erased if there was a partially written
5045 - * chunk due to power loss. This checking policy should
5046 - * catch that case with very few checks and thus save a
5047 - * lot of checks that are most likely not needed.
5049 - if (bi->gcPrioritise) {
5050 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5051 - /* try another chunk */
5055 - /* let's give it a try */
5058 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5059 - bi->skipErasedCheck = 0;
5061 - if (!bi->skipErasedCheck) {
5062 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5063 - if (erasedOk != YAFFS_OK) {
5064 - T(YAFFS_TRACE_ERROR,
5065 - (TSTR("**>> yaffs chunk %d was not erased"
5066 - TENDSTR), chunk));
5068 - /* try another chunk */
5071 - bi->skipErasedCheck = 1;
5074 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5076 - if (writeOk != YAFFS_OK) {
5077 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5078 - /* try another chunk */
5082 - /* Copy the data into the robustification buffer */
5083 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5085 - } while (writeOk != YAFFS_OK &&
5086 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5091 - if (attempts > 1) {
5092 - T(YAFFS_TRACE_ERROR,
5093 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5096 - dev->nRetriedWrites += (attempts - 1);
5103 - * Block retiring for handling a broken block.
5106 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5108 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5110 - yaffs_InvalidateCheckpoint(dev);
5112 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5113 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5114 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5115 - "yaffs: Failed to mark bad and erase block %d"
5116 - TENDSTR), blockInNAND));
5118 - yaffs_ExtendedTags tags;
5119 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5121 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5123 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5124 - yaffs_InitialiseTags(&tags);
5125 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5126 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5127 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5128 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5129 - TCONT("write bad block marker to block %d")
5130 - TENDSTR), blockInNAND));
5132 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5136 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5137 - bi->gcPrioritise = 0;
5138 - bi->needsRetiring = 0;
5140 - dev->nRetiredBlocks++;
5144 - * Functions for robustisizing TODO
5148 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5150 - const yaffs_ExtendedTags *tags)
5154 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5155 - const yaffs_ExtendedTags *tags)
5159 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5161 - if (!bi->gcPrioritise) {
5162 - bi->gcPrioritise = 1;
5163 - dev->hasPendingPrioritisedGCs = 1;
5164 - bi->chunkErrorStrikes++;
5166 - if (bi->chunkErrorStrikes > 3) {
5167 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5168 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5174 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5177 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5178 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5180 - yaffs_HandleChunkError(dev, bi);
5183 - /* Was an actual write failure, so mark the block for retirement */
5184 - bi->needsRetiring = 1;
5185 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5186 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5189 - /* Delete the chunk */
5190 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5194 -/*---------------- Name handling functions ------------*/
5196 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5201 - const YUCHAR *bname = (const YUCHAR *) name;
5203 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5205 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5206 - sum += yaffs_toupper(*bname) * i;
5208 - sum += (*bname) * i;
5217 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
5219 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5220 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5221 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
5222 - yaffs_strcpy(obj->shortName, name);
5224 - obj->shortName[0] = _Y('\0');
5226 - obj->sum = yaffs_CalcNameSum(name);
5229 -/*-------------------- TNODES -------------------
5231 - * List of spare tnodes
5232 - * The list is hooked together using the first pointer
5236 -/* yaffs_CreateTnodes creates a bunch more tnodes and
5237 - * adds them to the tnode free list.
5238 - * Don't use this function directly
5241 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
5245 - yaffs_Tnode *newTnodes;
5247 - yaffs_Tnode *curr;
5248 - yaffs_Tnode *next;
5249 - yaffs_TnodeList *tnl;
5254 - /* Calculate the tnode size in bytes for variable width tnode support.
5255 - * Must be a multiple of 32-bits */
5256 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5258 - if (tnodeSize < sizeof(yaffs_Tnode))
5259 - tnodeSize = sizeof(yaffs_Tnode);
5261 - /* make these things */
5263 - newTnodes = YMALLOC(nTnodes * tnodeSize);
5264 - mem = (__u8 *)newTnodes;
5267 - T(YAFFS_TRACE_ERROR,
5268 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
5269 - return YAFFS_FAIL;
5272 - /* Hook them into the free list */
5274 - for (i = 0; i < nTnodes - 1; i++) {
5275 - newTnodes[i].internal[0] = &newTnodes[i + 1];
5276 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5277 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5281 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
5282 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5283 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5285 - dev->freeTnodes = newTnodes;
5287 - /* New hookup for wide tnodes */
5288 - for (i = 0; i < nTnodes - 1; i++) {
5289 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
5290 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
5291 - curr->internal[0] = next;
5294 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
5295 - curr->internal[0] = dev->freeTnodes;
5296 - dev->freeTnodes = (yaffs_Tnode *)mem;
5301 - dev->nFreeTnodes += nTnodes;
5302 - dev->nTnodesCreated += nTnodes;
5304 - /* Now add this bunch of tnodes to a list for freeing up.
5305 - * NB If we can't add this to the management list it isn't fatal
5306 - * but it just means we can't free this bunch of tnodes later.
5309 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
5311 - T(YAFFS_TRACE_ERROR,
5313 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
5314 - return YAFFS_FAIL;
5316 - tnl->tnodes = newTnodes;
5317 - tnl->next = dev->allocatedTnodeList;
5318 - dev->allocatedTnodeList = tnl;
5321 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
5326 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
5328 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
5330 - yaffs_Tnode *tn = NULL;
5332 - /* If there are none left make more */
5333 - if (!dev->freeTnodes)
5334 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
5336 - if (dev->freeTnodes) {
5337 - tn = dev->freeTnodes;
5338 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5339 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
5340 - /* Hoosterman, this thing looks like it isn't in the list */
5341 - T(YAFFS_TRACE_ALWAYS,
5342 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
5345 - dev->freeTnodes = dev->freeTnodes->internal[0];
5346 - dev->nFreeTnodes--;
5349 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5354 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
5356 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
5357 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5359 - if (tnodeSize < sizeof(yaffs_Tnode))
5360 - tnodeSize = sizeof(yaffs_Tnode);
5363 - memset(tn, 0, tnodeSize);
5368 -/* FreeTnode frees up a tnode and puts it back on the free list */
5369 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
5372 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5373 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
5374 - /* Hoosterman, this thing looks like it is already in the list */
5375 - T(YAFFS_TRACE_ALWAYS,
5376 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
5378 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5380 - tn->internal[0] = dev->freeTnodes;
5381 - dev->freeTnodes = tn;
5382 - dev->nFreeTnodes++;
5384 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5387 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
5389 - /* Free the list of allocated tnodes */
5390 - yaffs_TnodeList *tmp;
5392 - while (dev->allocatedTnodeList) {
5393 - tmp = dev->allocatedTnodeList->next;
5395 - YFREE(dev->allocatedTnodeList->tnodes);
5396 - YFREE(dev->allocatedTnodeList);
5397 - dev->allocatedTnodeList = tmp;
5401 - dev->freeTnodes = NULL;
5402 - dev->nFreeTnodes = 0;
5405 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
5407 - dev->allocatedTnodeList = NULL;
5408 - dev->freeTnodes = NULL;
5409 - dev->nFreeTnodes = 0;
5410 - dev->nTnodesCreated = 0;
5414 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
5417 - __u32 *map = (__u32 *)tn;
5423 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5424 - val >>= dev->chunkGroupBits;
5426 - bitInMap = pos * dev->tnodeWidth;
5427 - wordInMap = bitInMap / 32;
5428 - bitInWord = bitInMap & (32 - 1);
5430 - mask = dev->tnodeMask << bitInWord;
5432 - map[wordInMap] &= ~mask;
5433 - map[wordInMap] |= (mask & (val << bitInWord));
5435 - if (dev->tnodeWidth > (32 - bitInWord)) {
5436 - bitInWord = (32 - bitInWord);
5438 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
5439 - map[wordInMap] &= ~mask;
5440 - map[wordInMap] |= (mask & (val >> bitInWord));
5444 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
5447 - __u32 *map = (__u32 *)tn;
5453 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5455 - bitInMap = pos * dev->tnodeWidth;
5456 - wordInMap = bitInMap / 32;
5457 - bitInWord = bitInMap & (32 - 1);
5459 - val = map[wordInMap] >> bitInWord;
5461 - if (dev->tnodeWidth > (32 - bitInWord)) {
5462 - bitInWord = (32 - bitInWord);
5464 - val |= (map[wordInMap] << bitInWord);
5467 - val &= dev->tnodeMask;
5468 - val <<= dev->chunkGroupBits;
5473 -/* ------------------- End of individual tnode manipulation -----------------*/
5475 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5476 - * The look up tree is represented by the top tnode and the number of topLevel
5477 - * in the tree. 0 means only the level 0 tnode is in the tree.
5480 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5481 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
5482 - yaffs_FileStructure *fStruct,
5485 - yaffs_Tnode *tn = fStruct->top;
5487 - int requiredTallness;
5488 - int level = fStruct->topLevel;
5490 - /* Check sane level and chunk Id */
5491 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5494 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5497 - /* First check we're tall enough (ie enough topLevel) */
5499 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5500 - requiredTallness = 0;
5502 - i >>= YAFFS_TNODES_INTERNAL_BITS;
5503 - requiredTallness++;
5506 - if (requiredTallness > fStruct->topLevel)
5507 - return NULL; /* Not tall enough, so we can't find it */
5509 - /* Traverse down to level 0 */
5510 - while (level > 0 && tn) {
5511 - tn = tn->internal[(chunkId >>
5512 - (YAFFS_TNODES_LEVEL0_BITS +
5514 - YAFFS_TNODES_INTERNAL_BITS)) &
5515 - YAFFS_TNODES_INTERNAL_MASK];
5522 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5523 - * This happens in two steps:
5524 - * 1. If the tree isn't tall enough, then make it taller.
5525 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5527 - * Used when modifying the tree.
5529 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5530 - * be plugged into the ttree.
5533 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
5534 - yaffs_FileStructure *fStruct,
5536 - yaffs_Tnode *passedTn)
5538 - int requiredTallness;
5546 - /* Check sane level and page Id */
5547 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
5550 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5553 - /* First check we're tall enough (ie enough topLevel) */
5555 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5556 - requiredTallness = 0;
5558 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5559 - requiredTallness++;
5563 - if (requiredTallness > fStruct->topLevel) {
5564 - /* Not tall enough, gotta make the tree taller */
5565 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
5567 - tn = yaffs_GetTnode(dev);
5570 - tn->internal[0] = fStruct->top;
5571 - fStruct->top = tn;
5573 - T(YAFFS_TRACE_ERROR,
5574 - (TSTR("yaffs: no more tnodes" TENDSTR)));
5578 - fStruct->topLevel = requiredTallness;
5581 - /* Traverse down to level 0, adding anything we need */
5583 - l = fStruct->topLevel;
5584 - tn = fStruct->top;
5587 - while (l > 0 && tn) {
5589 - (YAFFS_TNODES_LEVEL0_BITS +
5590 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5591 - YAFFS_TNODES_INTERNAL_MASK;
5594 - if ((l > 1) && !tn->internal[x]) {
5595 - /* Add missing non-level-zero tnode */
5596 - tn->internal[x] = yaffs_GetTnode(dev);
5598 - } else if (l == 1) {
5599 - /* Looking from level 1 at level 0 */
5601 - /* If we already have one, then release it.*/
5602 - if (tn->internal[x])
5603 - yaffs_FreeTnode(dev, tn->internal[x]);
5604 - tn->internal[x] = passedTn;
5606 - } else if (!tn->internal[x]) {
5607 - /* Don't have one, none passed in */
5608 - tn->internal[x] = yaffs_GetTnode(dev);
5612 - tn = tn->internal[x];
5616 - /* top is level 0 */
5618 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
5619 - yaffs_FreeTnode(dev, passedTn);
5626 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
5627 - yaffs_ExtendedTags *tags, int objectId,
5632 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
5633 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
5634 - theChunk % dev->nChunksPerBlock)) {
5635 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
5637 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
5648 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
5649 - * chunks and tnodes in the file
5650 - * Returns 1 if the tree was deleted.
5651 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5654 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
5655 - int chunkOffset, int *limit)
5660 - yaffs_ExtendedTags tags;
5662 - yaffs_Device *dev = in->myDev;
5668 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5670 - if (tn->internal[i]) {
5671 - if (limit && (*limit) < 0) {
5675 - yaffs_DeleteWorker(in,
5683 - YAFFS_TNODES_INTERNAL_BITS)
5688 - yaffs_FreeTnode(dev,
5691 - tn->internal[i] = NULL;
5695 - return (allDone) ? 1 : 0;
5696 - } else if (level == 0) {
5699 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5701 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5704 - chunkInInode = (chunkOffset <<
5705 - YAFFS_TNODES_LEVEL0_BITS) + i;
5708 - yaffs_FindChunkInGroup(dev,
5714 - if (foundChunk > 0) {
5715 - yaffs_DeleteChunk(dev,
5718 - in->nDataChunks--;
5720 - *limit = *limit - 1;
5727 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5731 - return (i < 0) ? 1 : 0;
5741 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
5743 - yaffs_BlockInfo *theBlock;
5745 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5747 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
5749 - theBlock->softDeletions++;
5750 - dev->nFreeChunks++;
5754 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5755 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5757 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5760 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
5761 - __u32 level, int chunkOffset)
5766 - yaffs_Device *dev = in->myDev;
5771 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5773 - if (tn->internal[i]) {
5775 - yaffs_SoftDeleteWorker(in,
5781 - YAFFS_TNODES_INTERNAL_BITS)
5784 - yaffs_FreeTnode(dev,
5787 - tn->internal[i] = NULL;
5789 - /* Hoosterman... how could this happen? */
5793 - return (allDone) ? 1 : 0;
5794 - } else if (level == 0) {
5796 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
5797 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5799 - /* Note this does not find the real chunk, only the chunk group.
5800 - * We make an assumption that a chunk group is not larger than
5803 - yaffs_SoftDeleteChunk(dev, theChunk);
5804 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5818 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
5820 - if (obj->deleted &&
5821 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
5822 - if (obj->nDataChunks <= 0) {
5823 - /* Empty file with no duplicate object headers, just delete it immediately */
5824 - yaffs_FreeTnode(obj->myDev,
5825 - obj->variant.fileVariant.top);
5826 - obj->variant.fileVariant.top = NULL;
5827 - T(YAFFS_TRACE_TRACING,
5828 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
5830 - yaffs_DoGenericObjectDeletion(obj);
5832 - yaffs_SoftDeleteWorker(obj,
5833 - obj->variant.fileVariant.top,
5834 - obj->variant.fileVariant.
5836 - obj->softDeleted = 1;
5841 -/* Pruning removes any part of the file structure tree that is beyond the
5842 - * bounds of the file (ie that does not point to chunks).
5844 - * A file should only get pruned when its size is reduced.
5846 - * Before pruning, the chunks must be pulled from the tree and the
5847 - * level 0 tnode entries must be zeroed out.
5848 - * Could also use this for file deletion, but that's probably better handled
5849 - * by a special case.
5852 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
5853 - __u32 level, int del0)
5861 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
5862 - if (tn->internal[i] && level > 0) {
5864 - yaffs_PruneWorker(dev, tn->internal[i],
5866 - (i == 0) ? del0 : 1);
5869 - if (tn->internal[i])
5873 - if (hasData == 0 && del0) {
5874 - /* Free and return NULL */
5876 - yaffs_FreeTnode(dev, tn);
5886 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
5887 - yaffs_FileStructure *fStruct)
5894 - if (fStruct->topLevel > 0) {
5896 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
5898 - /* Now we have a tree with all the non-zero branches NULL but the height
5899 - * is the same as it was.
5900 - * Let's see if we can trim internal tnodes to shorten the tree.
5901 - * We can do this if only the 0th element in the tnode is in use
5902 - * (ie all the non-zero are NULL)
5905 - while (fStruct->topLevel && !done) {
5906 - tn = fStruct->top;
5909 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
5910 - if (tn->internal[i])
5915 - fStruct->top = tn->internal[0];
5916 - fStruct->topLevel--;
5917 - yaffs_FreeTnode(dev, tn);
5927 -/*-------------------- End of File Structure functions.-------------------*/
5929 -/* yaffs_CreateFreeObjects creates a bunch more objects and
5930 - * adds them to the object free list.
5932 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
5935 - yaffs_Object *newObjects;
5936 - yaffs_ObjectList *list;
5941 - /* make these things */
5942 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
5943 - list = YMALLOC(sizeof(yaffs_ObjectList));
5945 - if (!newObjects || !list) {
5947 - YFREE(newObjects);
5950 - T(YAFFS_TRACE_ALLOCATE,
5951 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
5952 - return YAFFS_FAIL;
5955 - /* Hook them into the free list */
5956 - for (i = 0; i < nObjects - 1; i++) {
5957 - newObjects[i].siblings.next =
5958 - (struct ylist_head *)(&newObjects[i + 1]);
5961 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
5962 - dev->freeObjects = newObjects;
5963 - dev->nFreeObjects += nObjects;
5964 - dev->nObjectsCreated += nObjects;
5966 - /* Now add this bunch of Objects to a list for freeing up. */
5968 - list->objects = newObjects;
5969 - list->next = dev->allocatedObjectList;
5970 - dev->allocatedObjectList = list;
5976 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
5977 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
5979 - yaffs_Object *tn = NULL;
5981 -#ifdef VALGRIND_TEST
5982 - tn = YMALLOC(sizeof(yaffs_Object));
5984 - /* If there are none left make more */
5985 - if (!dev->freeObjects)
5986 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
5988 - if (dev->freeObjects) {
5989 - tn = dev->freeObjects;
5990 - dev->freeObjects =
5991 - (yaffs_Object *) (dev->freeObjects->siblings.next);
5992 - dev->nFreeObjects--;
5996 - /* Now sweeten it up... */
5998 - memset(tn, 0, sizeof(yaffs_Object));
5999 - tn->beingCreated = 1;
6003 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
6004 - YINIT_LIST_HEAD(&(tn->hardLinks));
6005 - YINIT_LIST_HEAD(&(tn->hashLink));
6006 - YINIT_LIST_HEAD(&tn->siblings);
6009 - /* Now make the directory sane */
6010 - if (dev->rootDir) {
6011 - tn->parent = dev->rootDir;
6012 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
6015 - /* Add it to the lost and found directory.
6016 - * NB Can't put root or lostNFound in lostNFound so
6017 - * check if lostNFound exists first
6019 - if (dev->lostNFoundDir)
6020 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
6022 - tn->beingCreated = 0;
6025 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6030 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
6034 - yaffs_Object *obj =
6035 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6037 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
6038 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
6039 - obj->unlinkAllowed = 0; /* ... or unlink it */
6041 - obj->unlinked = 0;
6042 - obj->yst_mode = mode;
6044 - obj->hdrChunk = 0; /* Not a valid chunk. */
6051 -static void yaffs_UnhashObject(yaffs_Object *tn)
6054 - yaffs_Device *dev = tn->myDev;
6056 - /* If it is still linked into the bucket list, free from the list */
6057 - if (!ylist_empty(&tn->hashLink)) {
6058 - ylist_del_init(&tn->hashLink);
6059 - bucket = yaffs_HashFunction(tn->objectId);
6060 - dev->objectBucket[bucket].count--;
6064 -/* FreeObject frees up a Object and puts it back on the free list */
6065 -static void yaffs_FreeObject(yaffs_Object *tn)
6067 - yaffs_Device *dev = tn->myDev;
6070 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
6075 - if (!ylist_empty(&tn->siblings))
6080 - if (tn->myInode) {
6081 - /* We're still hooked up to a cached inode.
6082 - * Don't delete now, but mark for later deletion
6084 - tn->deferedFree = 1;
6089 - yaffs_UnhashObject(tn);
6091 -#ifdef VALGRIND_TEST
6094 - /* Link into the free list. */
6095 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
6096 - dev->freeObjects = tn;
6097 - dev->nFreeObjects++;
6099 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6104 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
6106 - if (obj->deferedFree)
6107 - yaffs_FreeObject(obj);
6112 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
6114 - /* Free the list of allocated Objects */
6116 - yaffs_ObjectList *tmp;
6118 - while (dev->allocatedObjectList) {
6119 - tmp = dev->allocatedObjectList->next;
6120 - YFREE(dev->allocatedObjectList->objects);
6121 - YFREE(dev->allocatedObjectList);
6123 - dev->allocatedObjectList = tmp;
6126 - dev->freeObjects = NULL;
6127 - dev->nFreeObjects = 0;
6130 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
6134 - dev->allocatedObjectList = NULL;
6135 - dev->freeObjects = NULL;
6136 - dev->nFreeObjects = 0;
6138 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6139 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
6140 - dev->objectBucket[i].count = 0;
6144 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
6149 - int lowest = 999999;
6151 - /* First let's see if we can find one that's empty. */
6153 - for (i = 0; i < 10 && lowest > 0; i++) {
6155 - x %= YAFFS_NOBJECT_BUCKETS;
6156 - if (dev->objectBucket[x].count < lowest) {
6157 - lowest = dev->objectBucket[x].count;
6163 - /* If we didn't find an empty list, then try
6164 - * looking a bit further for a short one
6167 - for (i = 0; i < 10 && lowest > 3; i++) {
6169 - x %= YAFFS_NOBJECT_BUCKETS;
6170 - if (dev->objectBucket[x].count < lowest) {
6171 - lowest = dev->objectBucket[x].count;
6180 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
6182 - int bucket = yaffs_FindNiceObjectBucket(dev);
6184 - /* Now find an object value that has not already been taken
6185 - * by scanning the list.
6189 - struct ylist_head *i;
6191 - __u32 n = (__u32) bucket;
6193 - /* yaffs_CheckObjectHashSanity(); */
6197 - n += YAFFS_NOBJECT_BUCKETS;
6198 - if (1 || dev->objectBucket[bucket].count > 0) {
6199 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6200 - /* If there is already one in the list */
6201 - if (i && ylist_entry(i, yaffs_Object,
6202 - hashLink)->objectId == n) {
6212 -static void yaffs_HashObject(yaffs_Object *in)
6214 - int bucket = yaffs_HashFunction(in->objectId);
6215 - yaffs_Device *dev = in->myDev;
6217 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
6218 - dev->objectBucket[bucket].count++;
6221 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
6223 - int bucket = yaffs_HashFunction(number);
6224 - struct ylist_head *i;
6227 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6228 - /* Look if it is in the list */
6230 - in = ylist_entry(i, yaffs_Object, hashLink);
6231 - if (in->objectId == number) {
6233 - /* Don't tell the VFS about this one if it is defered free */
6234 - if (in->deferedFree)
6246 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
6247 - yaffs_ObjectType type)
6249 - yaffs_Object *theObject;
6250 - yaffs_Tnode *tn = NULL;
6253 - number = yaffs_CreateNewObjectNumber(dev);
6255 - theObject = yaffs_AllocateEmptyObject(dev);
6259 - if (type == YAFFS_OBJECT_TYPE_FILE) {
6260 - tn = yaffs_GetTnode(dev);
6262 - yaffs_FreeObject(theObject);
6268 - theObject->fake = 0;
6269 - theObject->renameAllowed = 1;
6270 - theObject->unlinkAllowed = 1;
6271 - theObject->objectId = number;
6272 - yaffs_HashObject(theObject);
6273 - theObject->variantType = type;
6274 -#ifdef CONFIG_YAFFS_WINCE
6275 - yfsd_WinFileTimeNow(theObject->win_atime);
6276 - theObject->win_ctime[0] = theObject->win_mtime[0] =
6277 - theObject->win_atime[0];
6278 - theObject->win_ctime[1] = theObject->win_mtime[1] =
6279 - theObject->win_atime[1];
6283 - theObject->yst_atime = theObject->yst_mtime =
6284 - theObject->yst_ctime = Y_CURRENT_TIME;
6287 - case YAFFS_OBJECT_TYPE_FILE:
6288 - theObject->variant.fileVariant.fileSize = 0;
6289 - theObject->variant.fileVariant.scannedFileSize = 0;
6290 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
6291 - theObject->variant.fileVariant.topLevel = 0;
6292 - theObject->variant.fileVariant.top = tn;
6294 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6295 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
6298 - case YAFFS_OBJECT_TYPE_SYMLINK:
6299 - case YAFFS_OBJECT_TYPE_HARDLINK:
6300 - case YAFFS_OBJECT_TYPE_SPECIAL:
6301 - /* No action required */
6303 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6304 - /* todo this should not happen */
6312 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
6314 - yaffs_ObjectType type)
6316 - yaffs_Object *theObject = NULL;
6319 - theObject = yaffs_FindObjectByNumber(dev, number);
6322 - theObject = yaffs_CreateNewObject(dev, number, type);
6329 -static YCHAR *yaffs_CloneString(const YCHAR *str)
6331 - YCHAR *newStr = NULL;
6333 - if (str && *str) {
6334 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
6336 - yaffs_strcpy(newStr, str);
6344 - * Mknod (create) a new object.
6345 - * equivalentObject only has meaning for a hard link;
6346 - * aliasString only has meaning for a sumlink.
6347 - * rdev only has meaning for devices (a subset of special objects)
6350 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
6351 - yaffs_Object *parent,
6352 - const YCHAR *name,
6356 - yaffs_Object *equivalentObject,
6357 - const YCHAR *aliasString, __u32 rdev)
6360 - YCHAR *str = NULL;
6362 - yaffs_Device *dev = parent->myDev;
6364 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
6365 - if (yaffs_FindObjectByName(parent, name))
6368 - in = yaffs_CreateNewObject(dev, -1, type);
6371 - return YAFFS_FAIL;
6373 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
6374 - str = yaffs_CloneString(aliasString);
6376 - yaffs_FreeObject(in);
6386 - in->variantType = type;
6388 - in->yst_mode = mode;
6390 -#ifdef CONFIG_YAFFS_WINCE
6391 - yfsd_WinFileTimeNow(in->win_atime);
6392 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
6393 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
6396 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
6398 - in->yst_rdev = rdev;
6399 - in->yst_uid = uid;
6400 - in->yst_gid = gid;
6402 - in->nDataChunks = 0;
6404 - yaffs_SetObjectName(in, name);
6407 - yaffs_AddObjectToDirectory(parent, in);
6409 - in->myDev = parent->myDev;
6412 - case YAFFS_OBJECT_TYPE_SYMLINK:
6413 - in->variant.symLinkVariant.alias = str;
6415 - case YAFFS_OBJECT_TYPE_HARDLINK:
6416 - in->variant.hardLinkVariant.equivalentObject =
6418 - in->variant.hardLinkVariant.equivalentObjectId =
6419 - equivalentObject->objectId;
6420 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
6422 - case YAFFS_OBJECT_TYPE_FILE:
6423 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6424 - case YAFFS_OBJECT_TYPE_SPECIAL:
6425 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6430 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
6431 - /* Could not create the object header, fail the creation */
6432 - yaffs_DeleteObject(in);
6441 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
6442 - __u32 mode, __u32 uid, __u32 gid)
6444 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
6445 - uid, gid, NULL, NULL, 0);
6448 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
6449 - __u32 mode, __u32 uid, __u32 gid)
6451 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
6452 - mode, uid, gid, NULL, NULL, 0);
6455 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
6456 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
6458 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
6459 - uid, gid, NULL, NULL, rdev);
6462 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
6463 - __u32 mode, __u32 uid, __u32 gid,
6464 - const YCHAR *alias)
6466 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
6467 - uid, gid, NULL, alias, 0);
6470 -/* yaffs_Link returns the object id of the equivalent object.*/
6471 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
6472 - yaffs_Object *equivalentObject)
6474 - /* Get the real object in case we were fed a hard link as an equivalent object */
6475 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
6477 - if (yaffs_MknodObject
6478 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
6479 - equivalentObject, NULL, 0)) {
6480 - return equivalentObject;
6487 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
6488 - const YCHAR *newName, int force, int shadows)
6493 - yaffs_Object *existingTarget;
6495 - if (newDir == NULL)
6496 - newDir = obj->parent; /* use the old directory */
6498 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6499 - T(YAFFS_TRACE_ALWAYS,
6501 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
6506 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
6507 - if (obj->myDev->isYaffs2)
6508 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
6510 - unlinkOp = (newDir == obj->myDev->unlinkedDir
6511 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
6513 - deleteOp = (newDir == obj->myDev->deletedDir);
6515 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6517 - /* If the object is a file going into the unlinked directory,
6518 - * then it is OK to just stuff it in since duplicate names are allowed.
6519 - * else only proceed if the new name does not exist and if we're putting
6520 - * it into a directory.
6526 - !existingTarget) &&
6527 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
6528 - yaffs_SetObjectName(obj, newName);
6531 - yaffs_AddObjectToDirectory(newDir, obj);
6534 - obj->unlinked = 1;
6536 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
6537 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
6541 - return YAFFS_FAIL;
6544 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
6545 - yaffs_Object *newDir, const YCHAR *newName)
6547 - yaffs_Object *obj = NULL;
6548 - yaffs_Object *existingTarget = NULL;
6552 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6554 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6557 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6558 - /* Special case for case insemsitive systems (eg. WinCE).
6559 - * While look-up is case insensitive, the name isn't.
6560 - * Therefore we might want to change x.txt to X.txt
6562 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
6566 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
6567 - /* ENAMETOOLONG */
6568 - return YAFFS_FAIL;
6570 - obj = yaffs_FindObjectByName(oldDir, oldName);
6572 - if (obj && obj->renameAllowed) {
6574 - /* Now do the handling for an existing target, if there is one */
6576 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6577 - if (existingTarget &&
6578 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
6579 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
6580 - /* There is a target that is a non-empty directory, so we fail */
6581 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
6582 - } else if (existingTarget && existingTarget != obj) {
6583 - /* Nuke the target first, using shadowing,
6584 - * but only if it isn't the same object
6586 - yaffs_ChangeObjectName(obj, newDir, newName, force,
6587 - existingTarget->objectId);
6588 - yaffs_UnlinkObject(existingTarget);
6591 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
6593 - return YAFFS_FAIL;
6596 -/*------------------------- Block Management and Page Allocation ----------------*/
6598 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
6600 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6602 - dev->blockInfo = NULL;
6603 - dev->chunkBits = NULL;
6605 - dev->allocationBlock = -1; /* force it to get a new one */
6607 - /* If the first allocation strategy fails, thry the alternate one */
6608 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
6609 - if (!dev->blockInfo) {
6610 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
6611 - dev->blockInfoAlt = 1;
6613 - dev->blockInfoAlt = 0;
6615 - if (dev->blockInfo) {
6616 - /* Set up dynamic blockinfo stuff. */
6617 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
6618 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
6619 - if (!dev->chunkBits) {
6620 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
6621 - dev->chunkBitsAlt = 1;
6623 - dev->chunkBitsAlt = 0;
6626 - if (dev->blockInfo && dev->chunkBits) {
6627 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
6628 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
6632 - return YAFFS_FAIL;
6635 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
6637 - if (dev->blockInfoAlt && dev->blockInfo)
6638 - YFREE_ALT(dev->blockInfo);
6639 - else if (dev->blockInfo)
6640 - YFREE(dev->blockInfo);
6642 - dev->blockInfoAlt = 0;
6644 - dev->blockInfo = NULL;
6646 - if (dev->chunkBitsAlt && dev->chunkBits)
6647 - YFREE_ALT(dev->chunkBits);
6648 - else if (dev->chunkBits)
6649 - YFREE(dev->chunkBits);
6650 - dev->chunkBitsAlt = 0;
6651 - dev->chunkBits = NULL;
6654 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
6655 - yaffs_BlockInfo *bi)
6659 - yaffs_BlockInfo *b;
6661 - if (!dev->isYaffs2)
6662 - return 1; /* disqualification only applies to yaffs2. */
6664 - if (!bi->hasShrinkHeader)
6665 - return 1; /* can gc */
6667 - /* Find the oldest dirty sequence number if we don't know it and save it
6668 - * so we don't have to keep recomputing it.
6670 - if (!dev->oldestDirtySequence) {
6671 - seq = dev->sequenceNumber;
6673 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
6675 - b = yaffs_GetBlockInfo(dev, i);
6676 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
6677 - (b->pagesInUse - b->softDeletions) <
6678 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
6679 - seq = b->sequenceNumber;
6682 - dev->oldestDirtySequence = seq;
6685 - /* Can't do gc of this block if there are any blocks older than this one that have
6686 - * discarded pages.
6688 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
6691 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
6692 - * for garbage collection.
6695 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
6698 - int b = dev->currentDirtyChecker;
6702 - int dirtiest = -1;
6703 - int pagesInUse = 0;
6704 - int prioritised = 0;
6705 - yaffs_BlockInfo *bi;
6706 - int pendingPrioritisedExist = 0;
6708 - /* First let's see if we need to grab a prioritised block */
6709 - if (dev->hasPendingPrioritisedGCs) {
6710 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
6712 - bi = yaffs_GetBlockInfo(dev, i);
6713 - /* yaffs_VerifyBlock(dev,bi,i); */
6715 - if (bi->gcPrioritise) {
6716 - pendingPrioritisedExist = 1;
6717 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6718 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6719 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6722 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
6727 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
6728 - dev->hasPendingPrioritisedGCs = 0;
6731 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
6733 - * else (we're doing a leasurely gc), then we only bother to do this if the
6734 - * block has only a few pages in use.
6737 - dev->nonAggressiveSkip--;
6739 - if (!aggressive && (dev->nonAggressiveSkip > 0))
6744 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
6748 - dev->internalEndBlock - dev->internalStartBlock + 1;
6751 - dev->internalEndBlock - dev->internalStartBlock + 1;
6752 - iterations = iterations / 16;
6753 - if (iterations > 200)
6757 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
6759 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
6760 - b = dev->internalStartBlock;
6762 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
6763 - T(YAFFS_TRACE_ERROR,
6764 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
6768 - bi = yaffs_GetBlockInfo(dev, b);
6770 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6771 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
6772 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6774 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6778 - dev->currentDirtyChecker = b;
6780 - if (dirtiest > 0) {
6782 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
6783 - dev->nChunksPerBlock - pagesInUse, prioritised));
6786 - dev->oldestDirtySequence = 0;
6789 - dev->nonAggressiveSkip = 4;
6794 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
6796 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
6800 - /* If the block is still healthy erase it and mark as clean.
6801 - * If the block has had a data failure, then retire it.
6804 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
6805 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
6806 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
6808 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
6810 - if (!bi->needsRetiring) {
6811 - yaffs_InvalidateCheckpoint(dev);
6812 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
6814 - dev->nErasureFailures++;
6815 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6816 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
6821 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
6823 - for (i = 0; i < dev->nChunksPerBlock; i++) {
6824 - if (!yaffs_CheckChunkErased
6825 - (dev, blockNo * dev->nChunksPerBlock + i)) {
6826 - T(YAFFS_TRACE_ERROR,
6828 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
6829 - TENDSTR), blockNo, i));
6835 - /* Clean it up... */
6836 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
6837 - dev->nErasedBlocks++;
6838 - bi->pagesInUse = 0;
6839 - bi->softDeletions = 0;
6840 - bi->hasShrinkHeader = 0;
6841 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
6842 - bi->gcPrioritise = 0;
6843 - yaffs_ClearChunkBits(dev, blockNo);
6845 - T(YAFFS_TRACE_ERASE,
6846 - (TSTR("Erased block %d" TENDSTR), blockNo));
6848 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
6850 - yaffs_RetireBlock(dev, blockNo);
6851 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6852 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
6856 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
6860 - yaffs_BlockInfo *bi;
6862 - if (dev->nErasedBlocks < 1) {
6863 - /* Hoosterman we've got a problem.
6864 - * Can't get space to gc
6866 - T(YAFFS_TRACE_ERROR,
6867 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
6872 - /* Find an empty block. */
6874 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
6875 - dev->allocationBlockFinder++;
6876 - if (dev->allocationBlockFinder < dev->internalStartBlock
6877 - || dev->allocationBlockFinder > dev->internalEndBlock) {
6878 - dev->allocationBlockFinder = dev->internalStartBlock;
6881 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
6883 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
6884 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
6885 - dev->sequenceNumber++;
6886 - bi->sequenceNumber = dev->sequenceNumber;
6887 - dev->nErasedBlocks--;
6888 - T(YAFFS_TRACE_ALLOCATE,
6889 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
6890 - dev->allocationBlockFinder, dev->sequenceNumber,
6891 - dev->nErasedBlocks));
6892 - return dev->allocationBlockFinder;
6896 - T(YAFFS_TRACE_ALWAYS,
6898 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
6899 - TENDSTR), dev->nErasedBlocks));
6906 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
6908 - if (!dev->nCheckpointBlocksRequired &&
6910 - /* Not a valid value so recalculate */
6913 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
6916 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6918 - if (tnodeSize < sizeof(yaffs_Tnode))
6919 - tnodeSize = sizeof(yaffs_Tnode);
6921 - nBytes += sizeof(yaffs_CheckpointValidity);
6922 - nBytes += sizeof(yaffs_CheckpointDevice);
6923 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
6924 - nBytes += devBlocks * dev->chunkBitmapStride;
6925 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
6926 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
6927 - nBytes += sizeof(yaffs_CheckpointValidity);
6928 - nBytes += sizeof(__u32); /* checksum*/
6930 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
6932 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
6934 - dev->nCheckpointBlocksRequired = nBlocks;
6937 - return dev->nCheckpointBlocksRequired;
6941 - * Check if there's space to allocate...
6942 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
6944 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
6946 - int reservedChunks;
6947 - int reservedBlocks = dev->nReservedBlocks;
6948 - int checkpointBlocks;
6950 - if (dev->isYaffs2) {
6951 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
6952 - dev->blocksInCheckpoint;
6953 - if (checkpointBlocks < 0)
6954 - checkpointBlocks = 0;
6956 - checkpointBlocks = 0;
6959 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
6961 - return (dev->nFreeChunks > reservedChunks);
6964 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
6965 - yaffs_BlockInfo **blockUsedPtr)
6968 - yaffs_BlockInfo *bi;
6970 - if (dev->allocationBlock < 0) {
6971 - /* Get next block to allocate off */
6972 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
6973 - dev->allocationPage = 0;
6976 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
6977 - /* Not enough space to allocate unless we're allowed to use the reserve. */
6981 - if (dev->nErasedBlocks < dev->nReservedBlocks
6982 - && dev->allocationPage == 0) {
6983 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
6986 - /* Next page please.... */
6987 - if (dev->allocationBlock >= 0) {
6988 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
6990 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
6991 - dev->allocationPage;
6993 - yaffs_SetChunkBit(dev, dev->allocationBlock,
6994 - dev->allocationPage);
6996 - dev->allocationPage++;
6998 - dev->nFreeChunks--;
7000 - /* If the block is full set the state to full */
7001 - if (dev->allocationPage >= dev->nChunksPerBlock) {
7002 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
7003 - dev->allocationBlock = -1;
7007 - *blockUsedPtr = bi;
7012 - T(YAFFS_TRACE_ERROR,
7013 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
7018 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
7022 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
7024 - if (dev->allocationBlock > 0)
7025 - n += (dev->nChunksPerBlock - dev->allocationPage);
7031 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
7037 - int retVal = YAFFS_OK;
7040 - int isCheckpointBlock;
7041 - int matchingChunk;
7044 - int chunksBefore = yaffs_GetErasedChunks(dev);
7047 - yaffs_ExtendedTags tags;
7049 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
7051 - yaffs_Object *object;
7053 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
7055 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
7057 - T(YAFFS_TRACE_TRACING,
7058 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
7061 - bi->hasShrinkHeader,
7064 - /*yaffs_VerifyFreeChunks(dev); */
7066 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
7068 - /* Take off the number of soft deleted entries because
7069 - * they're going to get really deleted during GC.
7071 - dev->nFreeChunks -= bi->softDeletions;
7073 - dev->isDoingGC = 1;
7075 - if (isCheckpointBlock ||
7076 - !yaffs_StillSomeChunkBits(dev, block)) {
7077 - T(YAFFS_TRACE_TRACING,
7079 - ("Collecting block %d that has no chunks in use" TENDSTR),
7081 - yaffs_BlockBecameDirty(dev, block);
7084 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
7086 - yaffs_VerifyBlock(dev, bi, block);
7088 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
7089 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
7091 - for (/* init already done */;
7092 - retVal == YAFFS_OK &&
7093 - dev->gcChunk < dev->nChunksPerBlock &&
7094 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
7096 - dev->gcChunk++, oldChunk++) {
7097 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
7099 - /* This page is in use and might need to be copied off */
7105 - yaffs_InitialiseTags(&tags);
7107 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
7111 - yaffs_FindObjectByNumber(dev,
7114 - T(YAFFS_TRACE_GC_DETAIL,
7116 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
7117 - dev->gcChunk, tags.objectId, tags.chunkId,
7120 - if (object && !yaffs_SkipVerification(dev)) {
7121 - if (tags.chunkId == 0)
7122 - matchingChunk = object->hdrChunk;
7123 - else if (object->softDeleted)
7124 - matchingChunk = oldChunk; /* Defeat the test */
7126 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
7128 - if (oldChunk != matchingChunk)
7129 - T(YAFFS_TRACE_ERROR,
7130 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
7131 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
7136 - T(YAFFS_TRACE_ERROR,
7138 - ("page %d in gc has no object: %d %d %d "
7139 - TENDSTR), oldChunk,
7140 - tags.objectId, tags.chunkId, tags.byteCount));
7144 - object->deleted &&
7145 - object->softDeleted &&
7146 - tags.chunkId != 0) {
7147 - /* Data chunk in a soft deleted file, throw it away
7148 - * It's a soft deleted data chunk,
7149 - * No need to copy this, just forget about it and
7150 - * fix up the object.
7153 - object->nDataChunks--;
7155 - if (object->nDataChunks <= 0) {
7156 - /* remeber to clean up the object */
7157 - dev->gcCleanupList[cleanups] =
7163 - /* Todo object && object->deleted && object->nDataChunks == 0 */
7164 - /* Deleted object header with no data chunks.
7165 - * Can be discarded and the file deleted.
7167 - object->hdrChunk = 0;
7168 - yaffs_FreeTnode(object->myDev,
7171 - object->variant.fileVariant.top = NULL;
7172 - yaffs_DoGenericObjectDeletion(object);
7174 - } else if (object) {
7175 - /* It's either a data chunk in a live file or
7176 - * an ObjectHeader, so we're interested in it.
7177 - * NB Need to keep the ObjectHeaders of deleted files
7178 - * until the whole file has been deleted off
7180 - tags.serialNumber++;
7184 - if (tags.chunkId == 0) {
7185 - /* It is an object Id,
7186 - * We need to nuke the shrinkheader flags first
7187 - * We no longer want the shrinkHeader flag since its work is done
7188 - * and if it is left in place it will mess up scanning.
7191 - yaffs_ObjectHeader *oh;
7192 - oh = (yaffs_ObjectHeader *)buffer;
7194 - tags.extraIsShrinkHeader = 0;
7196 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
7200 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
7202 - if (newChunk < 0) {
7203 - retVal = YAFFS_FAIL;
7206 - /* Ok, now fix up the Tnodes etc. */
7208 - if (tags.chunkId == 0) {
7209 - /* It's a header */
7210 - object->hdrChunk = newChunk;
7211 - object->serial = tags.serialNumber;
7213 - /* It's a data chunk */
7214 - yaffs_PutChunkIntoFile
7222 - if (retVal == YAFFS_OK)
7223 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
7228 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
7231 - /* Do any required cleanups */
7232 - for (i = 0; i < cleanups; i++) {
7233 - /* Time to delete the file too */
7235 - yaffs_FindObjectByNumber(dev,
7236 - dev->gcCleanupList[i]);
7238 - yaffs_FreeTnode(dev,
7239 - object->variant.fileVariant.
7241 - object->variant.fileVariant.top = NULL;
7244 - ("yaffs: About to finally delete object %d"
7245 - TENDSTR), object->objectId));
7246 - yaffs_DoGenericObjectDeletion(object);
7247 - object->myDev->nDeletedFiles--;
7254 - yaffs_VerifyCollectedBlock(dev, bi, block);
7255 + if (chunkId > YAFFS_MAX_CHUNK_ID)
7258 - chunksAfter = yaffs_GetErasedChunks(dev);
7259 - if (chunksBefore >= chunksAfter) {
7262 - ("gc did not increase free chunks before %d after %d"
7263 - TENDSTR), chunksBefore, chunksAfter));
7265 + /* First check we're tall enough (ie enough topLevel) */
7267 - /* If the gc completed then clear the current gcBlock so that we find another. */
7268 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
7269 - dev->gcBlock = -1;
7271 + x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
7272 + requiredTallness = 0;
7274 + x >>= YAFFS_TNODES_INTERNAL_BITS;
7275 + requiredTallness++;
7278 - dev->isDoingGC = 0;
7283 -/* New garbage collector
7284 - * If we're very low on erased blocks then we do aggressive garbage collection
7285 - * otherwise we do "leasurely" garbage collection.
7286 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
7287 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
7289 - * The idea is to help clear out space in a more spread-out manner.
7290 - * Dunno if it really does anything useful.
7292 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
7296 - int gcOk = YAFFS_OK;
7298 + if (requiredTallness > fStruct->topLevel) {
7299 + /* Not tall enough, gotta make the tree taller */
7300 + for (i = fStruct->topLevel; i < requiredTallness; i++) {
7302 - int checkpointBlockAdjust;
7303 + tn = yaffs_GetTnode(dev);
7305 - if (dev->isDoingGC) {
7306 - /* Bail out so we don't get recursive gc */
7309 + tn->internal[0] = fStruct->top;
7310 + fStruct->top = tn;
7311 + fStruct->topLevel++;
7313 + T(YAFFS_TRACE_ERROR,
7314 + (TSTR("yaffs: no more tnodes" TENDSTR)));
7320 - /* This loop should pass the first time.
7321 - * We'll only see looping here if the erase of the collected block fails.
7327 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
7328 - if (checkpointBlockAdjust < 0)
7329 - checkpointBlockAdjust = 0;
7330 + /* Traverse down to level 0, adding anything we need */
7332 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
7333 - /* We need a block soon...*/
7336 - /* We're in no hurry */
7339 + l = fStruct->topLevel;
7340 + tn = fStruct->top;
7342 - if (dev->gcBlock <= 0) {
7343 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
7347 + while (l > 0 && tn) {
7349 + (YAFFS_TNODES_LEVEL0_BITS +
7350 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
7351 + YAFFS_TNODES_INTERNAL_MASK;
7353 - block = dev->gcBlock;
7356 - dev->garbageCollections++;
7358 - dev->passiveGarbageCollections++;
7359 + if ((l > 1) && !tn->internal[x]) {
7360 + /* Add missing non-level-zero tnode */
7361 + tn->internal[x] = yaffs_GetTnode(dev);
7362 + if(!tn->internal[x])
7364 + } else if (l == 1) {
7365 + /* Looking from level 1 at level 0 */
7367 + /* If we already have one, then release it.*/
7368 + if (tn->internal[x])
7369 + yaffs_FreeTnode(dev, tn->internal[x]);
7370 + tn->internal[x] = passedTn;
7374 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
7375 - dev->nErasedBlocks, aggressive));
7376 + } else if (!tn->internal[x]) {
7377 + /* Don't have one, none passed in */
7378 + tn->internal[x] = yaffs_GetTnode(dev);
7379 + if(!tn->internal[x])
7384 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
7385 + tn = tn->internal[x];
7389 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
7392 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
7393 - TENDSTR), dev->nErasedBlocks, maxTries, block));
7395 + /* top is level 0 */
7397 + memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
7398 + yaffs_FreeTnode(dev, passedTn);
7400 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
7405 - return aggressive ? gcOk : YAFFS_OK;
7409 -/*------------------------- TAGS --------------------------------*/
7411 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
7412 - int chunkInObject)
7413 +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
7414 + yaffs_ExtendedTags *tags, int objectId,
7417 - return (tags->chunkId == chunkInObject &&
7418 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
7421 + for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
7422 + if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock,
7423 + theChunk % dev->param.nChunksPerBlock)) {
7425 + if(dev->chunkGroupSize == 1)
7428 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
7430 + if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
7442 +/* Experimental code not being used yet. Might speed up file deletion */
7443 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
7444 + * chunks and tnodes in the file.
7445 + * Returns 1 if the tree was deleted.
7446 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
7449 -/*-------------------- Data file manipulation -----------------*/
7451 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
7452 - yaffs_ExtendedTags *tags)
7453 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
7454 + int chunkOffset, int *limit)
7456 - /*Get the Tnode, then get the level 0 offset chunk offset */
7458 - int theChunk = -1;
7459 - yaffs_ExtendedTags localTags;
7465 + yaffs_ExtendedTags tags;
7467 yaffs_Device *dev = in->myDev;
7470 - /* Passed a NULL, so use our own tags space */
7471 - tags = &localTags;
7474 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7478 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7480 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7482 + if (tn->internal[i]) {
7483 + if (limit && (*limit) < 0) {
7487 + yaffs_DeleteWorker(in,
7495 + YAFFS_TNODES_INTERNAL_BITS)
7500 + yaffs_FreeTnode(dev,
7503 + tn->internal[i] = NULL;
7507 + return (allDone) ? 1 : 0;
7508 + } else if (level == 0) {
7512 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7517 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
7519 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7522 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
7523 - yaffs_ExtendedTags *tags)
7525 - /* Get the Tnode, then get the level 0 offset chunk offset */
7527 - int theChunk = -1;
7528 - yaffs_ExtendedTags localTags;
7529 + chunkInInode = (chunkOffset <<
7530 + YAFFS_TNODES_LEVEL0_BITS) + i;
7533 + yaffs_FindChunkInGroup(dev,
7539 + if (foundChunk > 0) {
7540 + yaffs_DeleteChunk(dev,
7543 + in->nDataChunks--;
7545 + *limit = *limit - 1;
7550 - yaffs_Device *dev = in->myDev;
7554 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7558 + return (i < 0) ? 1 : 0;
7563 - /* Passed a NULL, so use our own tags space */
7564 - tags = &localTags;
7567 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7573 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7577 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7579 +static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
7581 + yaffs_BlockInfo *theBlock;
7584 - /* Delete the entry in the filestructure (if found) */
7586 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
7588 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
7591 + blockNo = chunk / dev->param.nChunksPerBlock;
7592 + theBlock = yaffs_GetBlockInfo(dev, blockNo);
7594 + theBlock->softDeletions++;
7595 + dev->nFreeChunks++;
7596 + yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock);
7600 -#ifdef YAFFS_PARANOID
7601 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
7602 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
7604 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
7607 -static int yaffs_CheckFileSanity(yaffs_Object *in)
7608 +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
7609 + __u32 level, int chunkOffset)
7617 - yaffs_Tags localTags;
7618 - yaffs_Tags *tags = &localTags;
7623 + yaffs_Device *dev = in->myDev;
7625 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
7626 - return YAFFS_FAIL;
7630 - objId = in->objectId;
7631 - fSize = in->variant.fileVariant.fileSize;
7633 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
7635 - for (chunk = 1; chunk <= nChunks; chunk++) {
7636 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
7641 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
7643 - if (yaffs_CheckChunkBits
7644 - (dev, theChunk / dev->nChunksPerBlock,
7645 - theChunk % dev->nChunksPerBlock)) {
7647 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
7650 - if (yaffs_TagsMatch
7651 - (tags, in->objectId, chunk, chunkDeleted)) {
7653 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7655 + if (tn->internal[i]) {
7657 + yaffs_SoftDeleteWorker(in,
7663 + YAFFS_TNODES_INTERNAL_BITS)
7666 + yaffs_FreeTnode(dev,
7669 + tn->internal[i] = NULL;
7671 + /* Hoosterman... how could this happen? */
7675 + return (allDone) ? 1 : 0;
7676 + } else if (level == 0) {
7678 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
7679 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7681 + /* Note this does not find the real chunk, only the chunk group.
7682 + * We make an assumption that a chunk group is not larger than
7685 + yaffs_SoftDeleteChunk(dev, theChunk);
7686 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7695 - /* T(("No level 0 found for %d\n", chunk)); */
7700 - return failed ? YAFFS_FAIL : YAFFS_OK;
7706 +static void yaffs_SoftDeleteFile(yaffs_Object *obj)
7708 + if (obj->deleted &&
7709 + obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
7710 + if (obj->nDataChunks <= 0) {
7711 + /* Empty file with no duplicate object headers, just delete it immediately */
7712 + yaffs_FreeTnode(obj->myDev,
7713 + obj->variant.fileVariant.top);
7714 + obj->variant.fileVariant.top = NULL;
7715 + T(YAFFS_TRACE_TRACING,
7716 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
7718 + yaffs_DoGenericObjectDeletion(obj);
7720 + yaffs_SoftDeleteWorker(obj,
7721 + obj->variant.fileVariant.top,
7722 + obj->variant.fileVariant.
7724 + obj->softDeleted = 1;
7729 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
7730 - int chunkInNAND, int inScan)
7731 +/* Pruning removes any part of the file structure tree that is beyond the
7732 + * bounds of the file (ie that does not point to chunks).
7734 + * A file should only get pruned when its size is reduced.
7736 + * Before pruning, the chunks must be pulled from the tree and the
7737 + * level 0 tnode entries must be zeroed out.
7738 + * Could also use this for file deletion, but that's probably better handled
7739 + * by a special case.
7741 + * This function is recursive. For levels > 0 the function is called again on
7742 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
7743 + * If there is no data in a subtree then it is pruned.
7746 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7747 + __u32 level, int del0)
7749 - /* NB inScan is zero unless scanning.
7750 - * For forward scanning, inScan is > 0;
7751 - * for backward scanning inScan is < 0
7757 - yaffs_Device *dev = in->myDev;
7758 - int existingChunk;
7759 - yaffs_ExtendedTags existingTags;
7760 - yaffs_ExtendedTags newTags;
7761 - unsigned existingSerial, newSerial;
7765 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
7766 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
7767 - * If it is not during Scanning then something went wrong!
7770 - T(YAFFS_TRACE_ERROR,
7772 - ("yaffs tragedy:attempt to put data chunk into a non-file"
7777 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7778 + if (tn->internal[i]) {
7780 + yaffs_PruneWorker(dev, tn->internal[i],
7782 + (i == 0) ? del0 : 1);
7785 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
7788 + if (tn->internal[i])
7792 + int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32);
7793 + __u32 *map = (__u32 *)tn;
7795 - tn = yaffs_AddOrFindLevel0Tnode(dev,
7796 - &in->variant.fileVariant,
7800 - return YAFFS_FAIL;
7801 + for(i = 0; !hasData && i < tnodeSize_u32; i++){
7807 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7808 + if (hasData == 0 && del0) {
7809 + /* Free and return NULL */
7811 - if (inScan != 0) {
7812 - /* If we're scanning then we need to test for duplicates
7813 - * NB This does not need to be efficient since it should only ever
7814 - * happen when the power fails during a write, then only one
7815 - * chunk should ever be affected.
7817 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
7818 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
7820 + yaffs_FreeTnode(dev, tn);
7824 - if (existingChunk > 0) {
7825 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
7826 - * thus we have to do a FindChunkInFile to get the real chunk id.
7828 - * We have a duplicate now we need to decide which one to use:
7830 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
7831 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
7832 - * YAFFS1: Get both sets of tags and compare serial numbers.
7837 - /* Only do this for forward scanning */
7838 - yaffs_ReadChunkWithTagsFromNAND(dev,
7843 - /* Do a proper find */
7845 - yaffs_FindChunkInFile(in, chunkInInode,
7850 - if (existingChunk <= 0) {
7851 - /*Hoosterman - how did this happen? */
7852 +static int yaffs_PruneFileStructure(yaffs_Device *dev,
7853 + yaffs_FileStructure *fStruct)
7860 - T(YAFFS_TRACE_ERROR,
7862 - ("yaffs tragedy: existing chunk < 0 in scan"
7864 + if (fStruct->topLevel > 0) {
7866 + yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7869 + /* Now we have a tree with all the non-zero branches NULL but the height
7870 + * is the same as it was.
7871 + * Let's see if we can trim internal tnodes to shorten the tree.
7872 + * We can do this if only the 0th element in the tnode is in use
7873 + * (ie all the non-zero are NULL)
7876 - /* NB The deleted flags should be false, otherwise the chunks will
7877 - * not be loaded during a scan
7879 + while (fStruct->topLevel && !done) {
7880 + tn = fStruct->top;
7883 - newSerial = newTags.serialNumber;
7884 - existingSerial = existingTags.serialNumber;
7886 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7887 + if (tn->internal[i])
7891 - if ((inScan > 0) &&
7892 - (in->myDev->isYaffs2 ||
7893 - existingChunk <= 0 ||
7894 - ((existingSerial + 1) & 3) == newSerial)) {
7895 - /* Forward scanning.
7897 - * Delete the old one and drop through to update the tnode
7899 - yaffs_DeleteChunk(dev, existingChunk, 1,
7902 - /* Backward scanning or we want to use the existing one
7904 - * Delete the new one and return early so that the tnode isn't changed
7906 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
7911 + fStruct->top = tn->internal[0];
7912 + fStruct->topLevel--;
7913 + yaffs_FreeTnode(dev, tn);
7921 - if (existingChunk == 0)
7922 - in->nDataChunks++;
7924 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
7929 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
7932 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
7934 - if (chunkInNAND >= 0)
7935 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
7938 - T(YAFFS_TRACE_NANDACCESS,
7939 - (TSTR("Chunk %d not found zero instead" TENDSTR),
7941 - /* get sane (zero) data if you read a hole */
7942 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
7945 +/*-------------------- End of File Structure functions.-------------------*/
7949 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
7950 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7951 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7955 - yaffs_ExtendedTags tags;
7956 - yaffs_BlockInfo *bi;
7957 + yaffs_Object *obj = yaffs_AllocateRawObject(dev);
7964 - dev->nDeletions++;
7965 - block = chunkId / dev->nChunksPerBlock;
7966 - page = chunkId % dev->nChunksPerBlock;
7967 + /* Now sweeten it up... */
7969 + memset(obj, 0, sizeof(yaffs_Object));
7970 + obj->beingCreated = 1;
7972 - if (!yaffs_CheckChunkBit(dev, block, page))
7973 - T(YAFFS_TRACE_VERIFY,
7974 - (TSTR("Deleting invalid chunk %d"TENDSTR),
7977 + obj->hdrChunk = 0;
7978 + obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7979 + YINIT_LIST_HEAD(&(obj->hardLinks));
7980 + YINIT_LIST_HEAD(&(obj->hashLink));
7981 + YINIT_LIST_HEAD(&obj->siblings);
7983 - bi = yaffs_GetBlockInfo(dev, block);
7985 - T(YAFFS_TRACE_DELETION,
7986 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
7987 + /* Now make the directory sane */
7988 + if (dev->rootDir) {
7989 + obj->parent = dev->rootDir;
7990 + ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children);
7994 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
7995 + /* Add it to the lost and found directory.
7996 + * NB Can't put root or lostNFound in lostNFound so
7997 + * check if lostNFound exists first
7999 + if (dev->lostNFoundDir)
8000 + yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj);
8002 - yaffs_InitialiseTags(&tags);
8003 + obj->beingCreated = 0;
8006 - tags.chunkDeleted = 1;
8007 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
8009 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
8010 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
8012 - dev->nUnmarkedDeletions++;
8017 - /* Pull out of the management area.
8018 - * If the whole block became dirty, this will kick off an erasure.
8020 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8021 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8022 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8023 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8024 - dev->nFreeChunks++;
8025 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
8029 - yaffs_ClearChunkBit(dev, block, page);
8030 + yaffs_Object *obj =
8031 + yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
8033 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
8034 + obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
8035 + obj->unlinkAllowed = 0; /* ... or unlink it */
8037 + obj->unlinked = 0;
8038 + obj->yst_mode = mode;
8040 + obj->hdrChunk = 0; /* Not a valid chunk. */
8046 - if (bi->pagesInUse == 0 &&
8047 - !bi->hasShrinkHeader &&
8048 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8049 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8050 - yaffs_BlockBecameDirty(dev, block);
8055 +static void yaffs_UnhashObject(yaffs_Object *obj)
8058 + yaffs_Device *dev = obj->myDev;
8060 + /* If it is still linked into the bucket list, free from the list */
8061 + if (!ylist_empty(&obj->hashLink)) {
8062 + ylist_del_init(&obj->hashLink);
8063 + bucket = yaffs_HashFunction(obj->objectId);
8064 + dev->objectBucket[bucket].count--;
8068 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8069 - const __u8 *buffer, int nBytes,
8071 +/* FreeObject frees up a Object and puts it back on the free list */
8072 +static void yaffs_FreeObject(yaffs_Object *obj)
8074 - /* Find old chunk Need to do this to get serial number
8075 - * Write new one and patch into tree.
8076 - * Invalidate old tags.
8078 + yaffs_Device *dev = obj->myDev;
8081 - yaffs_ExtendedTags prevTags;
8082 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode));
8085 - yaffs_ExtendedTags newTags;
8090 + if (!ylist_empty(&obj->siblings))
8093 - yaffs_Device *dev = in->myDev;
8095 - yaffs_CheckGarbageCollection(dev);
8096 + if (obj->myInode) {
8097 + /* We're still hooked up to a cached inode.
8098 + * Don't delete now, but mark for later deletion
8100 + obj->deferedFree = 1;
8104 + yaffs_UnhashObject(obj);
8106 - /* Get the previous chunk at this location in the file if it exists */
8107 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8108 + yaffs_FreeRawObject(dev,obj);
8110 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
8113 - /* Set up new tags */
8114 - yaffs_InitialiseTags(&newTags);
8116 - newTags.chunkId = chunkInInode;
8117 - newTags.objectId = in->objectId;
8118 - newTags.serialNumber =
8119 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8120 - newTags.byteCount = nBytes;
8121 +void yaffs_HandleDeferedFree(yaffs_Object *obj)
8123 + if (obj->deferedFree)
8124 + yaffs_FreeObject(obj);
8127 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8128 - T(YAFFS_TRACE_ERROR,
8129 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8131 +static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev)
8135 + dev->nObjects = 0;
8138 + yaffs_InitialiseRawTnodesAndObjects(dev);
8140 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
8141 + YINIT_LIST_HEAD(&dev->objectBucket[i].list);
8142 + dev->objectBucket[i].count = 0;
8147 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8149 +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
8153 + int lowest = 999999;
8155 - if (newChunkId >= 0) {
8156 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8158 - if (prevChunkId >= 0)
8159 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8160 + /* Search for the shortest list or one that
8164 + for (i = 0; i < 10 && lowest > 4; i++) {
8165 + dev->bucketFinder++;
8166 + dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS;
8167 + if (dev->objectBucket[dev->bucketFinder].count < lowest) {
8168 + lowest = dev->objectBucket[dev->bucketFinder].count;
8169 + l = dev->bucketFinder;
8172 - yaffs_CheckFileSanity(in);
8174 - return newChunkId;
8179 -/* UpdateObjectHeader updates the header on NAND for an object.
8180 - * If name is not NULL, then that new name is used.
8182 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8183 - int isShrink, int shadows)
8184 +static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
8186 + int bucket = yaffs_FindNiceObjectBucket(dev);
8188 - yaffs_BlockInfo *bi;
8189 + /* Now find an object value that has not already been taken
8190 + * by scanning the list.
8193 - yaffs_Device *dev = in->myDev;
8195 + struct ylist_head *i;
8200 + __u32 n = (__u32) bucket;
8203 - yaffs_ExtendedTags newTags;
8204 - yaffs_ExtendedTags oldTags;
8205 + /* yaffs_CheckObjectHashSanity(); */
8207 - __u8 *buffer = NULL;
8208 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8211 + n += YAFFS_NOBJECT_BUCKETS;
8212 + if (1 || dev->objectBucket[bucket].count > 0) {
8213 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8214 + /* If there is already one in the list */
8215 + if (i && ylist_entry(i, yaffs_Object,
8216 + hashLink)->objectId == n) {
8223 - yaffs_ObjectHeader *oh = NULL;
8227 - yaffs_strcpy(oldName, _Y("silly old name"));
8228 +static void yaffs_HashObject(yaffs_Object *in)
8230 + int bucket = yaffs_HashFunction(in->objectId);
8231 + yaffs_Device *dev = in->myDev;
8233 + ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
8234 + dev->objectBucket[bucket].count++;
8238 - in == dev->rootDir || /* The rootDir should also be saved */
8240 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
8242 + int bucket = yaffs_HashFunction(number);
8243 + struct ylist_head *i;
8246 - yaffs_CheckGarbageCollection(dev);
8247 - yaffs_CheckObjectDetailsLoaded(in);
8248 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8249 + /* Look if it is in the list */
8251 + in = ylist_entry(i, yaffs_Object, hashLink);
8252 + if (in->objectId == number) {
8254 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8255 - oh = (yaffs_ObjectHeader *) buffer;
8256 + /* Don't tell the VFS about this one if it is defered free */
8257 + if (in->deferedFree)
8260 - prevChunkId = in->hdrChunk;
8266 - if (prevChunkId > 0) {
8267 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8268 - buffer, &oldTags);
8272 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8273 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
8274 + yaffs_ObjectType type)
8276 + yaffs_Object *theObject=NULL;
8277 + yaffs_Tnode *tn = NULL;
8280 + number = yaffs_CreateNewObjectNumber(dev);
8282 - memcpy(oldName, oh->name, sizeof(oh->name));
8284 + if (type == YAFFS_OBJECT_TYPE_FILE) {
8285 + tn = yaffs_GetTnode(dev);
8290 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8291 + theObject = yaffs_AllocateEmptyObject(dev);
8294 + yaffs_FreeTnode(dev,tn);
8298 - oh->type = in->variantType;
8299 - oh->yst_mode = in->yst_mode;
8300 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8303 + theObject->fake = 0;
8304 + theObject->renameAllowed = 1;
8305 + theObject->unlinkAllowed = 1;
8306 + theObject->objectId = number;
8307 + yaffs_HashObject(theObject);
8308 + theObject->variantType = type;
8309 #ifdef CONFIG_YAFFS_WINCE
8310 - oh->win_atime[0] = in->win_atime[0];
8311 - oh->win_ctime[0] = in->win_ctime[0];
8312 - oh->win_mtime[0] = in->win_mtime[0];
8313 - oh->win_atime[1] = in->win_atime[1];
8314 - oh->win_ctime[1] = in->win_ctime[1];
8315 - oh->win_mtime[1] = in->win_mtime[1];
8317 - oh->yst_uid = in->yst_uid;
8318 - oh->yst_gid = in->yst_gid;
8319 - oh->yst_atime = in->yst_atime;
8320 - oh->yst_mtime = in->yst_mtime;
8321 - oh->yst_ctime = in->yst_ctime;
8322 - oh->yst_rdev = in->yst_rdev;
8325 - oh->parentObjectId = in->parent->objectId;
8327 - oh->parentObjectId = 0;
8329 - if (name && *name) {
8330 - memset(oh->name, 0, sizeof(oh->name));
8331 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
8332 - } else if (prevChunkId >= 0)
8333 - memcpy(oh->name, oldName, sizeof(oh->name));
8335 - memset(oh->name, 0, sizeof(oh->name));
8336 + yfsd_WinFileTimeNow(theObject->win_atime);
8337 + theObject->win_ctime[0] = theObject->win_mtime[0] =
8338 + theObject->win_atime[0];
8339 + theObject->win_ctime[1] = theObject->win_mtime[1] =
8340 + theObject->win_atime[1];
8342 - oh->isShrink = isShrink;
8345 - switch (in->variantType) {
8346 - case YAFFS_OBJECT_TYPE_UNKNOWN:
8347 - /* Should not happen */
8349 + theObject->yst_atime = theObject->yst_mtime =
8350 + theObject->yst_ctime = Y_CURRENT_TIME;
8353 case YAFFS_OBJECT_TYPE_FILE:
8355 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
8356 - || oh->parentObjectId ==
8357 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
8358 - fileVariant.fileSize;
8360 - case YAFFS_OBJECT_TYPE_HARDLINK:
8361 - oh->equivalentObjectId =
8362 - in->variant.hardLinkVariant.equivalentObjectId;
8364 - case YAFFS_OBJECT_TYPE_SPECIAL:
8366 + theObject->variant.fileVariant.fileSize = 0;
8367 + theObject->variant.fileVariant.scannedFileSize = 0;
8368 + theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
8369 + theObject->variant.fileVariant.topLevel = 0;
8370 + theObject->variant.fileVariant.top = tn;
8372 case YAFFS_OBJECT_TYPE_DIRECTORY:
8374 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8376 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8379 case YAFFS_OBJECT_TYPE_SYMLINK:
8380 - yaffs_strncpy(oh->alias,
8381 - in->variant.symLinkVariant.alias,
8382 - YAFFS_MAX_ALIAS_LENGTH);
8383 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
8384 + case YAFFS_OBJECT_TYPE_HARDLINK:
8385 + case YAFFS_OBJECT_TYPE_SPECIAL:
8386 + /* No action required */
8388 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8389 + /* todo this should not happen */
8395 - yaffs_InitialiseTags(&newTags);
8397 - newTags.chunkId = 0;
8398 - newTags.objectId = in->objectId;
8399 - newTags.serialNumber = in->serial;
8401 - /* Add extra info for file header */
8403 - newTags.extraHeaderInfoAvailable = 1;
8404 - newTags.extraParentObjectId = oh->parentObjectId;
8405 - newTags.extraFileLength = oh->fileSize;
8406 - newTags.extraIsShrinkHeader = oh->isShrink;
8407 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
8408 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
8409 - newTags.extraObjectType = in->variantType;
8411 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
8415 - /* Create new chunk in NAND */
8417 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8418 - (prevChunkId >= 0) ? 1 : 0);
8419 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
8421 + yaffs_ObjectType type)
8423 + yaffs_Object *theObject = NULL;
8425 - if (newChunkId >= 0) {
8427 + theObject = yaffs_FindObjectByNumber(dev, number);
8429 - in->hdrChunk = newChunkId;
8431 + theObject = yaffs_CreateNewObject(dev, number, type);
8433 - if (prevChunkId >= 0) {
8434 - yaffs_DeleteChunk(dev, prevChunkId, 1,
8439 - if (!yaffs_ObjectHasCachedWriteData(in))
8443 - /* If this was a shrink, then mark the block that the chunk lives on */
8445 - bi = yaffs_GetBlockInfo(in->myDev,
8446 - newChunkId / in->myDev->nChunksPerBlock);
8447 - bi->hasShrinkHeader = 1;
8451 +YCHAR *yaffs_CloneString(const YCHAR *str)
8453 + YCHAR *newStr = NULL;
8456 - retVal = newChunkId;
8460 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
8461 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
8463 + yaffs_strncpy(newStr, str,len);
8469 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8474 -/*------------------------ Short Operations Cache ----------------------------------------
8475 - * In many situations where there is no high level buffering (eg WinCE) a lot of
8476 - * reads might be short sequential reads, and a lot of writes may be short
8477 - * sequential writes. eg. scanning/writing a jpeg file.
8478 - * In these cases, a short read/write cache can provide a huge perfomance benefit
8479 - * with dumb-as-a-rock code.
8480 - * In Linux, the page cache provides read buffering aand the short op cache provides write
8483 - * There are a limited number (~10) of cache chunks per device so that we don't
8484 - * need a very intelligent search.
8486 + * Mknod (create) a new object.
8487 + * equivalentObject only has meaning for a hard link;
8488 + * aliasString only has meaning for a symlink.
8489 + * rdev only has meaning for devices (a subset of special objects)
8492 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
8493 +static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
8494 + yaffs_Object *parent,
8495 + const YCHAR *name,
8499 + yaffs_Object *equivalentObject,
8500 + const YCHAR *aliasString, __u32 rdev)
8502 - yaffs_Device *dev = obj->myDev;
8504 - yaffs_ChunkCache *cache;
8505 - int nCaches = obj->myDev->nShortOpCaches;
8507 + YCHAR *str = NULL;
8509 - for (i = 0; i < nCaches; i++) {
8510 - cache = &dev->srCache[i];
8511 - if (cache->object == obj &&
8514 + yaffs_Device *dev = parent->myDev;
8516 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8517 + if (yaffs_FindObjectByName(parent, name))
8520 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8521 + str = yaffs_CloneString(aliasString);
8528 + in = yaffs_CreateNewObject(dev, -1, type);
8536 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
8538 - yaffs_Device *dev = obj->myDev;
8539 - int lowest = -99; /* Stop compiler whining. */
8541 - yaffs_ChunkCache *cache;
8542 - int chunkWritten = 0;
8543 - int nCaches = obj->myDev->nShortOpCaches;
8545 - if (nCaches > 0) {
8549 - /* Find the dirty cache for this object with the lowest chunk id. */
8550 - for (i = 0; i < nCaches; i++) {
8551 - if (dev->srCache[i].object == obj &&
8552 - dev->srCache[i].dirty) {
8554 - || dev->srCache[i].chunkId <
8556 - cache = &dev->srCache[i];
8557 - lowest = cache->chunkId;
8562 - if (cache && !cache->locked) {
8563 - /* Write it out and free it up */
8566 - yaffs_WriteChunkDataToObject(cache->object,
8572 - cache->object = NULL;
8577 + in->variantType = type;
8579 - } while (cache && chunkWritten > 0);
8580 + in->yst_mode = mode;
8583 - /* Hoosterman, disk full while writing cache out. */
8584 - T(YAFFS_TRACE_ERROR,
8585 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
8586 +#ifdef CONFIG_YAFFS_WINCE
8587 + yfsd_WinFileTimeNow(in->win_atime);
8588 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8589 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
8592 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
8594 + in->yst_rdev = rdev;
8595 + in->yst_uid = uid;
8596 + in->yst_gid = gid;
8598 + in->nDataChunks = 0;
8600 + yaffs_SetObjectName(in, name);
8603 + yaffs_AddObjectToDirectory(parent, in);
8605 + in->myDev = parent->myDev;
8608 + case YAFFS_OBJECT_TYPE_SYMLINK:
8609 + in->variant.symLinkVariant.alias = str;
8611 + case YAFFS_OBJECT_TYPE_HARDLINK:
8612 + in->variant.hardLinkVariant.equivalentObject =
8614 + in->variant.hardLinkVariant.equivalentObjectId =
8615 + equivalentObject->objectId;
8616 + ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
8618 + case YAFFS_OBJECT_TYPE_FILE:
8619 + case YAFFS_OBJECT_TYPE_DIRECTORY:
8620 + case YAFFS_OBJECT_TYPE_SPECIAL:
8621 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8626 + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) {
8627 + /* Could not create the object header, fail the creation */
8628 + yaffs_DeleteObject(in);
8632 + yaffs_UpdateParent(parent);
8638 -/*yaffs_FlushEntireDeviceCache(dev)
8643 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
8644 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
8645 + __u32 mode, __u32 uid, __u32 gid)
8647 - yaffs_Object *obj;
8648 - int nCaches = dev->nShortOpCaches;
8651 - /* Find a dirty object in the cache and flush it...
8652 - * until there are no further dirty objects.
8656 - for (i = 0; i < nCaches && !obj; i++) {
8657 - if (dev->srCache[i].object &&
8658 - dev->srCache[i].dirty)
8659 - obj = dev->srCache[i].object;
8663 - yaffs_FlushFilesChunkCache(obj);
8664 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
8665 + uid, gid, NULL, NULL, 0);
8669 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
8670 + __u32 mode, __u32 uid, __u32 gid)
8672 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
8673 + mode, uid, gid, NULL, NULL, 0);
8676 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
8677 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
8679 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
8680 + uid, gid, NULL, NULL, rdev);
8683 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
8684 + __u32 mode, __u32 uid, __u32 gid,
8685 + const YCHAR *alias)
8687 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
8688 + uid, gid, NULL, alias, 0);
8691 -/* Grab us a cache chunk for use.
8692 - * First look for an empty one.
8693 - * Then look for the least recently used non-dirty one.
8694 - * Then look for the least recently used dirty one...., flush and look again.
8696 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
8697 +/* yaffs_Link returns the object id of the equivalent object.*/
8698 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
8699 + yaffs_Object *equivalentObject)
8702 + /* Get the real object in case we were fed a hard link as an equivalent object */
8703 + equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
8705 - if (dev->nShortOpCaches > 0) {
8706 - for (i = 0; i < dev->nShortOpCaches; i++) {
8707 - if (!dev->srCache[i].object)
8708 - return &dev->srCache[i];
8710 + if (yaffs_MknodObject
8711 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
8712 + equivalentObject, NULL, 0)) {
8713 + return equivalentObject;
8721 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
8722 +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
8723 + const YCHAR *newName, int force, int shadows)
8725 - yaffs_ChunkCache *cache;
8726 - yaffs_Object *theObj;
8731 - if (dev->nShortOpCaches > 0) {
8732 - /* Try find a non-dirty one... */
8736 - cache = yaffs_GrabChunkCacheWorker(dev);
8737 + yaffs_Object *existingTarget;
8740 - /* They were all dirty, find the last recently used object and flush
8741 - * its cache, then find again.
8742 - * NB what's here is not very accurate, we actually flush the object
8743 - * the last recently used page.
8745 + if (newDir == NULL)
8746 + newDir = obj->parent; /* use the old directory */
8748 - /* With locking we can't assume we can use entry zero */
8749 + if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
8750 + T(YAFFS_TRACE_ALWAYS,
8752 + ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
8761 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
8762 + if (obj->myDev->param.isYaffs2)
8763 + unlinkOp = (newDir == obj->myDev->unlinkedDir);
8765 + unlinkOp = (newDir == obj->myDev->unlinkedDir
8766 + && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
8768 - for (i = 0; i < dev->nShortOpCaches; i++) {
8769 - if (dev->srCache[i].object &&
8770 - !dev->srCache[i].locked &&
8771 - (dev->srCache[i].lastUse < usage || !cache)) {
8772 - usage = dev->srCache[i].lastUse;
8773 - theObj = dev->srCache[i].object;
8774 - cache = &dev->srCache[i];
8778 + deleteOp = (newDir == obj->myDev->deletedDir);
8780 - if (!cache || cache->dirty) {
8781 - /* Flush and try again */
8782 - yaffs_FlushFilesChunkCache(theObj);
8783 - cache = yaffs_GrabChunkCacheWorker(dev);
8785 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8791 + /* If the object is a file going into the unlinked directory,
8792 + * then it is OK to just stuff it in since duplicate names are allowed.
8793 + * else only proceed if the new name does not exist and if we're putting
8794 + * it into a directory.
8800 + !existingTarget) &&
8801 + newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
8802 + yaffs_SetObjectName(obj, newName);
8806 + yaffs_AddObjectToDirectory(newDir, obj);
8808 -/* Find a cached chunk */
8809 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
8812 - yaffs_Device *dev = obj->myDev;
8814 - if (dev->nShortOpCaches > 0) {
8815 - for (i = 0; i < dev->nShortOpCaches; i++) {
8816 - if (dev->srCache[i].object == obj &&
8817 - dev->srCache[i].chunkId == chunkId) {
8820 + obj->unlinked = 1;
8822 - return &dev->srCache[i];
8825 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
8826 + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0)
8831 + return YAFFS_FAIL;
8834 -/* Mark the chunk for the least recently used algorithym */
8835 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
8837 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
8838 + yaffs_Object *newDir, const YCHAR *newName)
8840 + yaffs_Object *obj = NULL;
8841 + yaffs_Object *existingTarget = NULL;
8844 + yaffs_Device *dev;
8846 - if (dev->nShortOpCaches > 0) {
8847 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
8848 - /* Reset the cache usages */
8850 - for (i = 1; i < dev->nShortOpCaches; i++)
8851 - dev->srCache[i].lastUse = 0;
8853 - dev->srLastUse = 0;
8855 + if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8857 + if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8861 + dev = oldDir->myDev;
8863 - cache->lastUse = dev->srLastUse;
8864 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
8865 + /* Special case for case insemsitive systems (eg. WinCE).
8866 + * While look-up is case insensitive, the name isn't.
8867 + * Therefore we might want to change x.txt to X.txt
8869 + if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
8877 + if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
8878 + /* ENAMETOOLONG */
8879 + return YAFFS_FAIL;
8881 -/* Invalidate a single cache page.
8882 - * Do this when a whole page gets written,
8883 - * ie the short cache for this page is no longer valid.
8885 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
8887 - if (object->myDev->nShortOpCaches > 0) {
8888 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
8889 + obj = yaffs_FindObjectByName(oldDir, oldName);
8892 - cache->object = NULL;
8895 + if (obj && obj->renameAllowed) {
8897 -/* Invalidate all the cache pages associated with this object
8898 - * Do this whenever ther file is deleted or resized.
8900 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
8903 - yaffs_Device *dev = in->myDev;
8904 + /* Now do the handling for an existing target, if there is one */
8906 - if (dev->nShortOpCaches > 0) {
8907 - /* Invalidate it. */
8908 - for (i = 0; i < dev->nShortOpCaches; i++) {
8909 - if (dev->srCache[i].object == in)
8910 - dev->srCache[i].object = NULL;
8911 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8912 + if (existingTarget &&
8913 + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
8914 + !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
8915 + /* There is a target that is a non-empty directory, so we fail */
8916 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
8917 + } else if (existingTarget && existingTarget != obj) {
8918 + /* Nuke the target first, using shadowing,
8919 + * but only if it isn't the same object.
8921 + * Note we must disable gc otherwise it can mess up the shadowing.
8925 + yaffs_ChangeObjectName(obj, newDir, newName, force,
8926 + existingTarget->objectId);
8927 + existingTarget->isShadowed = 1;
8928 + yaffs_UnlinkObject(existingTarget);
8932 + result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
8934 + yaffs_UpdateParent(oldDir);
8935 + if(newDir != oldDir)
8936 + yaffs_UpdateParent(newDir);
8940 + return YAFFS_FAIL;
8943 -/*--------------------- Checkpointing --------------------*/
8945 +/*------------------------- Block Management and Page Allocation ----------------*/
8947 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
8948 +static int yaffs_InitialiseBlocks(yaffs_Device *dev)
8950 - yaffs_CheckpointValidity cp;
8951 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
8953 - memset(&cp, 0, sizeof(cp));
8954 + dev->blockInfo = NULL;
8955 + dev->chunkBits = NULL;
8957 - cp.structType = sizeof(cp);
8958 - cp.magic = YAFFS_MAGIC;
8959 - cp.version = YAFFS_CHECKPOINT_VERSION;
8960 - cp.head = (head) ? 1 : 0;
8961 + dev->allocationBlock = -1; /* force it to get a new one */
8963 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
8966 + /* If the first allocation strategy fails, thry the alternate one */
8967 + dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
8968 + if (!dev->blockInfo) {
8969 + dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
8970 + dev->blockInfoAlt = 1;
8972 + dev->blockInfoAlt = 0;
8974 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
8976 - yaffs_CheckpointValidity cp;
8978 + if (dev->blockInfo) {
8979 + /* Set up dynamic blockinfo stuff. */
8980 + dev->chunkBitmapStride = (dev->param.nChunksPerBlock + 7) / 8; /* round up bytes */
8981 + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
8982 + if (!dev->chunkBits) {
8983 + dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
8984 + dev->chunkBitsAlt = 1;
8986 + dev->chunkBitsAlt = 0;
8989 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
8990 + if (dev->blockInfo && dev->chunkBits) {
8991 + memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
8992 + memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
8997 - ok = (cp.structType == sizeof(cp)) &&
8998 - (cp.magic == YAFFS_MAGIC) &&
8999 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
9000 - (cp.head == ((head) ? 1 : 0));
9001 - return ok ? 1 : 0;
9002 + return YAFFS_FAIL;
9005 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
9006 - yaffs_Device *dev)
9007 +static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
9009 - cp->nErasedBlocks = dev->nErasedBlocks;
9010 - cp->allocationBlock = dev->allocationBlock;
9011 - cp->allocationPage = dev->allocationPage;
9012 - cp->nFreeChunks = dev->nFreeChunks;
9013 + if (dev->blockInfoAlt && dev->blockInfo)
9014 + YFREE_ALT(dev->blockInfo);
9015 + else if (dev->blockInfo)
9016 + YFREE(dev->blockInfo);
9018 + dev->blockInfoAlt = 0;
9020 - cp->nDeletedFiles = dev->nDeletedFiles;
9021 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9022 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9023 - cp->sequenceNumber = dev->sequenceNumber;
9024 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9025 + dev->blockInfo = NULL;
9027 + if (dev->chunkBitsAlt && dev->chunkBits)
9028 + YFREE_ALT(dev->chunkBits);
9029 + else if (dev->chunkBits)
9030 + YFREE(dev->chunkBits);
9031 + dev->chunkBitsAlt = 0;
9032 + dev->chunkBits = NULL;
9035 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9036 - yaffs_CheckpointDevice *cp)
9037 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
9039 - dev->nErasedBlocks = cp->nErasedBlocks;
9040 - dev->allocationBlock = cp->allocationBlock;
9041 - dev->allocationPage = cp->allocationPage;
9042 - dev->nFreeChunks = cp->nFreeChunks;
9043 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
9045 - dev->nDeletedFiles = cp->nDeletedFiles;
9046 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9047 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9048 - dev->sequenceNumber = cp->sequenceNumber;
9049 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9053 + /* If the block is still healthy erase it and mark as clean.
9054 + * If the block has had a data failure, then retire it.
9057 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9059 - yaffs_CheckpointDevice cp;
9061 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9062 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9063 + (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
9064 + blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
9067 + yaffs2_ClearOldestDirtySequence(dev,bi);
9069 - /* Write device runtime values*/
9070 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9071 - cp.structType = sizeof(cp);
9072 + bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
9074 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9075 + /* If this is the block being garbage collected then stop gc'ing this block */
9076 + if(blockNo == dev->gcBlock)
9079 + /* If this block is currently the best candidate for gc then drop as a candidate */
9080 + if(blockNo == dev->gcDirtiest){
9081 + dev->gcDirtiest = 0;
9082 + dev->gcPagesInUse = 0;
9085 - /* Write block info */
9087 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9088 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9089 + if (!bi->needsRetiring) {
9090 + yaffs2_InvalidateCheckpoint(dev);
9091 + erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
9093 + dev->nErasureFailures++;
9094 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9095 + (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
9099 - /* Write chunk bits */
9101 - nBytes = nBlocks * dev->chunkBitmapStride;
9102 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9104 + ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
9106 + for (i = 0; i < dev->param.nChunksPerBlock; i++) {
9107 + if (!yaffs_CheckChunkErased
9108 + (dev, blockNo * dev->param.nChunksPerBlock + i)) {
9109 + T(YAFFS_TRACE_ERROR,
9111 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9112 + TENDSTR), blockNo, i));
9116 - return ok ? 1 : 0;
9119 + /* Clean it up... */
9120 + bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
9121 + bi->sequenceNumber = 0;
9122 + dev->nErasedBlocks++;
9123 + bi->pagesInUse = 0;
9124 + bi->softDeletions = 0;
9125 + bi->hasShrinkHeader = 0;
9126 + bi->skipErasedCheck = 1; /* This is clean, so no need to check */
9127 + bi->gcPrioritise = 0;
9128 + yaffs_ClearChunkBits(dev, blockNo);
9130 + T(YAFFS_TRACE_ERASE,
9131 + (TSTR("Erased block %d" TENDSTR), blockNo));
9133 + dev->nFreeChunks -= dev->param.nChunksPerBlock; /* We lost a block of free space */
9135 + yaffs_RetireBlock(dev, blockNo);
9136 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9137 + (TSTR("**>> Block %d retired" TENDSTR), blockNo));
9141 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9142 +static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
9144 - yaffs_CheckpointDevice cp;
9146 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9151 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9154 + yaffs_BlockInfo *bi;
9156 - if (cp.structType != sizeof(cp))
9158 + if (dev->nErasedBlocks < 1) {
9159 + /* Hoosterman we've got a problem.
9160 + * Can't get space to gc
9162 + T(YAFFS_TRACE_ERROR,
9163 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9168 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9169 + /* Find an empty block. */
9171 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9172 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
9173 + dev->allocationBlockFinder++;
9174 + if (dev->allocationBlockFinder < dev->internalStartBlock
9175 + || dev->allocationBlockFinder > dev->internalEndBlock) {
9176 + dev->allocationBlockFinder = dev->internalStartBlock;
9179 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9180 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
9184 - nBytes = nBlocks * dev->chunkBitmapStride;
9185 + if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
9186 + bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
9187 + dev->sequenceNumber++;
9188 + bi->sequenceNumber = dev->sequenceNumber;
9189 + dev->nErasedBlocks--;
9190 + T(YAFFS_TRACE_ALLOCATE,
9191 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9192 + dev->allocationBlockFinder, dev->sequenceNumber,
9193 + dev->nErasedBlocks));
9194 + return dev->allocationBlockFinder;
9198 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9199 + T(YAFFS_TRACE_ALWAYS,
9201 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9202 + TENDSTR), dev->nErasedBlocks));
9204 - return ok ? 1 : 0;
9208 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9209 - yaffs_Object *obj)
9212 + * Check if there's space to allocate...
9213 + * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
9215 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks)
9217 + int reservedChunks;
9218 + int reservedBlocks = dev->param.nReservedBlocks;
9219 + int checkpointBlocks;
9221 - cp->objectId = obj->objectId;
9222 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9223 - cp->hdrChunk = obj->hdrChunk;
9224 - cp->variantType = obj->variantType;
9225 - cp->deleted = obj->deleted;
9226 - cp->softDeleted = obj->softDeleted;
9227 - cp->unlinked = obj->unlinked;
9228 - cp->fake = obj->fake;
9229 - cp->renameAllowed = obj->renameAllowed;
9230 - cp->unlinkAllowed = obj->unlinkAllowed;
9231 - cp->serial = obj->serial;
9232 - cp->nDataChunks = obj->nDataChunks;
9233 + checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev);
9235 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9236 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9237 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9238 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9239 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
9241 + return (dev->nFreeChunks > (reservedChunks + nChunks));
9244 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9245 +static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
9246 + yaffs_BlockInfo **blockUsedPtr)
9249 + yaffs_BlockInfo *bi;
9251 - yaffs_Object *parent;
9252 + if (dev->allocationBlock < 0) {
9253 + /* Get next block to allocate off */
9254 + dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
9255 + dev->allocationPage = 0;
9258 - if (obj->variantType != cp->variantType) {
9259 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9260 - TCONT("chunk %d does not match existing object type %d")
9261 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9262 - obj->variantType));
9264 + if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) {
9265 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9269 - obj->objectId = cp->objectId;
9270 + if (dev->nErasedBlocks < dev->param.nReservedBlocks
9271 + && dev->allocationPage == 0) {
9272 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9276 - parent = yaffs_FindOrCreateObjectByNumber(
9279 - YAFFS_OBJECT_TYPE_DIRECTORY);
9282 + /* Next page please.... */
9283 + if (dev->allocationBlock >= 0) {
9284 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9287 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9288 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9289 - TCONT(" chunk %d Parent type, %d, not directory")
9291 - cp->objectId, cp->parentId, cp->variantType,
9292 - cp->hdrChunk, parent->variantType));
9295 - yaffs_AddObjectToDirectory(parent, obj);
9297 + retVal = (dev->allocationBlock * dev->param.nChunksPerBlock) +
9298 + dev->allocationPage;
9300 + yaffs_SetChunkBit(dev, dev->allocationBlock,
9301 + dev->allocationPage);
9303 - obj->hdrChunk = cp->hdrChunk;
9304 - obj->variantType = cp->variantType;
9305 - obj->deleted = cp->deleted;
9306 - obj->softDeleted = cp->softDeleted;
9307 - obj->unlinked = cp->unlinked;
9308 - obj->fake = cp->fake;
9309 - obj->renameAllowed = cp->renameAllowed;
9310 - obj->unlinkAllowed = cp->unlinkAllowed;
9311 - obj->serial = cp->serial;
9312 - obj->nDataChunks = cp->nDataChunks;
9313 + dev->allocationPage++;
9315 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9316 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9317 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9318 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9319 + dev->nFreeChunks--;
9321 - if (obj->hdrChunk > 0)
9322 - obj->lazyLoaded = 1;
9325 + /* If the block is full set the state to full */
9326 + if (dev->allocationPage >= dev->param.nChunksPerBlock) {
9327 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9328 + dev->allocationBlock = -1;
9332 + *blockUsedPtr = bi;
9337 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9338 - __u32 level, int chunkOffset)
9341 - yaffs_Device *dev = in->myDev;
9343 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9344 + T(YAFFS_TRACE_ERROR,
9345 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9347 - if (tnodeSize < sizeof(yaffs_Tnode))
9348 - tnodeSize = sizeof(yaffs_Tnode);
9352 +static int yaffs_GetErasedChunks(yaffs_Device *dev)
9358 + n = dev->nErasedBlocks * dev->param.nChunksPerBlock;
9360 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9361 - if (tn->internal[i]) {
9362 - ok = yaffs_CheckpointTnodeWorker(in,
9365 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9368 - } else if (level == 0) {
9369 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9370 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9372 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9375 + if (dev->allocationBlock > 0)
9376 + n += (dev->param.nChunksPerBlock - dev->allocationPage);
9383 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9385 + * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
9386 + * if we don't want to write to it.
9388 +void yaffs_SkipRestOfBlock(yaffs_Device *dev)
9390 - __u32 endMarker = ~0;
9393 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9394 - ok = yaffs_CheckpointTnodeWorker(obj,
9395 - obj->variant.fileVariant.top,
9396 - obj->variant.fileVariant.topLevel,
9399 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
9400 - sizeof(endMarker));
9401 + if(dev->allocationBlock > 0){
9402 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9403 + if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
9404 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9405 + dev->allocationBlock = -1;
9409 - return ok ? 1 : 0;
9412 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
9416 - yaffs_Device *dev = obj->myDev;
9417 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
9420 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9422 - if (tnodeSize < sizeof(yaffs_Tnode))
9423 - tnodeSize = sizeof(yaffs_Tnode);
9424 +static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
9430 + int retVal = YAFFS_OK;
9432 + int isCheckpointBlock;
9433 + int matchingChunk;
9436 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9437 + int chunksBefore = yaffs_GetErasedChunks(dev);
9440 - while (ok && (~baseChunk)) {
9442 - /* Read level 0 tnode */
9443 + yaffs_ExtendedTags tags;
9445 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
9447 - tn = yaffs_GetTnodeRaw(dev);
9449 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
9452 + yaffs_Object *object;
9455 - ok = yaffs_AddOrFindLevel0Tnode(dev,
9459 + isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
9462 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9465 + T(YAFFS_TRACE_TRACING,
9466 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
9469 + bi->hasShrinkHeader,
9472 - T(YAFFS_TRACE_CHECKPOINT, (
9473 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
9474 - nread, baseChunk, ok));
9475 + /*yaffs_VerifyFreeChunks(dev); */
9477 - return ok ? 1 : 0;
9479 + if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
9480 + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
9482 + bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
9484 + dev->gcDisable = 1;
9486 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
9488 - yaffs_Object *obj;
9489 - yaffs_CheckpointObject cp;
9492 - struct ylist_head *lh;
9493 + if (isCheckpointBlock ||
9494 + !yaffs_StillSomeChunkBits(dev, block)) {
9495 + T(YAFFS_TRACE_TRACING,
9497 + ("Collecting block %d that has no chunks in use" TENDSTR),
9499 + yaffs_BlockBecameDirty(dev, block);
9502 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
9504 - /* Iterate through the objects in each hash entry,
9505 - * dumping them to the checkpointing stream.
9507 + yaffs_VerifyBlock(dev, bi, block);
9509 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
9510 - ylist_for_each(lh, &dev->objectBucket[i].list) {
9512 - obj = ylist_entry(lh, yaffs_Object, hashLink);
9513 - if (!obj->deferedFree) {
9514 - yaffs_ObjectToCheckpointObject(&cp, obj);
9515 - cp.structType = sizeof(cp);
9517 - T(YAFFS_TRACE_CHECKPOINT, (
9518 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
9519 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
9520 + maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5;
9521 + oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk;
9523 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9524 + for (/* init already done */;
9525 + retVal == YAFFS_OK &&
9526 + dev->gcChunk < dev->param.nChunksPerBlock &&
9527 + (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
9529 + dev->gcChunk++, oldChunk++) {
9530 + if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
9532 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9533 - ok = yaffs_WriteCheckpointTnodes(obj);
9538 + /* This page is in use and might need to be copied off */
9540 - /* Dump end of list */
9541 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
9542 - cp.structType = sizeof(cp);
9546 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9549 - return ok ? 1 : 0;
9551 + yaffs_InitialiseTags(&tags);
9553 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
9555 - yaffs_Object *obj;
9556 - yaffs_CheckpointObject cp;
9559 - yaffs_Object *hardList = NULL;
9560 + yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
9563 - while (ok && !done) {
9564 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9565 - if (cp.structType != sizeof(cp)) {
9566 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
9567 - cp.structType, sizeof(cp), ok));
9571 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
9572 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
9574 - if (ok && cp.objectId == ~0)
9577 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
9579 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
9582 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9583 - ok = yaffs_ReadCheckpointTnodes(obj);
9584 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
9585 - obj->hardLinks.next =
9586 - (struct ylist_head *) hardList;
9594 + yaffs_FindObjectByNumber(dev,
9598 - yaffs_HardlinkFixup(dev, hardList);
9599 + T(YAFFS_TRACE_GC_DETAIL,
9601 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
9602 + dev->gcChunk, tags.objectId, tags.chunkId,
9605 - return ok ? 1 : 0;
9607 + if (object && !yaffs_SkipVerification(dev)) {
9608 + if (tags.chunkId == 0)
9609 + matchingChunk = object->hdrChunk;
9610 + else if (object->softDeleted)
9611 + matchingChunk = oldChunk; /* Defeat the test */
9613 + matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
9615 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
9617 - __u32 checkpointSum;
9619 + if (oldChunk != matchingChunk)
9620 + T(YAFFS_TRACE_ERROR,
9621 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
9622 + oldChunk, matchingChunk, tags.objectId, tags.chunkId));
9624 - yaffs_GetCheckpointSum(dev, &checkpointSum);
9627 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
9629 + T(YAFFS_TRACE_ERROR,
9631 + ("page %d in gc has no object: %d %d %d "
9632 + TENDSTR), oldChunk,
9633 + tags.objectId, tags.chunkId, tags.byteCount));
9639 + object->deleted &&
9640 + object->softDeleted &&
9641 + tags.chunkId != 0) {
9642 + /* Data chunk in a soft deleted file, throw it away
9643 + * It's a soft deleted data chunk,
9644 + * No need to copy this, just forget about it and
9645 + * fix up the object.
9648 + /* Free chunks already includes softdeleted chunks.
9649 + * How ever this chunk is going to soon be really deleted
9650 + * which will increment free chunks.
9651 + * We have to decrement free chunks so this works out properly.
9653 + dev->nFreeChunks--;
9654 + bi->softDeletions--;
9658 + object->nDataChunks--;
9660 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
9662 - __u32 checkpointSum0;
9663 - __u32 checkpointSum1;
9665 + if (object->nDataChunks <= 0) {
9666 + /* remeber to clean up the object */
9667 + dev->gcCleanupList[dev->nCleanups] =
9673 + /* Todo object && object->deleted && object->nDataChunks == 0 */
9674 + /* Deleted object header with no data chunks.
9675 + * Can be discarded and the file deleted.
9677 + object->hdrChunk = 0;
9678 + yaffs_FreeTnode(object->myDev,
9681 + object->variant.fileVariant.top = NULL;
9682 + yaffs_DoGenericObjectDeletion(object);
9684 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
9685 + } else if (object) {
9686 + /* It's either a data chunk in a live file or
9687 + * an ObjectHeader, so we're interested in it.
9688 + * NB Need to keep the ObjectHeaders of deleted files
9689 + * until the whole file has been deleted off
9691 + tags.serialNumber++;
9693 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
9698 + if (tags.chunkId == 0) {
9699 + /* It is an object Id,
9700 + * We need to nuke the shrinkheader flags first
9701 + * Also need to clean up shadowing.
9702 + * We no longer want the shrinkHeader flag since its work is done
9703 + * and if it is left in place it will mess up scanning.
9706 - if (checkpointSum0 != checkpointSum1)
9708 + yaffs_ObjectHeader *oh;
9709 + oh = (yaffs_ObjectHeader *)buffer;
9714 + tags.extraIsShrinkHeader = 0;
9716 + oh->shadowsObject = 0;
9717 + oh->inbandShadowsObject = 0;
9718 + tags.extraShadows = 0;
9720 + /* Update file size */
9721 + if(object->variantType == YAFFS_OBJECT_TYPE_FILE){
9722 + oh->fileSize = object->variant.fileVariant.fileSize;
9723 + tags.extraFileLength = oh->fileSize;
9726 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
9729 + yaffs_VerifyObjectHeader(object, oh, &tags, 1);
9731 + yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1);
9734 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
9736 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
9737 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
9740 + if (newChunk < 0) {
9741 + retVal = YAFFS_FAIL;
9745 - ok = yaffs_CheckpointOpen(dev, 1);
9746 + /* Ok, now fix up the Tnodes etc. */
9749 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9750 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
9753 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
9754 - ok = yaffs_WriteCheckpointDevice(dev);
9757 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
9758 - ok = yaffs_WriteCheckpointObjects(dev);
9761 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9762 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
9764 + if (tags.chunkId == 0) {
9765 + /* It's a header */
9766 + object->hdrChunk = newChunk;
9767 + object->serial = tags.serialNumber;
9769 + /* It's a data chunk */
9771 + ok = yaffs_PutChunkIntoFile
9780 - ok = yaffs_WriteCheckpointSum(dev);
9781 + if (retVal == YAFFS_OK)
9782 + yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
9784 - if (!yaffs_CheckpointClose(dev))
9790 - dev->isCheckpointed = 1;
9792 - dev->isCheckpointed = 0;
9793 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9795 - return dev->isCheckpointed;
9798 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
9802 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
9803 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
9808 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
9811 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9812 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
9815 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
9816 - ok = yaffs_ReadCheckpointDevice(dev);
9819 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
9820 - ok = yaffs_ReadCheckpointObjects(dev);
9823 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9824 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
9826 + yaffs_VerifyCollectedBlock(dev, bi, block);
9829 - ok = yaffs_ReadCheckpointSum(dev);
9830 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
9833 - if (!yaffs_CheckpointClose(dev))
9837 - dev->isCheckpointed = 1;
9839 - dev->isCheckpointed = 0;
9840 + if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
9842 + * The gc did not complete. Set block state back to FULL
9843 + * because checkpointing does not restore gc.
9845 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9847 + /* The gc completed. */
9848 + /* Do any required cleanups */
9849 + for (i = 0; i < dev->nCleanups; i++) {
9850 + /* Time to delete the file too */
9852 + yaffs_FindObjectByNumber(dev,
9853 + dev->gcCleanupList[i]);
9855 + yaffs_FreeTnode(dev,
9856 + object->variant.fileVariant.
9858 + object->variant.fileVariant.top = NULL;
9861 + ("yaffs: About to finally delete object %d"
9862 + TENDSTR), object->objectId));
9863 + yaffs_DoGenericObjectDeletion(object);
9864 + object->myDev->nDeletedFiles--;
9867 - return ok ? 1 : 0;
9872 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
9874 - if (dev->isCheckpointed ||
9875 - dev->blocksInCheckpoint > 0) {
9876 - dev->isCheckpointed = 0;
9877 - yaffs_CheckpointInvalidateStream(dev);
9878 - if (dev->superBlock && dev->markSuperBlockDirty)
9879 - dev->markSuperBlockDirty(dev->superBlock);
9880 + chunksAfter = yaffs_GetErasedChunks(dev);
9881 + if (chunksBefore >= chunksAfter) {
9884 + ("gc did not increase free chunks before %d after %d"
9885 + TENDSTR), chunksBefore, chunksAfter));
9889 + dev->nCleanups = 0;
9893 + dev->gcDisable = 0;
9895 -int yaffs_CheckpointSave(yaffs_Device *dev)
9898 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9902 - yaffs_VerifyObjects(dev);
9903 - yaffs_VerifyBlocks(dev);
9904 - yaffs_VerifyFreeChunks(dev);
9906 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
9907 + * for garbage collection.
9910 - if (!dev->isCheckpointed) {
9911 - yaffs_InvalidateCheckpoint(dev);
9912 - yaffs_WriteCheckpointData(dev);
9914 +static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
9920 + unsigned selected = 0;
9921 + int prioritised = 0;
9922 + int prioritisedExists = 0;
9923 + yaffs_BlockInfo *bi;
9926 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9927 + /* First let's see if we need to grab a prioritised block */
9928 + if (dev->hasPendingPrioritisedGCs && !aggressive) {
9929 + dev->gcDirtiest = 0;
9930 + bi = dev->blockInfo;
9931 + for (i = dev->internalStartBlock;
9932 + i <= dev->internalEndBlock && !selected;
9935 - return dev->isCheckpointed;
9937 + if (bi->gcPrioritise) {
9938 + prioritisedExists = 1;
9939 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
9940 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
9948 -int yaffs_CheckpointRestore(yaffs_Device *dev)
9951 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9953 + * If there is a prioritised block and none was selected then
9954 + * this happened because there is at least one old dirty block gumming
9955 + * up the works. Let's gc the oldest dirty block.
9958 - retval = yaffs_ReadCheckpointData(dev);
9959 + if(prioritisedExists &&
9961 + dev->oldestDirtyBlock > 0)
9962 + selected = dev->oldestDirtyBlock;
9964 - if (dev->isCheckpointed) {
9965 - yaffs_VerifyObjects(dev);
9966 - yaffs_VerifyBlocks(dev);
9967 - yaffs_VerifyFreeChunks(dev);
9968 + if (!prioritisedExists) /* None found, so we can clear this */
9969 + dev->hasPendingPrioritisedGCs = 0;
9972 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9973 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
9975 + * else (we're doing a leasurely gc), then we only bother to do this if the
9976 + * block has only a few pages in use.
9983 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
9985 + threshold = dev->param.nChunksPerBlock;
9986 + iterations = nBlocks;
9990 -/*--------------------- File read/write ------------------------
9991 - * Read and write have very similar structures.
9992 - * In general the read/write has three parts to it
9993 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
9994 - * Some complete chunks
9995 - * An incomplete chunk to end off with
9997 - * Curve-balls: the first chunk might also be the last chunk.
10000 + maxThreshold = dev->param.nChunksPerBlock/2;
10002 + maxThreshold = dev->param.nChunksPerBlock/8;
10004 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
10007 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
10008 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
10015 - yaffs_ChunkCache *cache;
10016 + threshold = background ?
10017 + (dev->gcNotDone + 2) * 2 : 0;
10018 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10019 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10020 + if(threshold > maxThreshold)
10021 + threshold = maxThreshold;
10023 - yaffs_Device *dev;
10024 + iterations = nBlocks / 16 + 1;
10025 + if (iterations > 100)
10026 + iterations = 100;
10031 + i < iterations &&
10032 + (dev->gcDirtiest < 1 ||
10033 + dev->gcPagesInUse > YAFFS_GC_GOOD_ENOUGH);
10035 + dev->gcBlockFinder++;
10036 + if (dev->gcBlockFinder < dev->internalStartBlock ||
10037 + dev->gcBlockFinder > dev->internalEndBlock)
10038 + dev->gcBlockFinder = dev->internalStartBlock;
10041 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10042 - /* start = offset % dev->nDataBytesPerChunk; */
10043 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10045 + bi = yaffs_GetBlockInfo(dev, dev->gcBlockFinder);
10047 - /* OK now check for the curveball where the start and end are in
10048 - * the same chunk.
10050 - if ((start + n) < dev->nDataBytesPerChunk)
10053 - nToCopy = dev->nDataBytesPerChunk - start;
10054 + pagesUsed = bi->pagesInUse - bi->softDeletions;
10056 - cache = yaffs_FindChunkCache(in, chunk);
10057 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
10058 + pagesUsed < dev->param.nChunksPerBlock &&
10059 + (dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) &&
10060 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
10061 + dev->gcDirtiest = dev->gcBlockFinder;
10062 + dev->gcPagesInUse = pagesUsed;
10066 - /* If the chunk is already in the cache or it is less than a whole chunk
10067 - * or we're using inband tags then use the cache (if there is caching)
10068 - * else bypass the cache.
10070 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10071 - if (dev->nShortOpCaches > 0) {
10072 + if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold)
10073 + selected = dev->gcDirtiest;
10077 + * If nothing has been selected for a while, try selecting the oldest dirty
10078 + * because that's gumming up the works.
10081 - /* If we can't find the data in the cache, then load it up. */
10082 + if(!selected && dev->param.isYaffs2 &&
10083 + dev->gcNotDone >= ( background ? 10 : 20)){
10084 + yaffs2_FindOldestDirtySequence(dev);
10085 + if(dev->oldestDirtyBlock > 0) {
10086 + selected = dev->oldestDirtyBlock;
10087 + dev->gcDirtiest = selected;
10088 + dev->oldestDirtyGCs++;
10089 + bi = yaffs_GetBlockInfo(dev, selected);
10090 + dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions;
10092 + dev->gcNotDone = 0;
10096 - cache = yaffs_GrabChunkCache(in->myDev);
10097 - cache->object = in;
10098 - cache->chunkId = chunk;
10099 - cache->dirty = 0;
10100 - cache->locked = 0;
10101 - yaffs_ReadChunkDataFromObject(in, chunk,
10104 - cache->nBytes = 0;
10107 + T(YAFFS_TRACE_GC,
10108 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10110 + dev->param.nChunksPerBlock - dev->gcPagesInUse,
10113 + dev->nGCBlocks++;
10115 + dev->backgroundGCs++;
10117 + dev->gcDirtiest = 0;
10118 + dev->gcPagesInUse = 0;
10119 + dev->gcNotDone = 0;
10120 + if(dev->refreshSkip > 0)
10121 + dev->refreshSkip--;
10123 + dev->gcNotDone++;
10124 + T(YAFFS_TRACE_GC,
10125 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10126 + dev->gcBlockFinder, dev->gcNotDone,
10128 + dev->gcDirtiest, dev->gcPagesInUse,
10129 + dev->oldestDirtyBlock,
10130 + background ? " bg" : ""));
10133 - yaffs_UseChunkCache(dev, cache, 0);
10137 - cache->locked = 1;
10138 +/* New garbage collector
10139 + * If we're very low on erased blocks then we do aggressive garbage collection
10140 + * otherwise we do "leasurely" garbage collection.
10141 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10142 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10144 + * The idea is to help clear out space in a more spread-out manner.
10145 + * Dunno if it really does anything useful.
10147 +static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
10149 + int aggressive = 0;
10150 + int gcOk = YAFFS_OK;
10151 + int maxTries = 0;
10153 + int erasedChunks;
10154 + int checkpointBlockAdjust;
10156 + if(dev->param.gcControl &&
10157 + (dev->param.gcControl(dev) & 1) == 0)
10160 - memcpy(buffer, &cache->data[start], nToCopy);
10161 + if (dev->gcDisable) {
10162 + /* Bail out so we don't get recursive gc */
10166 - cache->locked = 0;
10168 - /* Read into the local buffer then copy..*/
10169 + /* This loop should pass the first time.
10170 + * We'll only see looping here if the collection does not increase space.
10173 - __u8 *localBuffer =
10174 - yaffs_GetTempBuffer(dev, __LINE__);
10175 - yaffs_ReadChunkDataFromObject(in, chunk,
10180 - memcpy(buffer, &localBuffer[start], nToCopy);
10181 + checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev);
10183 + minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1;
10184 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10186 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10188 + /* If we need a block soon then do aggressive gc.*/
10189 + if (dev->nErasedBlocks < minErased)
10192 + if(!background && erasedChunks > (dev->nFreeChunks / 4))
10195 + if(dev->gcSkip > 20)
10196 + dev->gcSkip = 20;
10197 + if(erasedChunks < dev->nFreeChunks/2 ||
10198 + dev->gcSkip < 1 ||
10210 - /* A full chunk. Read directly into the supplied buffer. */
10211 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10212 + /* If we don't already have a block being gc'd then see if we should start another */
10214 + if (dev->gcBlock < 1 && !aggressive) {
10215 + dev->gcBlock = yaffs2_FindRefreshBlock(dev);
10216 + dev->gcChunk = 0;
10217 + dev->nCleanups=0;
10219 + if (dev->gcBlock < 1) {
10220 + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
10221 + dev->gcChunk = 0;
10222 + dev->nCleanups=0;
10226 - offset += nToCopy;
10227 - buffer += nToCopy;
10228 - nDone += nToCopy;
10229 + if (dev->gcBlock > 0) {
10232 + dev->passiveGCs++;
10235 + T(YAFFS_TRACE_GC,
10237 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10238 + dev->nErasedBlocks, aggressive));
10241 + gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive);
10244 + if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) {
10245 + T(YAFFS_TRACE_GC,
10247 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10248 + TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock));
10250 + } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) &&
10251 + (dev->gcBlock > 0) &&
10254 + return aggressive ? gcOk : YAFFS_OK;
10257 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10258 - int nBytes, int writeThrough)
10260 + * yaffs_BackgroundGarbageCollect()
10261 + * Garbage collects. Intended to be called from a background thread.
10262 + * Returns non-zero if at least half the free chunks are erased.
10264 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency)
10266 + int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10273 - int nToWriteBack;
10274 - int startOfWrite = offset;
10275 - int chunkWritten = 0;
10276 - __u32 nBytesRead;
10277 - __u32 chunkStart;
10278 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10280 - yaffs_Device *dev;
10281 + yaffs_CheckGarbageCollection(dev, 1);
10282 + return erasedChunks > dev->nFreeChunks/2;
10286 +/*------------------------- TAGS --------------------------------*/
10288 - while (n > 0 && chunkWritten >= 0) {
10289 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10290 - /* start = offset % dev->nDataBytesPerChunk; */
10291 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10292 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
10293 + int chunkInObject)
10295 + return (tags->chunkId == chunkInObject &&
10296 + tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
10298 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10299 - start >= dev->nDataBytesPerChunk) {
10300 - T(YAFFS_TRACE_ERROR, (
10301 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10303 - (int)offset, chunk, start));
10308 - /* OK now check for the curveball where the start and end are in
10309 - * the same chunk.
10312 - if ((start + n) < dev->nDataBytesPerChunk) {
10314 +/*-------------------- Data file manipulation -----------------*/
10316 - /* Now folks, to calculate how many bytes to write back....
10317 - * If we're overwriting and not writing to then end of file then
10318 - * we need to write back as much as was there before.
10320 +static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
10321 + yaffs_ExtendedTags *tags)
10323 + /*Get the Tnode, then get the level 0 offset chunk offset */
10325 + int theChunk = -1;
10326 + yaffs_ExtendedTags localTags;
10329 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10330 + yaffs_Device *dev = in->myDev;
10332 - if (chunkStart > in->variant.fileVariant.fileSize)
10333 - nBytesRead = 0; /* Past end of file */
10335 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10337 + /* Passed a NULL, so use our own tags space */
10338 + tags = &localTags;
10341 - if (nBytesRead > dev->nDataBytesPerChunk)
10342 - nBytesRead = dev->nDataBytesPerChunk;
10343 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10347 - (start + n)) ? nBytesRead : (start + n);
10349 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10351 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10354 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10361 - nToCopy = dev->nDataBytesPerChunk - start;
10362 - nToWriteBack = dev->nDataBytesPerChunk;
10364 +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
10365 + yaffs_ExtendedTags *tags)
10367 + /* Get the Tnode, then get the level 0 offset chunk offset */
10369 + int theChunk = -1;
10370 + yaffs_ExtendedTags localTags;
10372 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10373 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10374 - * or we're using inband tags, so we want to use the cache buffers.
10376 - if (dev->nShortOpCaches > 0) {
10377 - yaffs_ChunkCache *cache;
10378 - /* If we can't find the data in the cache, then load the cache */
10379 - cache = yaffs_FindChunkCache(in, chunk);
10380 + yaffs_Device *dev = in->myDev;
10384 - && yaffs_CheckSpaceForAllocation(in->
10386 - cache = yaffs_GrabChunkCache(in->myDev);
10387 - cache->object = in;
10388 - cache->chunkId = chunk;
10389 - cache->dirty = 0;
10390 - cache->locked = 0;
10391 - yaffs_ReadChunkDataFromObject(in, chunk,
10394 - } else if (cache &&
10396 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10397 - /* Drop the cache if it was a read cache item and
10398 - * no space check has been made for it.
10403 + /* Passed a NULL, so use our own tags space */
10404 + tags = &localTags;
10408 - yaffs_UseChunkCache(dev, cache, 1);
10409 - cache->locked = 1;
10410 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10414 - memcpy(&cache->data[start], buffer,
10416 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10419 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10422 - cache->locked = 0;
10423 - cache->nBytes = nToWriteBack;
10424 + /* Delete the entry in the filestructure (if found) */
10425 + if (retVal != -1)
10426 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
10429 - if (writeThrough) {
10431 - yaffs_WriteChunkDataToObject
10434 - cache->data, cache->nBytes,
10436 - cache->dirty = 0;
10442 - chunkWritten = -1; /* fail the write */
10445 - /* An incomplete start or end chunk (or maybe both start and end chunk)
10446 - * Read into the local buffer then copy, then copy over and write back.
10449 - __u8 *localBuffer =
10450 - yaffs_GetTempBuffer(dev, __LINE__);
10451 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
10452 + int chunkInNAND, int inScan)
10454 + /* NB inScan is zero unless scanning.
10455 + * For forward scanning, inScan is > 0;
10456 + * for backward scanning inScan is < 0
10458 + * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
10462 + yaffs_Device *dev = in->myDev;
10463 + int existingChunk;
10464 + yaffs_ExtendedTags existingTags;
10465 + yaffs_ExtendedTags newTags;
10466 + unsigned existingSerial, newSerial;
10468 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
10469 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
10470 + * If it is not during Scanning then something went wrong!
10473 + T(YAFFS_TRACE_ERROR,
10475 + ("yaffs tragedy:attempt to put data chunk into a non-file"
10480 - yaffs_ReadChunkDataFromObject(in, chunk,
10482 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
10486 + tn = yaffs_AddOrFindLevel0Tnode(dev,
10487 + &in->variant.fileVariant,
10491 + return YAFFS_FAIL;
10494 + /* Dummy insert, bail now */
10497 + existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10499 - memcpy(&localBuffer[start], buffer, nToCopy);
10500 + if (inScan != 0) {
10501 + /* If we're scanning then we need to test for duplicates
10502 + * NB This does not need to be efficient since it should only ever
10503 + * happen when the power fails during a write, then only one
10504 + * chunk should ever be affected.
10506 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
10507 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
10511 - yaffs_WriteChunkDataToObject(in, chunk,
10515 + if (existingChunk > 0) {
10516 + /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1
10517 + * thus we have to do a FindChunkInFile to get the real chunk id.
10519 + * We have a duplicate now we need to decide which one to use:
10521 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
10522 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
10523 + * YAFFS1: Get both sets of tags and compare serial numbers.
10526 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10528 + if (inScan > 0) {
10529 + /* Only do this for forward scanning */
10530 + yaffs_ReadChunkWithTagsFromNAND(dev,
10534 + /* Do a proper find */
10536 + yaffs_FindChunkInFile(in, chunkInInode,
10541 - /* A full chunk. Write directly from the supplied buffer. */
10542 + if (existingChunk <= 0) {
10543 + /*Hoosterman - how did this happen? */
10545 + T(YAFFS_TRACE_ERROR,
10547 + ("yaffs tragedy: existing chunk < 0 in scan"
10553 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
10554 - dev->nDataBytesPerChunk,
10556 + /* NB The deleted flags should be false, otherwise the chunks will
10557 + * not be loaded during a scan
10560 - /* Since we've overwritten the cached data, we better invalidate it. */
10561 - yaffs_InvalidateChunkCache(in, chunk);
10563 + if (inScan > 0) {
10564 + newSerial = newTags.serialNumber;
10565 + existingSerial = existingTags.serialNumber;
10568 - if (chunkWritten >= 0) {
10570 - offset += nToCopy;
10571 - buffer += nToCopy;
10572 - nDone += nToCopy;
10573 + if ((inScan > 0) &&
10574 + (existingChunk <= 0 ||
10575 + ((existingSerial + 1) & 3) == newSerial)) {
10576 + /* Forward scanning.
10578 + * Delete the old one and drop through to update the tnode
10580 + yaffs_DeleteChunk(dev, existingChunk, 1,
10583 + /* Backward scanning or we want to use the existing one
10585 + * Delete the new one and return early so that the tnode isn't changed
10587 + yaffs_DeleteChunk(dev, chunkInNAND, 1,
10595 - /* Update file object */
10597 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
10598 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
10599 + if (existingChunk == 0)
10600 + in->nDataChunks++;
10603 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
10609 +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
10612 + int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
10614 -/* ---------------------- File resizing stuff ------------------ */
10615 + if (chunkInNAND >= 0)
10616 + return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
10619 + T(YAFFS_TRACE_NANDACCESS,
10620 + (TSTR("Chunk %d not found zero instead" TENDSTR),
10622 + /* get sane (zero) data if you read a hole */
10623 + memset(buffer, 0, in->myDev->nDataBytesPerChunk);
10627 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
10631 - yaffs_Device *dev = in->myDev;
10632 - int oldFileSize = in->variant.fileVariant.fileSize;
10633 +void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
10637 + yaffs_ExtendedTags tags;
10638 + yaffs_BlockInfo *bi;
10640 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
10641 + if (chunkId <= 0)
10644 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
10645 - dev->nDataBytesPerChunk;
10648 + dev->nDeletions++;
10649 + block = chunkId / dev->param.nChunksPerBlock;
10650 + page = chunkId % dev->param.nChunksPerBlock;
10652 - /* Delete backwards so that we don't end up with holes if
10653 - * power is lost part-way through the operation.
10655 - for (i = lastDel; i >= startDel; i--) {
10656 - /* NB this could be optimised somewhat,
10657 - * eg. could retrieve the tags and write them without
10658 - * using yaffs_DeleteChunk
10661 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
10662 - if (chunkId > 0) {
10664 - (dev->internalStartBlock * dev->nChunksPerBlock)
10666 - ((dev->internalEndBlock +
10667 - 1) * dev->nChunksPerBlock)) {
10668 - T(YAFFS_TRACE_ALWAYS,
10669 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
10672 - in->nDataChunks--;
10673 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
10677 + if (!yaffs_CheckChunkBit(dev, block, page))
10678 + T(YAFFS_TRACE_VERIFY,
10679 + (TSTR("Deleting invalid chunk %d"TENDSTR),
10683 + bi = yaffs_GetBlockInfo(dev, block);
10685 + yaffs2_UpdateOldestDirtySequence(dev, block, bi);
10687 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
10689 + T(YAFFS_TRACE_DELETION,
10690 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
10692 - int oldFileSize = in->variant.fileVariant.fileSize;
10693 - __u32 newSizeOfPartialChunk;
10694 - int newFullChunks;
10695 + if (!dev->param.isYaffs2 && markNAND &&
10696 + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
10698 - yaffs_Device *dev = in->myDev;
10699 + yaffs_InitialiseTags(&tags);
10701 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
10702 + tags.chunkDeleted = 1;
10704 - yaffs_FlushFilesChunkCache(in);
10705 - yaffs_InvalidateWholeChunkCache(in);
10706 + yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
10707 + yaffs_HandleUpdateChunk(dev, chunkId, &tags);
10709 + dev->nUnmarkedDeletions++;
10712 - yaffs_CheckGarbageCollection(dev);
10713 + /* Pull out of the management area.
10714 + * If the whole block became dirty, this will kick off an erasure.
10716 + if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
10717 + bi->blockState == YAFFS_BLOCK_STATE_FULL ||
10718 + bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
10719 + bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
10720 + dev->nFreeChunks++;
10722 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
10723 - return YAFFS_FAIL;
10724 + yaffs_ClearChunkBit(dev, block, page);
10726 - if (newSize == oldFileSize)
10728 + bi->pagesInUse--;
10730 - if (newSize < oldFileSize) {
10731 + if (bi->pagesInUse == 0 &&
10732 + !bi->hasShrinkHeader &&
10733 + bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
10734 + bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
10735 + yaffs_BlockBecameDirty(dev, block);
10738 - yaffs_PruneResizedChunks(in, newSize);
10741 - if (newSizeOfPartialChunk != 0) {
10742 - int lastChunk = 1 + newFullChunks;
10745 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
10746 +static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
10747 + const __u8 *buffer, int nBytes,
10750 + /* Find old chunk Need to do this to get serial number
10751 + * Write new one and patch into tree.
10752 + * Invalidate old tags.
10755 - /* Got to read and rewrite the last chunk with its new size and zero pad */
10756 - yaffs_ReadChunkDataFromObject(in, lastChunk,
10759 + yaffs_ExtendedTags prevTags;
10761 - memset(localBuffer + newSizeOfPartialChunk, 0,
10762 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
10764 + yaffs_ExtendedTags newTags;
10766 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
10767 - newSizeOfPartialChunk, 1);
10768 + yaffs_Device *dev = in->myDev;
10770 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
10772 + yaffs_CheckGarbageCollection(dev,0);
10774 - in->variant.fileVariant.fileSize = newSize;
10775 + /* Get the previous chunk at this location in the file if it exists.
10776 + * If it does not exist then put a zero into the tree. This creates
10777 + * the tnode now, rather than later when it is harder to clean up.
10779 + prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
10780 + if(prevChunkId < 1 &&
10781 + !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0))
10784 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
10786 - /* newsSize > oldFileSize */
10787 - in->variant.fileVariant.fileSize = newSize;
10789 + /* Set up new tags */
10790 + yaffs_InitialiseTags(&newTags);
10792 + newTags.chunkId = chunkInInode;
10793 + newTags.objectId = in->objectId;
10794 + newTags.serialNumber =
10795 + (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
10796 + newTags.byteCount = nBytes;
10798 - /* Write a new object header.
10799 - * show we've shrunk the file, if need be
10800 - * Do this only if the file is not in the deleted directories.
10802 - if (in->parent &&
10803 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
10804 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
10805 - yaffs_UpdateObjectHeader(in, NULL, 0,
10806 - (newSize < oldFileSize) ? 1 : 0, 0);
10807 + if (nBytes < 1 || nBytes > dev->param.totalBytesPerChunk) {
10808 + T(YAFFS_TRACE_ERROR,
10809 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
10815 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
10820 + if (newChunkId > 0) {
10821 + yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
10823 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
10825 - obj = yaffs_GetEquivalentObject(obj);
10826 + if (prevChunkId > 0)
10827 + yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
10829 - switch (obj->variantType) {
10830 - case YAFFS_OBJECT_TYPE_FILE:
10831 - return obj->variant.fileVariant.fileSize;
10832 - case YAFFS_OBJECT_TYPE_SYMLINK:
10833 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
10836 + yaffs_VerifyFileSanity(in);
10838 + return newChunkId;
10842 +/* UpdateObjectHeader updates the header on NAND for an object.
10843 + * If name is not NULL, then that new name is used.
10845 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
10846 + int isShrink, int shadows, yaffs_XAttrMod *xmod)
10849 + yaffs_BlockInfo *bi;
10851 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
10855 - yaffs_FlushFilesChunkCache(in);
10856 - if (updateTime) {
10857 -#ifdef CONFIG_YAFFS_WINCE
10858 - yfsd_WinFileTimeNow(in->win_mtime);
10860 + yaffs_Device *dev = in->myDev;
10862 - in->yst_mtime = Y_CURRENT_TIME;
10870 + yaffs_ExtendedTags newTags;
10871 + yaffs_ExtendedTags oldTags;
10872 + const YCHAR *alias = NULL;
10874 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
10875 - 0) ? YAFFS_OK : YAFFS_FAIL;
10877 - retVal = YAFFS_OK;
10879 + __u8 *buffer = NULL;
10880 + YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
10883 + yaffs_ObjectHeader *oh = NULL;
10886 + yaffs_strcpy(oldName, _Y("silly old name"));
10888 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
10891 - /* First off, invalidate the file's data in the cache, without flushing. */
10892 - yaffs_InvalidateWholeChunkCache(in);
10894 + in == dev->rootDir || /* The rootDir should also be saved */
10897 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
10898 - /* Move to the unlinked directory so we have a record that it was deleted. */
10899 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
10900 + yaffs_CheckGarbageCollection(dev,0);
10901 + yaffs_CheckObjectDetailsLoaded(in);
10904 + buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
10905 + oh = (yaffs_ObjectHeader *) buffer;
10907 - yaffs_RemoveObjectFromDirectory(in);
10908 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
10909 - in->hdrChunk = 0;
10910 + prevChunkId = in->hdrChunk;
10912 - yaffs_FreeObject(in);
10914 + if (prevChunkId > 0) {
10915 + result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
10916 + buffer, &oldTags);
10919 + yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
10921 -/* yaffs_DeleteFile deletes the whole file data
10922 - * and the inode associated with the file.
10923 - * It does not delete the links associated with the file.
10925 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
10927 + memcpy(oldName, oh->name, sizeof(oh->name));
10928 + memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader));
10930 + memset(buffer, 0xFF, dev->nDataBytesPerChunk);
10933 - int immediateDeletion = 0;
10934 + oh->type = in->variantType;
10935 + oh->yst_mode = in->yst_mode;
10936 + oh->shadowsObject = oh->inbandShadowsObject = shadows;
10939 - if (!in->myInode)
10940 - immediateDeletion = 1;
10941 +#ifdef CONFIG_YAFFS_WINCE
10942 + oh->win_atime[0] = in->win_atime[0];
10943 + oh->win_ctime[0] = in->win_ctime[0];
10944 + oh->win_mtime[0] = in->win_mtime[0];
10945 + oh->win_atime[1] = in->win_atime[1];
10946 + oh->win_ctime[1] = in->win_ctime[1];
10947 + oh->win_mtime[1] = in->win_mtime[1];
10949 - if (in->inUse <= 0)
10950 - immediateDeletion = 1;
10951 + oh->yst_uid = in->yst_uid;
10952 + oh->yst_gid = in->yst_gid;
10953 + oh->yst_atime = in->yst_atime;
10954 + oh->yst_mtime = in->yst_mtime;
10955 + oh->yst_ctime = in->yst_ctime;
10956 + oh->yst_rdev = in->yst_rdev;
10959 + oh->parentObjectId = in->parent->objectId;
10961 + oh->parentObjectId = 0;
10963 - if (immediateDeletion) {
10965 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
10966 - _Y("deleted"), 0, 0);
10967 - T(YAFFS_TRACE_TRACING,
10968 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
10971 - in->myDev->nDeletedFiles++;
10972 - if (1 || in->myDev->isYaffs2)
10973 - yaffs_ResizeFile(in, 0);
10974 - yaffs_SoftDeleteFile(in);
10977 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
10978 - _Y("unlinked"), 0, 0);
10980 + if (name && *name) {
10981 + memset(oh->name, 0, sizeof(oh->name));
10982 + yaffs_LoadObjectHeaderFromName(dev,oh->name,name);
10983 + } else if (prevChunkId > 0)
10984 + memcpy(oh->name, oldName, sizeof(oh->name));
10986 + memset(oh->name, 0, sizeof(oh->name));
10988 + oh->isShrink = isShrink;
10992 + switch (in->variantType) {
10993 + case YAFFS_OBJECT_TYPE_UNKNOWN:
10994 + /* Should not happen */
10996 + case YAFFS_OBJECT_TYPE_FILE:
10998 + (oh->parentObjectId == YAFFS_OBJECTID_DELETED
10999 + || oh->parentObjectId ==
11000 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
11001 + fileVariant.fileSize;
11003 + case YAFFS_OBJECT_TYPE_HARDLINK:
11004 + oh->equivalentObjectId =
11005 + in->variant.hardLinkVariant.equivalentObjectId;
11007 + case YAFFS_OBJECT_TYPE_SPECIAL:
11010 + case YAFFS_OBJECT_TYPE_DIRECTORY:
11013 + case YAFFS_OBJECT_TYPE_SYMLINK:
11014 + alias = in->variant.symLinkVariant.alias;
11016 + alias = _Y("no alias");
11017 + yaffs_strncpy(oh->alias,
11019 + YAFFS_MAX_ALIAS_LENGTH);
11020 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11024 -int yaffs_DeleteFile(yaffs_Object *in)
11026 - int retVal = YAFFS_OK;
11027 - int deleted = in->deleted;
11028 + /* process any xattrib modifications */
11030 + yaffs_ApplyXMod(in, (char *)buffer, xmod);
11032 - yaffs_ResizeFile(in, 0);
11034 - if (in->nDataChunks > 0) {
11035 - /* Use soft deletion if there is data in the file.
11036 - * That won't be the case if it has been resized to zero.
11038 - if (!in->unlinked)
11039 - retVal = yaffs_UnlinkFileIfNeeded(in);
11041 + yaffs_InitialiseTags(&newTags);
11043 + newTags.chunkId = 0;
11044 + newTags.objectId = in->objectId;
11045 + newTags.serialNumber = in->serial;
11047 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11050 - in->myDev->nDeletedFiles++;
11051 - yaffs_SoftDeleteFile(in);
11053 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11055 - /* The file has no data chunks so we toss it immediately */
11056 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11057 - in->variant.fileVariant.top = NULL;
11058 - yaffs_DoGenericObjectDeletion(in);
11059 + /* Add extra info for file header */
11064 + newTags.extraHeaderInfoAvailable = 1;
11065 + newTags.extraParentObjectId = oh->parentObjectId;
11066 + newTags.extraFileLength = oh->fileSize;
11067 + newTags.extraIsShrinkHeader = oh->isShrink;
11068 + newTags.extraEquivalentObjectId = oh->equivalentObjectId;
11069 + newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
11070 + newTags.extraObjectType = in->variantType;
11072 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11074 - /* First check that the directory is empty. */
11075 - if (ylist_empty(&in->variant.directoryVariant.children))
11076 - return yaffs_DoGenericObjectDeletion(in);
11077 + yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
11079 - return YAFFS_FAIL;
11080 + /* Create new chunk in NAND */
11082 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
11083 + (prevChunkId > 0) ? 1 : 0);
11086 + if (newChunkId >= 0) {
11088 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11090 - YFREE(in->variant.symLinkVariant.alias);
11091 + in->hdrChunk = newChunkId;
11093 - return yaffs_DoGenericObjectDeletion(in);
11095 + if (prevChunkId > 0) {
11096 + yaffs_DeleteChunk(dev, prevChunkId, 1,
11100 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11102 - /* remove this hardlink from the list assocaited with the equivalent
11105 - ylist_del_init(&in->hardLinks);
11106 - return yaffs_DoGenericObjectDeletion(in);
11108 + if (!yaffs_ObjectHasCachedWriteData(in))
11111 + /* If this was a shrink, then mark the block that the chunk lives on */
11113 + bi = yaffs_GetBlockInfo(in->myDev,
11114 + newChunkId / in->myDev->param.nChunksPerBlock);
11115 + bi->hasShrinkHeader = 1;
11120 + retVal = newChunkId;
11122 -int yaffs_DeleteObject(yaffs_Object *obj)
11125 - switch (obj->variantType) {
11126 - case YAFFS_OBJECT_TYPE_FILE:
11127 - retVal = yaffs_DeleteFile(obj);
11129 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11130 - return yaffs_DeleteDirectory(obj);
11132 - case YAFFS_OBJECT_TYPE_SYMLINK:
11133 - retVal = yaffs_DeleteSymLink(obj);
11135 - case YAFFS_OBJECT_TYPE_HARDLINK:
11136 - retVal = yaffs_DeleteHardLink(obj);
11138 - case YAFFS_OBJECT_TYPE_SPECIAL:
11139 - retVal = yaffs_DoGenericObjectDeletion(obj);
11141 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11143 - break; /* should not happen. */
11147 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
11152 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11153 +/*------------------------ Short Operations Cache ----------------------------------------
11154 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11155 + * reads might be short sequential reads, and a lot of writes may be short
11156 + * sequential writes. eg. scanning/writing a jpeg file.
11157 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11158 + * with dumb-as-a-rock code.
11159 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11162 + * There are a limited number (~10) of cache chunks per device so that we don't
11163 + * need a very intelligent search.
11166 +static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
11168 + yaffs_Device *dev = obj->myDev;
11170 + yaffs_ChunkCache *cache;
11171 + int nCaches = obj->myDev->param.nShortOpCaches;
11173 - int immediateDeletion = 0;
11174 + for (i = 0; i < nCaches; i++) {
11175 + cache = &dev->srCache[i];
11176 + if (cache->object == obj &&
11182 - if (!obj->myInode)
11183 - immediateDeletion = 1;
11185 - if (obj->inUse <= 0)
11186 - immediateDeletion = 1;
11191 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11192 - return yaffs_DeleteHardLink(obj);
11193 - } else if (!ylist_empty(&obj->hardLinks)) {
11194 - /* Curve ball: We're unlinking an object that has a hardlink.
11196 - * This problem arises because we are not strictly following
11197 - * The Linux link/inode model.
11199 - * We can't really delete the object.
11200 - * Instead, we do the following:
11201 - * - Select a hardlink.
11202 - * - Unhook it from the hard links
11203 - * - Unhook it from its parent directory (so that the rename can work)
11204 - * - Rename the object to the hardlink's name.
11205 - * - Delete the hardlink
11208 - yaffs_Object *hl;
11210 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11211 +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
11213 + yaffs_Device *dev = obj->myDev;
11214 + int lowest = -99; /* Stop compiler whining. */
11216 + yaffs_ChunkCache *cache;
11217 + int chunkWritten = 0;
11218 + int nCaches = obj->myDev->param.nShortOpCaches;
11220 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11221 + if (nCaches > 0) {
11225 - ylist_del_init(&hl->hardLinks);
11226 - ylist_del_init(&hl->siblings);
11227 + /* Find the dirty cache for this object with the lowest chunk id. */
11228 + for (i = 0; i < nCaches; i++) {
11229 + if (dev->srCache[i].object == obj &&
11230 + dev->srCache[i].dirty) {
11232 + || dev->srCache[i].chunkId <
11234 + cache = &dev->srCache[i];
11235 + lowest = cache->chunkId;
11240 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11241 + if (cache && !cache->locked) {
11242 + /* Write it out and free it up */
11244 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11246 + yaffs_WriteChunkDataToObject(cache->object,
11251 + cache->dirty = 0;
11252 + cache->object = NULL;
11255 - if (retVal == YAFFS_OK)
11256 - retVal = yaffs_DoGenericObjectDeletion(hl);
11257 + } while (cache && chunkWritten > 0);
11261 + /* Hoosterman, disk full while writing cache out. */
11262 + T(YAFFS_TRACE_ERROR,
11263 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11265 - } else if (immediateDeletion) {
11266 - switch (obj->variantType) {
11267 - case YAFFS_OBJECT_TYPE_FILE:
11268 - return yaffs_DeleteFile(obj);
11270 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11271 - return yaffs_DeleteDirectory(obj);
11273 - case YAFFS_OBJECT_TYPE_SYMLINK:
11274 - return yaffs_DeleteSymLink(obj);
11276 - case YAFFS_OBJECT_TYPE_SPECIAL:
11277 - return yaffs_DoGenericObjectDeletion(obj);
11279 - case YAFFS_OBJECT_TYPE_HARDLINK:
11280 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11282 - return YAFFS_FAIL;
11285 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11286 - _Y("unlinked"), 0, 0);
11291 +/*yaffs_FlushEntireDeviceCache(dev)
11296 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11297 +void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
11299 + yaffs_Object *obj;
11300 + int nCaches = dev->param.nShortOpCaches;
11303 - if (obj && obj->unlinkAllowed)
11304 - return yaffs_UnlinkWorker(obj);
11305 + /* Find a dirty object in the cache and flush it...
11306 + * until there are no further dirty objects.
11310 + for (i = 0; i < nCaches && !obj; i++) {
11311 + if (dev->srCache[i].object &&
11312 + dev->srCache[i].dirty)
11313 + obj = dev->srCache[i].object;
11315 - return YAFFS_FAIL;
11318 + yaffs_FlushFilesChunkCache(obj);
11323 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11326 +/* Grab us a cache chunk for use.
11327 + * First look for an empty one.
11328 + * Then look for the least recently used non-dirty one.
11329 + * Then look for the least recently used dirty one...., flush and look again.
11331 +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
11333 - yaffs_Object *obj;
11336 - obj = yaffs_FindObjectByName(dir, name);
11337 - return yaffs_UnlinkObject(obj);
11339 + if (dev->param.nShortOpCaches > 0) {
11340 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11341 + if (!dev->srCache[i].object)
11342 + return &dev->srCache[i];
11346 -/*----------------------- Initialisation Scanning ---------------------- */
11350 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11351 - int backwardScanning)
11352 +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
11354 - yaffs_Object *obj;
11355 + yaffs_ChunkCache *cache;
11356 + yaffs_Object *theObj;
11361 - if (!backwardScanning) {
11362 - /* Handle YAFFS1 forward scanning case
11363 - * For YAFFS1 we always do the deletion
11365 + if (dev->param.nShortOpCaches > 0) {
11366 + /* Try find a non-dirty one... */
11369 - /* Handle YAFFS2 case (backward scanning)
11370 - * If the shadowed object exists then ignore.
11372 - if (yaffs_FindObjectByNumber(dev, objId))
11375 + cache = yaffs_GrabChunkCacheWorker(dev);
11377 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11378 - * We put it in unlinked dir to be cleaned up after the scanning
11381 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11382 - YAFFS_OBJECT_TYPE_FILE);
11385 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11386 - obj->variant.fileVariant.shrinkSize = 0;
11387 - obj->valid = 1; /* So that we don't read any other info for this file */
11389 + /* They were all dirty, find the last recently used object and flush
11390 + * its cache, then find again.
11391 + * NB what's here is not very accurate, we actually flush the object
11392 + * the last recently used page.
11396 + /* With locking we can't assume we can use entry zero */
11401 -} yaffs_BlockIndex;
11407 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11408 + if (dev->srCache[i].object &&
11409 + !dev->srCache[i].locked &&
11410 + (dev->srCache[i].lastUse < usage || !cache)) {
11411 + usage = dev->srCache[i].lastUse;
11412 + theObj = dev->srCache[i].object;
11413 + cache = &dev->srCache[i];
11418 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
11420 - yaffs_Object *hl;
11421 - yaffs_Object *in;
11422 + if (!cache || cache->dirty) {
11423 + /* Flush and try again */
11424 + yaffs_FlushFilesChunkCache(theObj);
11425 + cache = yaffs_GrabChunkCacheWorker(dev);
11428 - while (hardList) {
11430 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
11436 - in = yaffs_FindObjectByNumber(dev,
11437 - hl->variant.hardLinkVariant.
11438 - equivalentObjectId);
11442 - /* Add the hardlink pointers */
11443 - hl->variant.hardLinkVariant.equivalentObject = in;
11444 - ylist_add(&hl->hardLinks, &in->hardLinks);
11446 - /* Todo Need to report/handle this better.
11447 - * Got a problem... hardlink to a non-existant object
11449 - hl->variant.hardLinkVariant.equivalentObject = NULL;
11450 - YINIT_LIST_HEAD(&hl->hardLinks);
11451 +/* Find a cached chunk */
11452 +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
11455 + yaffs_Device *dev = obj->myDev;
11457 + if (dev->param.nShortOpCaches > 0) {
11458 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11459 + if (dev->srCache[i].object == obj &&
11460 + dev->srCache[i].chunkId == chunkId) {
11461 + dev->cacheHits++;
11463 + return &dev->srCache[i];
11470 +/* Mark the chunk for the least recently used algorithym */
11471 +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
11475 + if (dev->param.nShortOpCaches > 0) {
11476 + if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
11477 + /* Reset the cache usages */
11479 + for (i = 1; i < dev->param.nShortOpCaches; i++)
11480 + dev->srCache[i].lastUse = 0;
11482 + dev->srLastUse = 0;
11485 + dev->srLastUse++;
11487 + cache->lastUse = dev->srLastUse;
11489 -static int ybicmp(const void *a, const void *b)
11491 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
11492 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
11493 - register int ablock = ((yaffs_BlockIndex *)a)->block;
11494 - register int bblock = ((yaffs_BlockIndex *)b)->block;
11495 - if (aseq == bseq)
11496 - return ablock - bblock;
11498 - return aseq - bseq;
11500 + cache->dirty = 1;
11504 +/* Invalidate a single cache page.
11505 + * Do this when a whole page gets written,
11506 + * ie the short cache for this page is no longer valid.
11508 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
11510 + if (object->myDev->param.nShortOpCaches > 0) {
11511 + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
11513 -struct yaffs_ShadowFixerStruct {
11516 - struct yaffs_ShadowFixerStruct *next;
11520 + cache->object = NULL;
11524 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
11525 +/* Invalidate all the cache pages associated with this object
11526 + * Do this whenever ther file is deleted or resized.
11528 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
11531 - * Sort out state of unlinked and deleted objects after scanning.
11533 - struct ylist_head *i;
11534 - struct ylist_head *n;
11537 + yaffs_Device *dev = in->myDev;
11539 - /* Soft delete all the unlinked files */
11540 - ylist_for_each_safe(i, n,
11541 - &dev->unlinkedDir->variant.directoryVariant.children) {
11543 - l = ylist_entry(i, yaffs_Object, siblings);
11544 - yaffs_DeleteObject(l);
11545 + if (dev->param.nShortOpCaches > 0) {
11546 + /* Invalidate it. */
11547 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11548 + if (dev->srCache[i].object == in)
11549 + dev->srCache[i].object = NULL;
11554 - ylist_for_each_safe(i, n,
11555 - &dev->deletedDir->variant.directoryVariant.children) {
11557 - l = ylist_entry(i, yaffs_Object, siblings);
11558 - yaffs_DeleteObject(l);
11563 +/*--------------------- File read/write ------------------------
11564 + * Read and write have very similar structures.
11565 + * In general the read/write has three parts to it
11566 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
11567 + * Some complete chunks
11568 + * An incomplete chunk to end off with
11570 + * Curve-balls: the first chunk might also be the last chunk.
11573 -static int yaffs_Scan(yaffs_Device *dev)
11574 +int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
11577 - yaffs_ExtendedTags tags;
11579 - int blockIterator;
11580 - int startIterator;
11587 - yaffs_BlockState state;
11588 - yaffs_Object *hardList = NULL;
11589 - yaffs_BlockInfo *bi;
11590 - __u32 sequenceNumber;
11591 - yaffs_ObjectHeader *oh;
11592 - yaffs_Object *in;
11593 - yaffs_Object *parent;
11595 - int alloc_failed = 0;
11600 + yaffs_ChunkCache *cache;
11602 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
11603 + yaffs_Device *dev;
11609 + /* chunk = offset / dev->nDataBytesPerChunk + 1; */
11610 + /* start = offset % dev->nDataBytesPerChunk; */
11611 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11614 + /* OK now check for the curveball where the start and end are in
11615 + * the same chunk.
11617 + if ((start + n) < dev->nDataBytesPerChunk)
11620 + nToCopy = dev->nDataBytesPerChunk - start;
11622 + cache = yaffs_FindChunkCache(in, chunk);
11624 - T(YAFFS_TRACE_SCAN,
11625 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
11626 - dev->internalStartBlock, dev->internalEndBlock));
11628 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
11630 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
11632 - /* Scan all the blocks to determine their state */
11633 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
11634 - bi = yaffs_GetBlockInfo(dev, blk);
11635 - yaffs_ClearChunkBits(dev, blk);
11636 - bi->pagesInUse = 0;
11637 - bi->softDeletions = 0;
11638 + /* If the chunk is already in the cache or it is less than a whole chunk
11639 + * or we're using inband tags then use the cache (if there is caching)
11640 + * else bypass the cache.
11642 + if (cache || nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11643 + if (dev->param.nShortOpCaches > 0) {
11645 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
11646 + /* If we can't find the data in the cache, then load it up. */
11648 - bi->blockState = state;
11649 - bi->sequenceNumber = sequenceNumber;
11651 + cache = yaffs_GrabChunkCache(in->myDev);
11652 + cache->object = in;
11653 + cache->chunkId = chunk;
11654 + cache->dirty = 0;
11655 + cache->locked = 0;
11656 + yaffs_ReadChunkDataFromObject(in, chunk,
11659 + cache->nBytes = 0;
11662 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
11663 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
11664 + yaffs_UseChunkCache(dev, cache, 0);
11666 - T(YAFFS_TRACE_SCAN_DEBUG,
11667 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
11668 - state, sequenceNumber));
11669 + cache->locked = 1;
11671 - if (state == YAFFS_BLOCK_STATE_DEAD) {
11672 - T(YAFFS_TRACE_BAD_BLOCKS,
11673 - (TSTR("block %d is bad" TENDSTR), blk));
11674 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
11675 - T(YAFFS_TRACE_SCAN_DEBUG,
11676 - (TSTR("Block empty " TENDSTR)));
11677 - dev->nErasedBlocks++;
11678 - dev->nFreeChunks += dev->nChunksPerBlock;
11682 - startIterator = dev->internalStartBlock;
11683 - endIterator = dev->internalEndBlock;
11684 + memcpy(buffer, &cache->data[start], nToCopy);
11686 - /* For each block.... */
11687 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
11688 - blockIterator++) {
11689 + cache->locked = 0;
11691 + /* Read into the local buffer then copy..*/
11694 + __u8 *localBuffer =
11695 + yaffs_GetTempBuffer(dev, __LINE__);
11696 + yaffs_ReadChunkDataFromObject(in, chunk,
11700 + memcpy(buffer, &localBuffer[start], nToCopy);
11702 - blk = blockIterator;
11704 - bi = yaffs_GetBlockInfo(dev, blk);
11705 - state = bi->blockState;
11706 + yaffs_ReleaseTempBuffer(dev, localBuffer,
11713 - /* For each chunk in each block that needs scanning....*/
11714 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
11715 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
11716 - /* Read the tags and decide what to do */
11717 - chunk = blk * dev->nChunksPerBlock + c;
11718 + /* A full chunk. Read directly into the supplied buffer. */
11719 + yaffs_ReadChunkDataFromObject(in, chunk, buffer);
11721 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
11725 - /* Let's have a good look at this chunk... */
11727 + offset += nToCopy;
11728 + buffer += nToCopy;
11729 + nDone += nToCopy;
11731 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
11732 - /* YAFFS1 only...
11733 - * A deleted chunk
11736 - dev->nFreeChunks++;
11737 - /*T((" %d %d deleted\n",blk,c)); */
11738 - } else if (!tags.chunkUsed) {
11739 - /* An unassigned chunk in the block
11740 - * This means that either the block is empty or
11741 - * this is the one being allocated from
11746 - /* We're looking at the first chunk in the block so the block is unused */
11747 - state = YAFFS_BLOCK_STATE_EMPTY;
11748 - dev->nErasedBlocks++;
11750 - /* this is the block being allocated from */
11751 - T(YAFFS_TRACE_SCAN,
11753 - (" Allocating from %d %d" TENDSTR),
11755 - state = YAFFS_BLOCK_STATE_ALLOCATING;
11756 - dev->allocationBlock = blk;
11757 - dev->allocationPage = c;
11758 - dev->allocationBlockFinder = blk;
11759 - /* Set it to here to encourage the allocator to go forth from here. */
11764 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
11765 + int nBytes, int writeThrough)
11768 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
11769 - } else if (tags.chunkId > 0) {
11770 - /* chunkId > 0 so it is a data chunk... */
11771 - unsigned int endpos;
11773 - yaffs_SetChunkBit(dev, blk, c);
11774 - bi->pagesInUse++;
11776 - in = yaffs_FindOrCreateObjectByNumber(dev,
11779 - YAFFS_OBJECT_TYPE_FILE);
11780 - /* PutChunkIntoFile checks for a clash (two data chunks with
11781 - * the same chunkId).
11788 + int nToWriteBack;
11789 + int startOfWrite = offset;
11790 + int chunkWritten = 0;
11791 + __u32 nBytesRead;
11792 + __u32 chunkStart;
11795 - alloc_failed = 1;
11796 + yaffs_Device *dev;
11799 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
11800 - alloc_failed = 1;
11805 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
11808 - in->variantType == YAFFS_OBJECT_TYPE_FILE
11809 - && in->variant.fileVariant.scannedFileSize <
11811 - in->variant.fileVariant.
11812 - scannedFileSize = endpos;
11813 - if (!dev->useHeaderFileSize) {
11814 - in->variant.fileVariant.
11816 - in->variant.fileVariant.
11819 + while (n > 0 && chunkWritten >= 0) {
11820 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11823 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
11825 - /* chunkId == 0, so it is an ObjectHeader.
11826 - * Thus, we read in the object header and make the object
11828 - yaffs_SetChunkBit(dev, blk, c);
11829 - bi->pagesInUse++;
11830 + if (chunk * dev->nDataBytesPerChunk + start != offset ||
11831 + start >= dev->nDataBytesPerChunk) {
11832 + T(YAFFS_TRACE_ERROR, (
11833 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
11835 + (int)offset, chunk, start));
11837 + chunk++; /* File pos to chunk in file offset */
11839 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
11843 - oh = (yaffs_ObjectHeader *) chunkData;
11845 - in = yaffs_FindObjectByNumber(dev,
11847 - if (in && in->variantType != oh->type) {
11848 - /* This should not happen, but somehow
11849 - * Wev'e ended up with an objectId that has been reused but not yet
11850 - * deleted, and worse still it has changed type. Delete the old object.
11852 + /* OK now check for the curveball where the start and end are in
11853 + * the same chunk.
11856 - yaffs_DeleteObject(in);
11857 + if ((start + n) < dev->nDataBytesPerChunk) {
11862 + /* Now folks, to calculate how many bytes to write back....
11863 + * If we're overwriting and not writing to then end of file then
11864 + * we need to write back as much as was there before.
11867 - in = yaffs_FindOrCreateObjectByNumber(dev,
11873 - alloc_failed = 1;
11875 - if (in && oh->shadowsObject > 0) {
11877 - struct yaffs_ShadowFixerStruct *fixer;
11878 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
11880 - fixer->next = shadowFixerList;
11881 - shadowFixerList = fixer;
11882 - fixer->objectId = tags.objectId;
11883 - fixer->shadowedId = oh->shadowsObject;
11885 + chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
11888 + if (chunkStart > in->variant.fileVariant.fileSize)
11889 + nBytesRead = 0; /* Past end of file */
11891 + nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
11893 - if (in && in->valid) {
11894 - /* We have already filled this one. We have a duplicate and need to resolve it. */
11895 + if (nBytesRead > dev->nDataBytesPerChunk)
11896 + nBytesRead = dev->nDataBytesPerChunk;
11898 - unsigned existingSerial = in->serial;
11899 - unsigned newSerial = tags.serialNumber;
11902 + (start + n)) ? nBytesRead : (start + n);
11904 - if (((existingSerial + 1) & 3) == newSerial) {
11905 - /* Use new one - destroy the exisiting one */
11906 - yaffs_DeleteChunk(dev,
11911 - /* Use existing - destroy this one. */
11912 - yaffs_DeleteChunk(dev, chunk, 1,
11916 + if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
11919 - if (in && !in->valid &&
11920 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
11921 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
11922 - /* We only load some info, don't fiddle with directory structure */
11924 - in->variantType = oh->type;
11926 + nToCopy = dev->nDataBytesPerChunk - start;
11927 + nToWriteBack = dev->nDataBytesPerChunk;
11930 - in->yst_mode = oh->yst_mode;
11931 -#ifdef CONFIG_YAFFS_WINCE
11932 - in->win_atime[0] = oh->win_atime[0];
11933 - in->win_ctime[0] = oh->win_ctime[0];
11934 - in->win_mtime[0] = oh->win_mtime[0];
11935 - in->win_atime[1] = oh->win_atime[1];
11936 - in->win_ctime[1] = oh->win_ctime[1];
11937 - in->win_mtime[1] = oh->win_mtime[1];
11939 - in->yst_uid = oh->yst_uid;
11940 - in->yst_gid = oh->yst_gid;
11941 - in->yst_atime = oh->yst_atime;
11942 - in->yst_mtime = oh->yst_mtime;
11943 - in->yst_ctime = oh->yst_ctime;
11944 - in->yst_rdev = oh->yst_rdev;
11946 - in->hdrChunk = chunk;
11947 - in->serial = tags.serialNumber;
11948 + if (nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11949 + /* An incomplete start or end chunk (or maybe both start and end chunk),
11950 + * or we're using inband tags, so we want to use the cache buffers.
11952 + if (dev->param.nShortOpCaches > 0) {
11953 + yaffs_ChunkCache *cache;
11954 + /* If we can't find the data in the cache, then load the cache */
11955 + cache = yaffs_FindChunkCache(in, chunk);
11957 - } else if (in && !in->valid) {
11958 - /* we need to load this info */
11960 + && yaffs_CheckSpaceForAllocation(dev, 1)) {
11961 + cache = yaffs_GrabChunkCache(dev);
11962 + cache->object = in;
11963 + cache->chunkId = chunk;
11964 + cache->dirty = 0;
11965 + cache->locked = 0;
11966 + yaffs_ReadChunkDataFromObject(in, chunk,
11968 + } else if (cache &&
11970 + !yaffs_CheckSpaceForAllocation(dev, 1)) {
11971 + /* Drop the cache if it was a read cache item and
11972 + * no space check has been made for it.
11978 - in->variantType = oh->type;
11980 + yaffs_UseChunkCache(dev, cache, 1);
11981 + cache->locked = 1;
11983 - in->yst_mode = oh->yst_mode;
11984 -#ifdef CONFIG_YAFFS_WINCE
11985 - in->win_atime[0] = oh->win_atime[0];
11986 - in->win_ctime[0] = oh->win_ctime[0];
11987 - in->win_mtime[0] = oh->win_mtime[0];
11988 - in->win_atime[1] = oh->win_atime[1];
11989 - in->win_ctime[1] = oh->win_ctime[1];
11990 - in->win_mtime[1] = oh->win_mtime[1];
11992 - in->yst_uid = oh->yst_uid;
11993 - in->yst_gid = oh->yst_gid;
11994 - in->yst_atime = oh->yst_atime;
11995 - in->yst_mtime = oh->yst_mtime;
11996 - in->yst_ctime = oh->yst_ctime;
11997 - in->yst_rdev = oh->yst_rdev;
11999 - in->hdrChunk = chunk;
12000 - in->serial = tags.serialNumber;
12002 - yaffs_SetObjectName(in, oh->name);
12004 + memcpy(&cache->data[start], buffer,
12007 - /* directory stuff...
12008 - * hook up to parent
12012 - yaffs_FindOrCreateObjectByNumber
12013 - (dev, oh->parentObjectId,
12014 - YAFFS_OBJECT_TYPE_DIRECTORY);
12016 - alloc_failed = 1;
12017 - if (parent && parent->variantType ==
12018 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12019 - /* Set up as a directory */
12020 - parent->variantType =
12021 - YAFFS_OBJECT_TYPE_DIRECTORY;
12022 - YINIT_LIST_HEAD(&parent->variant.
12023 - directoryVariant.
12025 - } else if (!parent || parent->variantType !=
12026 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12027 - /* Hoosterman, another problem....
12028 - * We're trying to use a non-directory as a directory
12030 + cache->locked = 0;
12031 + cache->nBytes = nToWriteBack;
12033 - T(YAFFS_TRACE_ERROR,
12035 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12037 - parent = dev->lostNFoundDir;
12038 + if (writeThrough) {
12040 + yaffs_WriteChunkDataToObject
12043 + cache->data, cache->nBytes,
12045 + cache->dirty = 0;
12048 - yaffs_AddObjectToDirectory(parent, in);
12050 + chunkWritten = -1; /* fail the write */
12053 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12054 + * Read into the local buffer then copy, then copy over and write back.
12057 - if (0 && (parent == dev->deletedDir ||
12058 - parent == dev->unlinkedDir)) {
12059 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12060 - dev->nDeletedFiles++;
12062 - /* Note re hardlinks.
12063 - * Since we might scan a hardlink before its equivalent object is scanned
12064 - * we put them all in a list.
12065 - * After scanning is complete, we should have all the objects, so we run through this
12066 - * list and fix up all the chains.
12068 + __u8 *localBuffer =
12069 + yaffs_GetTempBuffer(dev, __LINE__);
12071 - switch (in->variantType) {
12072 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12073 - /* Todo got a problem */
12075 - case YAFFS_OBJECT_TYPE_FILE:
12076 - if (dev->useHeaderFileSize)
12078 - in->variant.fileVariant.
12083 - case YAFFS_OBJECT_TYPE_HARDLINK:
12084 - in->variant.hardLinkVariant.
12085 - equivalentObjectId =
12086 - oh->equivalentObjectId;
12087 - in->hardLinks.next =
12088 - (struct ylist_head *)
12092 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12095 - case YAFFS_OBJECT_TYPE_SPECIAL:
12098 - case YAFFS_OBJECT_TYPE_SYMLINK:
12099 - in->variant.symLinkVariant.alias =
12100 - yaffs_CloneString(oh->alias);
12101 - if (!in->variant.symLinkVariant.alias)
12102 - alloc_failed = 1;
12105 + yaffs_ReadChunkDataFromObject(in, chunk,
12109 - if (parent == dev->deletedDir) {
12110 - yaffs_DestroyObject(in);
12111 - bi->hasShrinkHeader = 1;
12118 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12119 - /* If we got this far while scanning, then the block is fully allocated.*/
12120 - state = YAFFS_BLOCK_STATE_FULL;
12123 - bi->blockState = state;
12124 + memcpy(&localBuffer[start], buffer, nToCopy);
12126 - /* Now let's see if it was dirty */
12127 - if (bi->pagesInUse == 0 &&
12128 - !bi->hasShrinkHeader &&
12129 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12130 - yaffs_BlockBecameDirty(dev, blk);
12133 + yaffs_WriteChunkDataToObject(in, chunk,
12139 + yaffs_ReleaseTempBuffer(dev, localBuffer,
12144 - /* Ok, we've done all the scanning.
12145 - * Fix up the hard link chains.
12146 - * We should now have scanned all the objects, now it's time to add these
12150 + /* A full chunk. Write directly from the supplied buffer. */
12152 - yaffs_HardlinkFixup(dev, hardList);
12154 - /* Fix up any shadowed objects */
12156 - struct yaffs_ShadowFixerStruct *fixer;
12157 - yaffs_Object *obj;
12159 - while (shadowFixerList) {
12160 - fixer = shadowFixerList;
12161 - shadowFixerList = fixer->next;
12162 - /* Complete the rename transaction by deleting the shadowed object
12163 - * then setting the object header to unshadowed.
12165 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12167 - yaffs_DeleteObject(obj);
12169 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12171 + yaffs_WriteChunkDataToObject(in, chunk, buffer,
12172 + dev->nDataBytesPerChunk,
12176 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12177 + /* Since we've overwritten the cached data, we better invalidate it. */
12178 + yaffs_InvalidateChunkCache(in, chunk);
12182 + if (chunkWritten >= 0) {
12184 + offset += nToCopy;
12185 + buffer += nToCopy;
12186 + nDone += nToCopy;
12190 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12193 - if (alloc_failed)
12194 - return YAFFS_FAIL;
12195 + /* Update file object */
12197 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12198 + if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
12199 + in->variant.fileVariant.fileSize = (startOfWrite + nDone);
12207 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12208 +int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
12209 + int nBytes, int writeThrough)
12212 - yaffs_ObjectHeader *oh;
12213 - yaffs_Device *dev;
12214 - yaffs_ExtendedTags tags;
12216 - int alloc_failed = 0;
12217 + yaffs2_HandleHole(in,offset);
12218 + return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
12227 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12229 - in->lazyLoaded ? "not yet" : "already"));
12231 +/* ---------------------- File resizing stuff ------------------ */
12233 - if (in->lazyLoaded && in->hdrChunk > 0) {
12234 - in->lazyLoaded = 0;
12235 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12236 +static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
12239 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12240 - oh = (yaffs_ObjectHeader *) chunkData;
12241 + yaffs_Device *dev = in->myDev;
12242 + int oldFileSize = in->variant.fileVariant.fileSize;
12244 - in->yst_mode = oh->yst_mode;
12245 -#ifdef CONFIG_YAFFS_WINCE
12246 - in->win_atime[0] = oh->win_atime[0];
12247 - in->win_ctime[0] = oh->win_ctime[0];
12248 - in->win_mtime[0] = oh->win_mtime[0];
12249 - in->win_atime[1] = oh->win_atime[1];
12250 - in->win_ctime[1] = oh->win_ctime[1];
12251 - in->win_mtime[1] = oh->win_mtime[1];
12253 - in->yst_uid = oh->yst_uid;
12254 - in->yst_gid = oh->yst_gid;
12255 - in->yst_atime = oh->yst_atime;
12256 - in->yst_mtime = oh->yst_mtime;
12257 - in->yst_ctime = oh->yst_ctime;
12258 - in->yst_rdev = oh->yst_rdev;
12259 + int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
12262 - yaffs_SetObjectName(in, oh->name);
12263 + int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
12264 + dev->nDataBytesPerChunk;
12268 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12269 - in->variant.symLinkVariant.alias =
12270 - yaffs_CloneString(oh->alias);
12271 - if (!in->variant.symLinkVariant.alias)
12272 - alloc_failed = 1; /* Not returned to caller */
12274 + /* Delete backwards so that we don't end up with holes if
12275 + * power is lost part-way through the operation.
12277 + for (i = lastDel; i >= startDel; i--) {
12278 + /* NB this could be optimised somewhat,
12279 + * eg. could retrieve the tags and write them without
12280 + * using yaffs_DeleteChunk
12283 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12284 + chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
12285 + if (chunkId > 0) {
12287 + (dev->internalStartBlock * dev->param.nChunksPerBlock)
12289 + ((dev->internalEndBlock +
12290 + 1) * dev->param.nChunksPerBlock)) {
12291 + T(YAFFS_TRACE_ALWAYS,
12292 + (TSTR("Found daft chunkId %d for %d" TENDSTR),
12295 + in->nDataChunks--;
12296 + yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
12303 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12305 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize)
12307 - yaffs_ExtendedTags tags;
12309 - int blockIterator;
12310 - int startIterator;
12312 - int nBlocksToScan = 0;
12313 + int newFullChunks;
12314 + __u32 newSizeOfPartialChunk;
12315 + yaffs_Device *dev = obj->myDev;
12321 - yaffs_BlockState state;
12322 - yaffs_Object *hardList = NULL;
12323 - yaffs_BlockInfo *bi;
12324 - __u32 sequenceNumber;
12325 - yaffs_ObjectHeader *oh;
12326 - yaffs_Object *in;
12327 - yaffs_Object *parent;
12328 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12331 + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
12335 - int foundChunksInBlock;
12336 - int equivalentObjectId;
12337 - int alloc_failed = 0;
12338 + yaffs_PruneResizedChunks(obj, newSize);
12340 + if (newSizeOfPartialChunk != 0) {
12341 + int lastChunk = 1 + newFullChunks;
12342 + __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
12344 - yaffs_BlockIndex *blockIndex = NULL;
12345 - int altBlockIndex = 0;
12346 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12347 + yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer);
12348 + memset(localBuffer + newSizeOfPartialChunk, 0,
12349 + dev->nDataBytesPerChunk - newSizeOfPartialChunk);
12351 - if (!dev->isYaffs2) {
12352 - T(YAFFS_TRACE_SCAN,
12353 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12354 - return YAFFS_FAIL;
12355 + yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer,
12356 + newSizeOfPartialChunk, 1);
12358 + yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
12361 - T(YAFFS_TRACE_SCAN,
12363 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12364 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12365 + obj->variant.fileVariant.fileSize = newSize;
12367 + yaffs_PruneFileStructure(dev, &obj->variant.fileVariant);
12371 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12372 +int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
12374 + yaffs_Device *dev = in->myDev;
12375 + int oldFileSize = in->variant.fileVariant.fileSize;
12377 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12378 + yaffs_FlushFilesChunkCache(in);
12379 + yaffs_InvalidateWholeChunkCache(in);
12381 - if (!blockIndex) {
12382 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12383 - altBlockIndex = 1;
12385 + yaffs_CheckGarbageCollection(dev,0);
12387 - if (!blockIndex) {
12388 - T(YAFFS_TRACE_SCAN,
12389 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
12390 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
12394 - dev->blocksInCheckpoint = 0;
12395 + if (newSize == oldFileSize)
12398 + if(newSize > oldFileSize){
12399 + yaffs2_HandleHole(in,newSize);
12400 + in->variant.fileVariant.fileSize = newSize;
12402 + /* newSize < oldFileSize */
12403 + yaffs_ResizeDown(in, newSize);
12406 + /* Write a new object header to reflect the resize.
12407 + * show we've shrunk the file, if need be
12408 + * Do this only if the file is not in the deleted directories
12409 + * and is not shadowed.
12411 + if (in->parent &&
12412 + !in->isShadowed &&
12413 + in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
12414 + in->parent->objectId != YAFFS_OBJECTID_DELETED)
12415 + yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL);
12418 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12422 - /* Scan all the blocks to determine their state */
12423 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12424 - bi = yaffs_GetBlockInfo(dev, blk);
12425 - yaffs_ClearChunkBits(dev, blk);
12426 - bi->pagesInUse = 0;
12427 - bi->softDeletions = 0;
12428 +loff_t yaffs_GetFileSize(yaffs_Object *obj)
12430 + YCHAR *alias = NULL;
12431 + obj = yaffs_GetEquivalentObject(obj);
12433 + switch (obj->variantType) {
12434 + case YAFFS_OBJECT_TYPE_FILE:
12435 + return obj->variant.fileVariant.fileSize;
12436 + case YAFFS_OBJECT_TYPE_SYMLINK:
12437 + alias = obj->variant.symLinkVariant.alias;
12440 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
12446 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12448 - bi->blockState = state;
12449 - bi->sequenceNumber = sequenceNumber;
12451 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
12452 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
12453 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12454 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12455 +int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
12459 + yaffs_FlushFilesChunkCache(in);
12460 + if(dataSync) /* Only sync data */
12463 + if (updateTime) {
12464 +#ifdef CONFIG_YAFFS_WINCE
12465 + yfsd_WinFileTimeNow(in->win_mtime);
12468 - T(YAFFS_TRACE_SCAN_DEBUG,
12469 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12470 - state, sequenceNumber));
12471 + in->yst_mtime = Y_CURRENT_TIME;
12476 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
12477 - dev->blocksInCheckpoint++;
12478 + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >=
12479 + 0) ? YAFFS_OK : YAFFS_FAIL;
12482 + retVal = YAFFS_OK;
12485 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
12486 - T(YAFFS_TRACE_BAD_BLOCKS,
12487 - (TSTR("block %d is bad" TENDSTR), blk));
12488 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12489 - T(YAFFS_TRACE_SCAN_DEBUG,
12490 - (TSTR("Block empty " TENDSTR)));
12491 - dev->nErasedBlocks++;
12492 - dev->nFreeChunks += dev->nChunksPerBlock;
12493 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12496 - /* Determine the highest sequence number */
12497 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
12498 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
12501 - blockIndex[nBlocksToScan].seq = sequenceNumber;
12502 - blockIndex[nBlocksToScan].block = blk;
12503 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
12507 + /* First off, invalidate the file's data in the cache, without flushing. */
12508 + yaffs_InvalidateWholeChunkCache(in);
12510 - if (sequenceNumber >= dev->sequenceNumber)
12511 - dev->sequenceNumber = sequenceNumber;
12513 - /* TODO: Nasty sequence number! */
12514 - T(YAFFS_TRACE_SCAN,
12516 - ("Block scanning block %d has bad sequence number %d"
12517 - TENDSTR), blk, sequenceNumber));
12518 + if (in->myDev->param.isYaffs2 && (in->parent != in->myDev->deletedDir)) {
12519 + /* Move to the unlinked directory so we have a record that it was deleted. */
12520 + yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
12526 - T(YAFFS_TRACE_SCAN,
12527 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
12528 + yaffs_RemoveObjectFromDirectory(in);
12529 + yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
12530 + in->hdrChunk = 0;
12532 + yaffs_FreeObject(in);
12538 +/* yaffs_DeleteFile deletes the whole file data
12539 + * and the inode associated with the file.
12540 + * It does not delete the links associated with the file.
12542 +static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
12545 - /* Sort the blocks */
12546 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
12548 - /* Use qsort now. */
12549 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
12553 - /* Dungy old bubble sort... */
12555 + int immediateDeletion = 0;
12556 + yaffs_Device *dev = in->myDev;
12558 - yaffs_BlockIndex temp;
12561 + if (!in->myInode)
12562 + immediateDeletion = 1;
12564 - for (i = 0; i < nBlocksToScan; i++)
12565 - for (j = i + 1; j < nBlocksToScan; j++)
12566 - if (blockIndex[i].seq > blockIndex[j].seq) {
12567 - temp = blockIndex[j];
12568 - blockIndex[j] = blockIndex[i];
12569 - blockIndex[i] = temp;
12571 + if (immediateDeletion) {
12573 + yaffs_ChangeObjectName(in, in->myDev->deletedDir,
12574 + _Y("deleted"), 0, 0);
12575 + T(YAFFS_TRACE_TRACING,
12576 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
12579 + in->myDev->nDeletedFiles++;
12580 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12581 + yaffs_ResizeFile(in, 0);
12582 + yaffs_SoftDeleteFile(in);
12585 + yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
12586 + _Y("unlinked"), 0, 0);
12592 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
12596 +int yaffs_DeleteFile(yaffs_Object *in)
12598 + int retVal = YAFFS_OK;
12599 + int deleted; /* Need to cache value on stack if in is freed */
12600 + yaffs_Device *dev = in->myDev;
12602 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12603 + yaffs_ResizeFile(in, 0);
12605 + if (in->nDataChunks > 0) {
12606 + /* Use soft deletion if there is data in the file.
12607 + * That won't be the case if it has been resized to zero.
12609 + if (!in->unlinked)
12610 + retVal = yaffs_UnlinkFileIfNeeded(in);
12612 - /* Now scan the blocks looking at the data. */
12613 - startIterator = 0;
12614 - endIterator = nBlocksToScan - 1;
12615 - T(YAFFS_TRACE_SCAN_DEBUG,
12616 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
12617 + deleted = in->deleted;
12619 - /* For each block.... backwards */
12620 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
12621 - blockIterator--) {
12622 - /* Cooperative multitasking! This loop can run for so
12623 - long that watchdog timers expire. */
12625 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
12628 + in->myDev->nDeletedFiles++;
12629 + yaffs_SoftDeleteFile(in);
12631 + return deleted ? YAFFS_OK : YAFFS_FAIL;
12633 + /* The file has no data chunks so we toss it immediately */
12634 + yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
12635 + in->variant.fileVariant.top = NULL;
12636 + yaffs_DoGenericObjectDeletion(in);
12638 - /* get the block to scan in the correct order */
12639 - blk = blockIndex[blockIterator].block;
12644 - bi = yaffs_GetBlockInfo(dev, blk);
12645 +static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
12647 + return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
12648 + !(ylist_empty(&obj->variant.directoryVariant.children));
12651 +static int yaffs_DeleteDirectory(yaffs_Object *obj)
12653 + /* First check that the directory is empty. */
12654 + if (yaffs_IsNonEmptyDirectory(obj))
12655 + return YAFFS_FAIL;
12657 - state = bi->blockState;
12658 + return yaffs_DoGenericObjectDeletion(obj);
12662 +static int yaffs_DeleteSymLink(yaffs_Object *in)
12664 + if(in->variant.symLinkVariant.alias)
12665 + YFREE(in->variant.symLinkVariant.alias);
12666 + in->variant.symLinkVariant.alias=NULL;
12668 - /* For each chunk in each block that needs scanning.... */
12669 - foundChunksInBlock = 0;
12670 - for (c = dev->nChunksPerBlock - 1;
12671 - !alloc_failed && c >= 0 &&
12672 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12673 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
12674 - /* Scan backwards...
12675 - * Read the tags and decide what to do
12677 + return yaffs_DoGenericObjectDeletion(in);
12680 - chunk = blk * dev->nChunksPerBlock + c;
12681 +static int yaffs_DeleteHardLink(yaffs_Object *in)
12683 + /* remove this hardlink from the list assocaited with the equivalent
12686 + ylist_del_init(&in->hardLinks);
12687 + return yaffs_DoGenericObjectDeletion(in);
12690 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12692 +int yaffs_DeleteObject(yaffs_Object *obj)
12695 + switch (obj->variantType) {
12696 + case YAFFS_OBJECT_TYPE_FILE:
12697 + retVal = yaffs_DeleteFile(obj);
12699 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12700 + if(!ylist_empty(&obj->variant.directoryVariant.dirty)){
12701 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->objectId));
12702 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12704 + return yaffs_DeleteDirectory(obj);
12706 + case YAFFS_OBJECT_TYPE_SYMLINK:
12707 + retVal = yaffs_DeleteSymLink(obj);
12709 + case YAFFS_OBJECT_TYPE_HARDLINK:
12710 + retVal = yaffs_DeleteHardLink(obj);
12712 + case YAFFS_OBJECT_TYPE_SPECIAL:
12713 + retVal = yaffs_DoGenericObjectDeletion(obj);
12715 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12717 + break; /* should not happen. */
12720 - /* Let's have a good look at this chunk... */
12724 - if (!tags.chunkUsed) {
12725 - /* An unassigned chunk in the block.
12726 - * If there are used chunks after this one, then
12727 - * it is a chunk that was skipped due to failing the erased
12728 - * check. Just skip it so that it can be deleted.
12729 - * But, more typically, We get here when this is an unallocated
12730 - * chunk and his means that either the block is empty or
12731 - * this is the one being allocated from
12733 +static int yaffs_UnlinkWorker(yaffs_Object *obj)
12736 - if (foundChunksInBlock) {
12737 - /* This is a chunk that was skipped due to failing the erased check */
12738 - } else if (c == 0) {
12739 - /* We're looking at the first chunk in the block so the block is unused */
12740 - state = YAFFS_BLOCK_STATE_EMPTY;
12741 - dev->nErasedBlocks++;
12743 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12744 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
12745 - if (dev->sequenceNumber == bi->sequenceNumber) {
12746 - /* this is the block being allocated from */
12748 - T(YAFFS_TRACE_SCAN,
12750 - (" Allocating from %d %d"
12751 - TENDSTR), blk, c));
12753 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12754 - dev->allocationBlock = blk;
12755 - dev->allocationPage = c;
12756 - dev->allocationBlockFinder = blk;
12758 - /* This is a partially written block that is not
12759 - * the current allocation block. This block must have
12760 - * had a write failure, so set up for retirement.
12763 - /* bi->needsRetiring = 1; ??? TODO */
12764 - bi->gcPrioritise = 1;
12766 - T(YAFFS_TRACE_ALWAYS,
12767 - (TSTR("Partially written block %d detected" TENDSTR),
12772 + int immediateDeletion = 0;
12774 - dev->nFreeChunks++;
12775 + if (!obj->myInode)
12776 + immediateDeletion = 1;
12778 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
12779 - T(YAFFS_TRACE_SCAN,
12780 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
12783 - dev->nFreeChunks++;
12785 - } else if (tags.chunkId > 0) {
12786 - /* chunkId > 0 so it is a data chunk... */
12787 - unsigned int endpos;
12788 - __u32 chunkBase =
12789 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
12791 - foundChunksInBlock = 1;
12794 - yaffs_SetChunkBit(dev, blk, c);
12795 - bi->pagesInUse++;
12797 - in = yaffs_FindOrCreateObjectByNumber(dev,
12800 - YAFFS_OBJECT_TYPE_FILE);
12802 - /* Out of memory */
12803 - alloc_failed = 1;
12806 + yaffs_UpdateParent(obj->parent);
12809 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12811 - in->variant.fileVariant.shrinkSize) {
12812 - /* This has not been invalidated by a resize */
12813 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
12815 - alloc_failed = 1;
12817 + if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
12818 + return yaffs_DeleteHardLink(obj);
12819 + } else if (!ylist_empty(&obj->hardLinks)) {
12820 + /* Curve ball: We're unlinking an object that has a hardlink.
12822 + * This problem arises because we are not strictly following
12823 + * The Linux link/inode model.
12825 + * We can't really delete the object.
12826 + * Instead, we do the following:
12827 + * - Select a hardlink.
12828 + * - Unhook it from the hard links
12829 + * - Move it from its parent directory (so that the rename can work)
12830 + * - Rename the object to the hardlink's name.
12831 + * - Delete the hardlink
12834 - /* File size is calculated by looking at the data chunks if we have not
12835 - * seen an object header yet. Stop this practice once we find an object header.
12839 - 1) * dev->nDataBytesPerChunk +
12842 - if (!in->valid && /* have not got an object header yet */
12843 - in->variant.fileVariant.
12844 - scannedFileSize < endpos) {
12845 - in->variant.fileVariant.
12846 - scannedFileSize = endpos;
12847 - in->variant.fileVariant.
12849 - in->variant.fileVariant.
12852 + yaffs_Object *hl;
12853 + yaffs_Object *parent;
12855 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
12858 - /* This chunk has been invalidated by a resize, so delete */
12859 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
12860 + hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
12864 - /* chunkId == 0, so it is an ObjectHeader.
12865 - * Thus, we read in the object header and make the object
12867 - foundChunksInBlock = 1;
12868 + yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
12869 + parent = hl->parent;
12871 - yaffs_SetChunkBit(dev, blk, c);
12872 - bi->pagesInUse++;
12873 + ylist_del_init(&hl->hardLinks);
12877 + yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl);
12879 - if (tags.extraHeaderInfoAvailable) {
12880 - in = yaffs_FindOrCreateObjectByNumber
12881 - (dev, tags.objectId,
12882 - tags.extraObjectType);
12884 - alloc_failed = 1;
12886 + retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0);
12889 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
12892 - tags.extraShadows ||
12894 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12895 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
12897 - /* If we don't have valid info then we need to read the chunk
12898 - * TODO In future we can probably defer reading the chunk and
12899 - * living with invalid data until needed.
12901 + if (retVal == YAFFS_OK)
12902 + retVal = yaffs_DoGenericObjectDeletion(hl);
12904 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
12909 - oh = (yaffs_ObjectHeader *) chunkData;
12911 - if (dev->inbandTags) {
12912 - /* Fix up the header if they got corrupted by inband tags */
12913 - oh->shadowsObject = oh->inbandShadowsObject;
12914 - oh->isShrink = oh->inbandIsShrink;
12919 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
12921 - alloc_failed = 1;
12923 + } else if (immediateDeletion) {
12924 + switch (obj->variantType) {
12925 + case YAFFS_OBJECT_TYPE_FILE:
12926 + return yaffs_DeleteFile(obj);
12928 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12929 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12930 + return yaffs_DeleteDirectory(obj);
12932 + case YAFFS_OBJECT_TYPE_SYMLINK:
12933 + return yaffs_DeleteSymLink(obj);
12935 + case YAFFS_OBJECT_TYPE_SPECIAL:
12936 + return yaffs_DoGenericObjectDeletion(obj);
12938 + case YAFFS_OBJECT_TYPE_HARDLINK:
12939 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12941 + return YAFFS_FAIL;
12943 + } else if(yaffs_IsNonEmptyDirectory(obj))
12944 + return YAFFS_FAIL;
12946 + return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
12947 + _Y("unlinked"), 0, 0);
12953 - /* TODO Hoosterman we have a problem! */
12954 - T(YAFFS_TRACE_ERROR,
12956 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
12957 - TENDSTR), tags.objectId, chunk));
12960 +static int yaffs_UnlinkObject(yaffs_Object *obj)
12964 - /* We have already filled this one.
12965 - * We have a duplicate that will be discarded, but
12966 - * we first have to suck out resize info if it is a file.
12968 + if (obj && obj->unlinkAllowed)
12969 + return yaffs_UnlinkWorker(obj);
12971 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
12973 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
12974 - (tags.extraHeaderInfoAvailable &&
12975 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
12977 - (oh) ? oh->fileSize : tags.
12979 - __u32 parentObjectId =
12981 - parentObjectId : tags.
12982 - extraParentObjectId;
12986 - (oh) ? oh->isShrink : tags.
12987 - extraIsShrinkHeader;
12988 + return YAFFS_FAIL;
12990 - /* If it is deleted (unlinked at start also means deleted)
12991 - * we treat the file size as being zeroed at this point.
12993 - if (parentObjectId ==
12994 - YAFFS_OBJECTID_DELETED
12995 - || parentObjectId ==
12996 - YAFFS_OBJECTID_UNLINKED) {
13001 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
13003 + yaffs_Object *obj;
13006 - in->variant.fileVariant.
13007 - shrinkSize > thisSize) {
13008 - in->variant.fileVariant.
13012 + obj = yaffs_FindObjectByName(dir, name);
13013 + return yaffs_UnlinkObject(obj);
13017 - bi->hasShrinkHeader = 1;
13018 +/*----------------------- Initialisation Scanning ---------------------- */
13021 - /* Use existing - destroy this one. */
13022 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13023 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
13024 + int backwardScanning)
13026 + yaffs_Object *obj;
13029 + if (!backwardScanning) {
13030 + /* Handle YAFFS1 forward scanning case
13031 + * For YAFFS1 we always do the deletion
13034 - if (!in->valid && in->variantType !=
13035 - (oh ? oh->type : tags.extraObjectType))
13036 - T(YAFFS_TRACE_ERROR, (
13037 - TSTR("yaffs tragedy: Bad object type, "
13038 - TCONT("%d != %d, for object %d at chunk ")
13039 - TCONT("%d during scan")
13041 - oh->type : tags.extraObjectType,
13042 - in->variantType, tags.objectId,
13045 - if (!in->valid &&
13046 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13048 - YAFFS_OBJECTID_LOSTNFOUND)) {
13049 - /* We only load some info, don't fiddle with directory structure */
13052 + /* Handle YAFFS2 case (backward scanning)
13053 + * If the shadowed object exists then ignore.
13055 + obj = yaffs_FindObjectByNumber(dev, objId);
13061 - in->variantType = oh->type;
13062 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13063 + * We put it in unlinked dir to be cleaned up after the scanning
13066 + yaffs_FindOrCreateObjectByNumber(dev, objId,
13067 + YAFFS_OBJECT_TYPE_FILE);
13070 + obj->isShadowed = 1;
13071 + yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
13072 + obj->variant.fileVariant.shrinkSize = 0;
13073 + obj->valid = 1; /* So that we don't read any other info for this file */
13075 - in->yst_mode = oh->yst_mode;
13076 -#ifdef CONFIG_YAFFS_WINCE
13077 - in->win_atime[0] = oh->win_atime[0];
13078 - in->win_ctime[0] = oh->win_ctime[0];
13079 - in->win_mtime[0] = oh->win_mtime[0];
13080 - in->win_atime[1] = oh->win_atime[1];
13081 - in->win_ctime[1] = oh->win_ctime[1];
13082 - in->win_mtime[1] = oh->win_mtime[1];
13084 - in->yst_uid = oh->yst_uid;
13085 - in->yst_gid = oh->yst_gid;
13086 - in->yst_atime = oh->yst_atime;
13087 - in->yst_mtime = oh->yst_mtime;
13088 - in->yst_ctime = oh->yst_ctime;
13089 - in->yst_rdev = oh->yst_rdev;
13094 - in->variantType = tags.extraObjectType;
13095 - in->lazyLoaded = 1;
13098 - in->hdrChunk = chunk;
13099 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
13101 + yaffs_Object *hl;
13102 + yaffs_Object *in;
13104 - } else if (!in->valid) {
13105 - /* we need to load this info */
13106 + while (hardList) {
13108 + hardList = (yaffs_Object *) (hardList->hardLinks.next);
13111 - in->hdrChunk = chunk;
13112 + in = yaffs_FindObjectByNumber(dev,
13113 + hl->variant.hardLinkVariant.
13114 + equivalentObjectId);
13117 - in->variantType = oh->type;
13119 + /* Add the hardlink pointers */
13120 + hl->variant.hardLinkVariant.equivalentObject = in;
13121 + ylist_add(&hl->hardLinks, &in->hardLinks);
13123 + /* Todo Need to report/handle this better.
13124 + * Got a problem... hardlink to a non-existant object
13126 + hl->variant.hardLinkVariant.equivalentObject = NULL;
13127 + YINIT_LIST_HEAD(&hl->hardLinks);
13129 - in->yst_mode = oh->yst_mode;
13130 -#ifdef CONFIG_YAFFS_WINCE
13131 - in->win_atime[0] = oh->win_atime[0];
13132 - in->win_ctime[0] = oh->win_ctime[0];
13133 - in->win_mtime[0] = oh->win_mtime[0];
13134 - in->win_atime[1] = oh->win_atime[1];
13135 - in->win_ctime[1] = oh->win_ctime[1];
13136 - in->win_mtime[1] = oh->win_mtime[1];
13138 - in->yst_uid = oh->yst_uid;
13139 - in->yst_gid = oh->yst_gid;
13140 - in->yst_atime = oh->yst_atime;
13141 - in->yst_mtime = oh->yst_mtime;
13142 - in->yst_ctime = oh->yst_ctime;
13143 - in->yst_rdev = oh->yst_rdev;
13149 - if (oh->shadowsObject > 0)
13150 - yaffs_HandleShadowedObject(dev,
13156 - yaffs_SetObjectName(in, oh->name);
13158 - yaffs_FindOrCreateObjectByNumber
13159 - (dev, oh->parentObjectId,
13160 - YAFFS_OBJECT_TYPE_DIRECTORY);
13162 - fileSize = oh->fileSize;
13163 - isShrink = oh->isShrink;
13164 - equivalentObjectId = oh->equivalentObjectId;
13167 - in->variantType = tags.extraObjectType;
13169 - yaffs_FindOrCreateObjectByNumber
13170 - (dev, tags.extraParentObjectId,
13171 - YAFFS_OBJECT_TYPE_DIRECTORY);
13172 - fileSize = tags.extraFileLength;
13173 - isShrink = tags.extraIsShrinkHeader;
13174 - equivalentObjectId = tags.extraEquivalentObjectId;
13175 - in->lazyLoaded = 1;
13176 +static void yaffs_StripDeletedObjects(yaffs_Device *dev)
13179 + * Sort out state of unlinked and deleted objects after scanning.
13181 + struct ylist_head *i;
13182 + struct ylist_head *n;
13187 + if (dev->readOnly)
13191 - alloc_failed = 1;
13192 + /* Soft delete all the unlinked files */
13193 + ylist_for_each_safe(i, n,
13194 + &dev->unlinkedDir->variant.directoryVariant.children) {
13196 + l = ylist_entry(i, yaffs_Object, siblings);
13197 + yaffs_DeleteObject(l);
13201 - /* directory stuff...
13202 - * hook up to parent
13204 + ylist_for_each_safe(i, n,
13205 + &dev->deletedDir->variant.directoryVariant.children) {
13207 + l = ylist_entry(i, yaffs_Object, siblings);
13208 + yaffs_DeleteObject(l);
13212 - if (parent && parent->variantType ==
13213 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13214 - /* Set up as a directory */
13215 - parent->variantType =
13216 - YAFFS_OBJECT_TYPE_DIRECTORY;
13217 - YINIT_LIST_HEAD(&parent->variant.
13218 - directoryVariant.
13220 - } else if (!parent || parent->variantType !=
13221 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13222 - /* Hoosterman, another problem....
13223 - * We're trying to use a non-directory as a directory
13227 - T(YAFFS_TRACE_ERROR,
13229 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13231 - parent = dev->lostNFoundDir;
13234 + * This code iterates through all the objects making sure that they are rooted.
13235 + * Any unrooted objects are re-rooted in lost+found.
13236 + * An object needs to be in one of:
13237 + * - Directly under deleted, unlinked
13238 + * - Directly or indirectly under root.
13241 + * This code assumes that we don't ever change the current relationships between
13243 + * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
13244 + * lostNfound->parent == rootDir
13246 + * This fixes the problem where directories might have inadvertently been deleted
13247 + * leaving the object "hanging" without being rooted in the directory tree.
13250 +static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
13252 + return (obj == dev->deletedDir ||
13253 + obj == dev->unlinkedDir||
13254 + obj == dev->rootDir);
13257 - yaffs_AddObjectToDirectory(parent, in);
13258 +static void yaffs_FixHangingObjects(yaffs_Device *dev)
13260 + yaffs_Object *obj;
13261 + yaffs_Object *parent;
13263 + struct ylist_head *lh;
13264 + struct ylist_head *n;
13268 - itsUnlinked = (parent == dev->deletedDir) ||
13269 - (parent == dev->unlinkedDir);
13270 + if (dev->readOnly)
13274 - /* Mark the block as having a shrinkHeader */
13275 - bi->hasShrinkHeader = 1;
13277 + /* Iterate through the objects in each hash entry,
13278 + * looking at each object.
13279 + * Make sure it is rooted.
13282 - /* Note re hardlinks.
13283 - * Since we might scan a hardlink before its equivalent object is scanned
13284 - * we put them all in a list.
13285 - * After scanning is complete, we should have all the objects, so we run
13286 - * through this list and fix up all the chains.
13287 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13288 + ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
13290 + obj = ylist_entry(lh, yaffs_Object, hashLink);
13291 + parent= obj->parent;
13293 + if(yaffs_HasNULLParent(dev,obj)){
13294 + /* These directories are not hanging */
13297 + else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13299 + else if(yaffs_HasNULLParent(dev,parent))
13303 + * Need to follow the parent chain to see if it is hanging.
13308 - switch (in->variantType) {
13309 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13310 - /* Todo got a problem */
13312 - case YAFFS_OBJECT_TYPE_FILE:
13314 - if (in->variant.fileVariant.
13315 - scannedFileSize < fileSize) {
13316 - /* This covers the case where the file size is greater
13317 - * than where the data is
13318 - * This will happen if the file is resized to be larger
13319 - * than its current data extents.
13321 - in->variant.fileVariant.fileSize = fileSize;
13322 - in->variant.fileVariant.scannedFileSize =
13323 - in->variant.fileVariant.fileSize;
13327 - in->variant.fileVariant.shrinkSize > fileSize) {
13328 - in->variant.fileVariant.shrinkSize = fileSize;
13332 - case YAFFS_OBJECT_TYPE_HARDLINK:
13333 - if (!itsUnlinked) {
13334 - in->variant.hardLinkVariant.equivalentObjectId =
13335 - equivalentObjectId;
13336 - in->hardLinks.next =
13337 - (struct ylist_head *) hardList;
13341 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13344 - case YAFFS_OBJECT_TYPE_SPECIAL:
13347 - case YAFFS_OBJECT_TYPE_SYMLINK:
13349 - in->variant.symLinkVariant.alias =
13350 - yaffs_CloneString(oh->alias);
13351 - if (!in->variant.symLinkVariant.alias)
13352 - alloc_failed = 1;
13355 + while(parent != dev->rootDir &&
13356 + parent->parent &&
13357 + parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
13359 + parent = parent->parent;
13363 + if(parent != dev->rootDir)
13367 + T(YAFFS_TRACE_SCAN,
13368 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13370 + yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
13378 - } /* End of scanning for each chunk */
13380 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13381 - /* If we got this far while scanning, then the block is fully allocated. */
13382 - state = YAFFS_BLOCK_STATE_FULL;
13385 + * Delete directory contents for cleaning up lost and found.
13387 +static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
13389 + yaffs_Object *obj;
13390 + struct ylist_head *lh;
13391 + struct ylist_head *n;
13393 - bi->blockState = state;
13394 + if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13397 + ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
13399 + obj = ylist_entry(lh, yaffs_Object, siblings);
13400 + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
13401 + yaffs_DeleteDirectoryContents(obj);
13403 + T(YAFFS_TRACE_SCAN,
13404 + (TSTR("Deleting lost_found object %d" TENDSTR),
13407 - /* Now let's see if it was dirty */
13408 - if (bi->pagesInUse == 0 &&
13409 - !bi->hasShrinkHeader &&
13410 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13411 - yaffs_BlockBecameDirty(dev, blk);
13412 + /* Need to use UnlinkObject since Delete would not handle
13413 + * hardlinked objects correctly.
13415 + yaffs_UnlinkObject(obj);
13422 - if (altBlockIndex)
13423 - YFREE_ALT(blockIndex);
13425 - YFREE(blockIndex);
13426 +static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
13428 + yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
13431 - /* Ok, we've done all the scanning.
13432 - * Fix up the hard link chains.
13433 - * We should now have scanned all the objects, now it's time to add these
13436 - yaffs_HardlinkFixup(dev, hardList);
13437 +static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
13440 + yaffs_ObjectHeader *oh;
13441 + yaffs_Device *dev;
13442 + yaffs_ExtendedTags tags;
13444 + int alloc_failed = 0;
13449 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13452 - if (alloc_failed)
13453 - return YAFFS_FAIL;
13455 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
13457 + in->lazyLoaded ? "not yet" : "already"));
13460 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
13461 + if (in->lazyLoaded && in->hdrChunk > 0) {
13462 + in->lazyLoaded = 0;
13463 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13467 + result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
13468 + oh = (yaffs_ObjectHeader *) chunkData;
13470 -/*------------------------------ Directory Functions ----------------------------- */
13471 + in->yst_mode = oh->yst_mode;
13472 +#ifdef CONFIG_YAFFS_WINCE
13473 + in->win_atime[0] = oh->win_atime[0];
13474 + in->win_ctime[0] = oh->win_ctime[0];
13475 + in->win_mtime[0] = oh->win_mtime[0];
13476 + in->win_atime[1] = oh->win_atime[1];
13477 + in->win_ctime[1] = oh->win_ctime[1];
13478 + in->win_mtime[1] = oh->win_mtime[1];
13480 + in->yst_uid = oh->yst_uid;
13481 + in->yst_gid = oh->yst_gid;
13482 + in->yst_atime = oh->yst_atime;
13483 + in->yst_mtime = oh->yst_mtime;
13484 + in->yst_ctime = oh->yst_ctime;
13485 + in->yst_rdev = oh->yst_rdev;
13487 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
13489 - struct ylist_head *lh;
13490 - yaffs_Object *listObj;
13492 + yaffs_SetObjectNameFromOH(in, oh);
13495 + if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
13496 + in->variant.symLinkVariant.alias =
13497 + yaffs_CloneString(oh->alias);
13498 + if (!in->variant.symLinkVariant.alias)
13499 + alloc_failed = 1; /* Not returned to caller */
13503 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
13506 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13510 - if (yaffs_SkipVerification(obj->myDev))
13512 +/*------------------------------ Directory Functions ----------------------------- */
13514 - if (!obj->parent) {
13515 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
13518 + *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
13519 + * link (ie. name) is created or deleted in the directory.
13522 + * create dir/a : update dir's mtime/ctime
13523 + * rm dir/a: update dir's mtime/ctime
13524 + * modify dir/a: don't update dir's mtimme/ctime
13526 + * This can be handled immediately or defered. Defering helps reduce the number
13527 + * of updates when many files in a directory are changed within a brief period.
13529 + * If the directory updating is defered then yaffs_UpdateDirtyDirecories must be
13530 + * called periodically.
13533 +static void yaffs_UpdateParent(yaffs_Object *obj)
13535 + yaffs_Device *dev;
13540 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13541 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
13545 - /* Iterate through the objects in each hash entry */
13546 +#ifndef CONFIG_YAFFS_WINCE
13548 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
13550 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13551 - yaffs_VerifyObject(listObj);
13552 - if (obj == listObj)
13554 + dev = obj->myDev;
13556 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
13557 + if(dev->param.deferDirectoryUpdate){
13558 + struct ylist_head *link = &obj->variant.directoryVariant.dirty;
13560 + if(ylist_empty(link)){
13561 + ylist_add(link,&dev->dirtyDirectories);
13562 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->objectId));
13566 - if (count != 1) {
13567 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
13571 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13575 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
13576 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
13578 - struct ylist_head *lh;
13579 - yaffs_Object *listObj;
13581 - if (!directory) {
13585 + struct ylist_head *link;
13586 + yaffs_Object *obj;
13587 + yaffs_DirectoryStructure *dS;
13588 + yaffs_ObjectVariant *oV;
13590 - if (yaffs_SkipFullVerification(directory->myDev))
13592 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
13594 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13595 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
13598 + while(!ylist_empty(&dev->dirtyDirectories)){
13599 + link = dev->dirtyDirectories.next;
13600 + ylist_del_init(link);
13602 + dS=ylist_entry(link,yaffs_DirectoryStructure,dirty);
13603 + oV = ylist_entry(dS,yaffs_ObjectVariant,directoryVariant);
13604 + obj = ylist_entry(oV,yaffs_Object,variant);
13606 - /* Iterate through the objects in each hash entry */
13607 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId));
13609 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
13611 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13612 - if (listObj->parent != directory) {
13613 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
13616 - yaffs_VerifyObjectInDirectory(listObj);
13619 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13624 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
13626 yaffs_Device *dev = obj->myDev;
13627 @@ -6677,18 +4474,17 @@ static void yaffs_RemoveObjectFromDirect
13629 yaffs_VerifyDirectory(parent);
13631 - if (dev && dev->removeObjectCallback)
13632 - dev->removeObjectCallback(obj);
13633 + if (dev && dev->param.removeObjectCallback)
13634 + dev->param.removeObjectCallback(obj);
13637 ylist_del_init(&obj->siblings);
13638 obj->parent = NULL;
13641 yaffs_VerifyDirectory(parent);
13645 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13646 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13650 @@ -6781,7 +4577,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
13653 yaffs_GetObjectName(l, buffer,
13654 - YAFFS_MAX_NAME_LENGTH);
13655 + YAFFS_MAX_NAME_LENGTH + 1);
13656 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
13659 @@ -6842,36 +4638,124 @@ yaffs_Object *yaffs_GetEquivalentObject(
13663 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
13665 - memset(name, 0, buffSize * sizeof(YCHAR));
13667 - yaffs_CheckObjectDetailsLoaded(obj);
13669 + * A note or two on object names.
13670 + * * If the object name is missing, we then make one up in the form objnnn
13672 + * * ASCII names are stored in the object header's name field from byte zero
13673 + * * Unicode names are historically stored starting from byte zero.
13675 + * Then there are automatic Unicode names...
13676 + * The purpose of these is to save names in a way that can be read as
13677 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
13678 + * system to share files.
13680 + * These automatic unicode are stored slightly differently...
13681 + * - If the name can fit in the ASCII character space then they are saved as
13682 + * ascii names as per above.
13683 + * - If the name needs Unicode then the name is saved in Unicode
13684 + * starting at oh->name[1].
13686 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13687 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13688 - } else if (obj->hdrChunk <= 0) {
13690 +static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize)
13692 + /* Create an object name if we could not find one. */
13693 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
13695 YCHAR numString[20];
13696 YCHAR *x = &numString[19];
13697 unsigned v = obj->objectId;
13702 *x = '0' + (v % 10);
13705 /* make up a name */
13706 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
13707 - yaffs_strcat(locName, x);
13708 + yaffs_strcat(locName,x);
13709 yaffs_strncpy(name, locName, buffSize - 1);
13713 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
13715 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13716 + if(dev->param.autoUnicode){
13718 + /* It is an ASCII name, so do an ASCII to unicode conversion */
13719 + const char *asciiOhName = (const char *)ohName;
13720 + int n = bufferSize - 1;
13721 + while(n > 0 && *asciiOhName){
13722 + *name = *asciiOhName;
13728 + yaffs_strncpy(name,ohName+1, bufferSize -1);
13731 + yaffs_strncpy(name, ohName, bufferSize - 1);
13735 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name)
13737 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13742 + if(dev->param.autoUnicode){
13747 + /* Figure out if the name will fit in ascii character set */
13748 + while(isAscii && *w){
13749 + if((*w) & 0xff00)
13755 + /* It is an ASCII name, so do a unicode to ascii conversion */
13756 + char *asciiOhName = (char *)ohName;
13757 + int n = YAFFS_MAX_NAME_LENGTH - 1;
13758 + while(n > 0 && *name){
13759 + *asciiOhName= *name;
13765 + /* It is a unicode name, so save starting at the second YCHAR */
13767 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
13772 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
13776 +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
13778 + memset(name, 0, buffSize * sizeof(YCHAR));
13780 + yaffs_CheckObjectDetailsLoaded(obj);
13782 + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13783 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13785 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
13786 - else if (obj->shortName[0])
13787 + else if (obj->shortName[0]) {
13788 yaffs_strcpy(name, obj->shortName);
13792 + else if(obj->hdrChunk > 0) {
13794 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
13796 @@ -6884,14 +4768,17 @@ int yaffs_GetObjectName(yaffs_Object *ob
13797 obj->hdrChunk, buffer,
13800 - yaffs_strncpy(name, oh->name, buffSize - 1);
13801 + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize);
13803 yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
13806 - return yaffs_strlen(name);
13807 + yaffs_FixNullName(obj,name,buffSize);
13809 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
13813 int yaffs_GetObjectFileLength(yaffs_Object *obj)
13815 /* Dereference any hard linking */
13816 @@ -6899,9 +4786,11 @@ int yaffs_GetObjectFileLength(yaffs_Obje
13818 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
13819 return obj->variant.fileVariant.fileSize;
13820 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
13821 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
13823 + if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
13824 + if(!obj->variant.symLinkVariant.alias)
13826 + return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
13828 /* Only a directory should drop through to here */
13829 return obj->myDev->nDataBytesPerChunk;
13831 @@ -6992,7 +4881,7 @@ int yaffs_SetAttributes(yaffs_Object *ob
13832 if (valid & ATTR_SIZE)
13833 yaffs_ResizeFile(obj, attr->ia_size);
13835 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
13836 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
13840 @@ -7025,12 +4914,129 @@ int yaffs_GetAttributes(yaffs_Object *ob
13845 +static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags)
13847 + yaffs_XAttrMod xmod;
13852 + xmod.name = name;
13853 + xmod.data = value;
13854 + xmod.size = size;
13855 + xmod.flags = flags;
13856 + xmod.result = -ENOSPC;
13858 + result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod);
13861 + return xmod.result;
13866 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod)
13869 + int x_offs = sizeof(yaffs_ObjectHeader);
13870 + yaffs_Device *dev = obj->myDev;
13871 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13873 + char * x_buffer = buffer + x_offs;
13876 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
13878 + retval = nval_del(x_buffer, x_size, xmod->name);
13880 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13881 + obj->xattrKnown = 1;
13883 + xmod->result = retval;
13888 +static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13890 + char *buffer = NULL;
13892 + yaffs_ExtendedTags tags;
13893 + yaffs_Device *dev = obj->myDev;
13894 + int x_offs = sizeof(yaffs_ObjectHeader);
13895 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13901 + if(obj->hdrChunk < 1)
13904 + /* If we know that the object has no xattribs then don't do all the
13905 + * reading and parsing.
13907 + if(obj->xattrKnown && !obj->hasXattr){
13914 + buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__);
13918 + result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags);
13920 + if(result != YAFFS_OK)
13921 + retval = -ENOENT;
13923 + x_buffer = buffer + x_offs;
13925 + if (!obj->xattrKnown){
13926 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13927 + obj->xattrKnown = 1;
13931 + retval = nval_get(x_buffer, x_size, name, value, size);
13933 + retval = nval_list(x_buffer, x_size, value,size);
13935 + yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__);
13939 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags)
13941 + return yaffs_DoXMod(obj, 1, name, value, size, flags);
13944 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name)
13946 + return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
13949 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13951 + return yaffs_DoXFetch(obj, name, value, size);
13954 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size)
13956 + return yaffs_DoXFetch(obj, NULL, buffer,size);
13962 int yaffs_DumpObject(yaffs_Object *obj)
13966 - yaffs_GetObjectName(obj, name, 256);
13967 + yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
13969 T(YAFFS_TRACE_ALWAYS,
13971 @@ -7050,30 +5056,32 @@ static int yaffs_CheckDevFunctions(const
13974 /* Common functions, gotta have */
13975 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
13976 + if (!dev->param.eraseBlockInNAND || !dev->param.initialiseNAND)
13979 #ifdef CONFIG_YAFFS_YAFFS2
13981 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
13982 - if (dev->writeChunkWithTagsToNAND &&
13983 - dev->readChunkWithTagsFromNAND &&
13984 - !dev->writeChunkToNAND &&
13985 - !dev->readChunkFromNAND &&
13986 - dev->markNANDBlockBad && dev->queryNANDBlock)
13987 + if (dev->param.writeChunkWithTagsToNAND &&
13988 + dev->param.readChunkWithTagsFromNAND &&
13989 + !dev->param.writeChunkToNAND &&
13990 + !dev->param.readChunkFromNAND &&
13991 + dev->param.markNANDBlockBad &&
13992 + dev->param.queryNANDBlock)
13996 /* Can use the "spare" style interface for yaffs1 */
13997 - if (!dev->isYaffs2 &&
13998 - !dev->writeChunkWithTagsToNAND &&
13999 - !dev->readChunkWithTagsFromNAND &&
14000 - dev->writeChunkToNAND &&
14001 - dev->readChunkFromNAND &&
14002 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
14003 + if (!dev->param.isYaffs2 &&
14004 + !dev->param.writeChunkWithTagsToNAND &&
14005 + !dev->param.readChunkWithTagsFromNAND &&
14006 + dev->param.writeChunkToNAND &&
14007 + dev->param.readChunkFromNAND &&
14008 + !dev->param.markNANDBlockBad &&
14009 + !dev->param.queryNANDBlock)
14012 - return 0; /* bad */
14013 + return 0; /* bad */
14017 @@ -7120,35 +5128,35 @@ int yaffs_GutsInitialise(yaffs_Device *d
14021 - dev->internalStartBlock = dev->startBlock;
14022 - dev->internalEndBlock = dev->endBlock;
14023 + dev->internalStartBlock = dev->param.startBlock;
14024 + dev->internalEndBlock = dev->param.endBlock;
14025 dev->blockOffset = 0;
14026 dev->chunkOffset = 0;
14027 dev->nFreeChunks = 0;
14029 - dev->gcBlock = -1;
14030 + dev->gcBlock = 0;
14032 - if (dev->startBlock == 0) {
14033 - dev->internalStartBlock = dev->startBlock + 1;
14034 - dev->internalEndBlock = dev->endBlock + 1;
14035 + if (dev->param.startBlock == 0) {
14036 + dev->internalStartBlock = dev->param.startBlock + 1;
14037 + dev->internalEndBlock = dev->param.endBlock + 1;
14038 dev->blockOffset = 1;
14039 - dev->chunkOffset = dev->nChunksPerBlock;
14040 + dev->chunkOffset = dev->param.nChunksPerBlock;
14043 /* Check geometry parameters. */
14045 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14046 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14047 - (dev->inbandTags && !dev->isYaffs2) ||
14048 - dev->nChunksPerBlock < 2 ||
14049 - dev->nReservedBlocks < 2 ||
14050 + if ((!dev->param.inbandTags && dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 1024) ||
14051 + (!dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 512) ||
14052 + (dev->param.inbandTags && !dev->param.isYaffs2) ||
14053 + dev->param.nChunksPerBlock < 2 ||
14054 + dev->param.nReservedBlocks < 2 ||
14055 dev->internalStartBlock <= 0 ||
14056 dev->internalEndBlock <= 0 ||
14057 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14058 + dev->internalEndBlock <= (dev->internalStartBlock + dev->param.nReservedBlocks + 2)) { /* otherwise it is too small */
14059 T(YAFFS_TRACE_ALWAYS,
14061 ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14062 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14063 + TENDSTR), dev->param.totalBytesPerChunk, dev->param.isYaffs2 ? "2" : "", dev->param.inbandTags));
14067 @@ -7159,10 +5167,10 @@ int yaffs_GutsInitialise(yaffs_Device *d
14070 /* Sort out space for inband tags, if required */
14071 - if (dev->inbandTags)
14072 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14073 + if (dev->param.inbandTags)
14074 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14076 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
14077 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk;
14079 /* Got the right mix of functions? */
14080 if (!yaffs_CheckDevFunctions(dev)) {
14081 @@ -7209,12 +5217,12 @@ int yaffs_GutsInitialise(yaffs_Device *d
14082 * We need to find the next power of 2 > than internalEndBlock
14085 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
14086 + x = dev->param.nChunksPerBlock * (dev->internalEndBlock + 1);
14088 bits = ShiftsGE(x);
14090 /* Set up tnode width if wide tnodes are enabled. */
14091 - if (!dev->wideTnodesDisabled) {
14092 + if (!dev->param.wideTnodesDisabled) {
14093 /* bits must be even so that we end up with 32-bit words */
14096 @@ -7238,10 +5246,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14098 dev->chunkGroupBits = bits - dev->tnodeWidth;
14100 + dev->tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
14101 + if(dev->tnodeSize < sizeof(yaffs_Tnode))
14102 + dev->tnodeSize = sizeof(yaffs_Tnode);
14104 dev->chunkGroupSize = 1 << dev->chunkGroupBits;
14106 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
14107 + if (dev->param.nChunksPerBlock < dev->chunkGroupSize) {
14108 /* We have a problem because the soft delete won't work if
14109 * the chunk group size > chunks per block.
14110 * This can be remedied by using larger "virtual blocks".
14111 @@ -7255,9 +5266,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14112 /* OK, we've finished verifying the device, lets continue with initialisation */
14114 /* More device initialisation */
14115 - dev->garbageCollections = 0;
14116 - dev->passiveGarbageCollections = 0;
14117 - dev->currentDirtyChecker = 0;
14119 + dev->passiveGCs = 0;
14120 + dev->oldestDirtyGCs = 0;
14121 + dev->backgroundGCs = 0;
14122 + dev->gcBlockFinder = 0;
14123 dev->bufferedBlock = -1;
14124 dev->doingBufferedBlockRewrite = 0;
14125 dev->nDeletedFiles = 0;
14126 @@ -7269,8 +5282,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14127 dev->tagsEccUnfixed = 0;
14128 dev->nErasureFailures = 0;
14129 dev->nErasedBlocks = 0;
14130 - dev->isDoingGC = 0;
14131 + dev->gcDisable= 0;
14132 dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
14133 + YINIT_LIST_HEAD(&dev->dirtyDirectories);
14134 + dev->oldestDirtySequence = 0;
14135 + dev->oldestDirtyBlock = 0;
14137 /* Initialise temporary buffers and caches. */
14138 if (!yaffs_InitialiseTempBuffers(dev))
14139 @@ -7281,13 +5297,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14142 if (!init_failed &&
14143 - dev->nShortOpCaches > 0) {
14144 + dev->param.nShortOpCaches > 0) {
14147 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
14148 + int srCacheBytes = dev->param.nShortOpCaches * sizeof(yaffs_ChunkCache);
14150 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14151 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14152 + if (dev->param.nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14153 + dev->param.nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14155 dev->srCache = YMALLOC(srCacheBytes);
14157 @@ -7296,11 +5312,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14159 memset(dev->srCache, 0, srCacheBytes);
14161 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
14162 + for (i = 0; i < dev->param.nShortOpCaches && buf; i++) {
14163 dev->srCache[i].object = NULL;
14164 dev->srCache[i].lastUse = 0;
14165 dev->srCache[i].dirty = 0;
14166 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
14167 + dev->srCache[i].data = buf = YMALLOC_DMA(dev->param.totalBytesPerChunk);
14171 @@ -7311,19 +5327,18 @@ int yaffs_GutsInitialise(yaffs_Device *d
14172 dev->cacheHits = 0;
14174 if (!init_failed) {
14175 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
14176 + dev->gcCleanupList = YMALLOC(dev->param.nChunksPerBlock * sizeof(__u32));
14177 if (!dev->gcCleanupList)
14181 - if (dev->isYaffs2)
14182 - dev->useHeaderFileSize = 1;
14183 + if (dev->param.isYaffs2)
14184 + dev->param.useHeaderFileSize = 1;
14186 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14189 - yaffs_InitialiseTnodes(dev);
14190 - yaffs_InitialiseObjects(dev);
14191 + yaffs_InitialiseTnodesAndObjects(dev);
14193 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14195 @@ -7331,8 +5346,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14197 if (!init_failed) {
14198 /* Now scan the flash. */
14199 - if (dev->isYaffs2) {
14200 - if (yaffs_CheckpointRestore(dev)) {
14201 + if (dev->param.isYaffs2) {
14202 + if (yaffs2_CheckpointRestore(dev)) {
14203 yaffs_CheckObjectDetailsLoaded(dev->rootDir);
14204 T(YAFFS_TRACE_ALWAYS,
14205 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
14206 @@ -7342,9 +5357,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14207 * and scan backwards.
14209 yaffs_DeinitialiseBlocks(dev);
14210 - yaffs_DeinitialiseTnodes(dev);
14211 - yaffs_DeinitialiseObjects(dev);
14213 + yaffs_DeinitialiseTnodesAndObjects(dev);
14215 dev->nErasedBlocks = 0;
14216 dev->nFreeChunks = 0;
14217 @@ -7353,24 +5367,25 @@ int yaffs_GutsInitialise(yaffs_Device *d
14218 dev->nDeletedFiles = 0;
14219 dev->nUnlinkedFiles = 0;
14220 dev->nBackgroundDeletions = 0;
14221 - dev->oldestDirtySequence = 0;
14223 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14226 - yaffs_InitialiseTnodes(dev);
14227 - yaffs_InitialiseObjects(dev);
14228 + yaffs_InitialiseTnodesAndObjects(dev);
14230 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14233 - if (!init_failed && !yaffs_ScanBackwards(dev))
14234 + if (!init_failed && !yaffs2_ScanBackwards(dev))
14237 - } else if (!yaffs_Scan(dev))
14238 + } else if (!yaffs1_Scan(dev))
14241 yaffs_StripDeletedObjects(dev);
14242 + yaffs_FixHangingObjects(dev);
14243 + if(dev->param.emptyLostAndFound)
14244 + yaffs_EmptyLostAndFound(dev);
14248 @@ -7394,6 +5409,9 @@ int yaffs_GutsInitialise(yaffs_Device *d
14249 yaffs_VerifyFreeChunks(dev);
14250 yaffs_VerifyBlocks(dev);
14252 + /* Clean up any aborted checkpoint data */
14253 + if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
14254 + yaffs2_InvalidateCheckpoint(dev);
14256 T(YAFFS_TRACE_TRACING,
14257 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
14258 @@ -7407,12 +5425,11 @@ void yaffs_Deinitialise(yaffs_Device *de
14261 yaffs_DeinitialiseBlocks(dev);
14262 - yaffs_DeinitialiseTnodes(dev);
14263 - yaffs_DeinitialiseObjects(dev);
14264 - if (dev->nShortOpCaches > 0 &&
14265 + yaffs_DeinitialiseTnodesAndObjects(dev);
14266 + if (dev->param.nShortOpCaches > 0 &&
14269 - for (i = 0; i < dev->nShortOpCaches; i++) {
14270 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
14271 if (dev->srCache[i].data)
14272 YFREE(dev->srCache[i].data);
14273 dev->srCache[i].data = NULL;
14274 @@ -7429,34 +5446,33 @@ void yaffs_Deinitialise(yaffs_Device *de
14276 dev->isMounted = 0;
14278 - if (dev->deinitialiseNAND)
14279 - dev->deinitialiseNAND(dev);
14280 + if (dev->param.deinitialiseNAND)
14281 + dev->param.deinitialiseNAND(dev);
14285 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
14286 +int yaffs_CountFreeChunks(yaffs_Device *dev)
14292 yaffs_BlockInfo *blk;
14294 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
14296 - blk = yaffs_GetBlockInfo(dev, b);
14298 + blk = dev->blockInfo;
14299 + for (b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) {
14300 switch (blk->blockState) {
14301 case YAFFS_BLOCK_STATE_EMPTY:
14302 case YAFFS_BLOCK_STATE_ALLOCATING:
14303 case YAFFS_BLOCK_STATE_COLLECTING:
14304 case YAFFS_BLOCK_STATE_FULL:
14306 - (dev->nChunksPerBlock - blk->pagesInUse +
14307 + (dev->param.nChunksPerBlock - blk->pagesInUse +
14308 blk->softDeletions);
14317 @@ -7481,21 +5497,19 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14319 /* Now count the number of dirty chunks in the cache and subtract those */
14321 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
14322 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.nShortOpCaches; i++) {
14323 if (dev->srCache[i].dirty)
14324 nDirtyCacheChunks++;
14327 nFree -= nDirtyCacheChunks;
14329 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
14330 + nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock);
14332 /* Now we figure out how much to reserve for the checkpoint and report that... */
14333 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
14334 - if (blocksForCheckpoint < 0)
14335 - blocksForCheckpoint = 0;
14336 + blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev);
14338 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
14339 + nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock);
14343 @@ -7504,27 +5518,6 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14347 -static int yaffs_freeVerificationFailures;
14349 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
14354 - if (yaffs_SkipVerification(dev))
14357 - counted = yaffs_CountFreeChunks(dev);
14359 - difference = dev->nFreeChunks - counted;
14361 - if (difference) {
14362 - T(YAFFS_TRACE_ALWAYS,
14363 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
14364 - dev->nFreeChunks, counted, difference));
14365 - yaffs_freeVerificationFailures++;
14369 /*---------------------------------------- YAFFS test code ----------------------*/
14371 @@ -7532,7 +5525,7 @@ static void yaffs_VerifyFreeChunks(yaffs
14373 if (sizeof(structure) != syze) { \
14374 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
14375 - name, syze, sizeof(structure))); \
14376 + name, syze, (int) sizeof(structure))); \
14377 return YAFFS_FAIL; \
14380 @@ -7542,9 +5535,8 @@ static int yaffs_CheckStructures(void)
14381 /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
14382 /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
14383 /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
14384 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
14385 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
14387 +/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
14389 #ifndef CONFIG_YAFFS_WINCE
14390 yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
14392 diff -Nrup a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
14393 --- a/fs/yaffs2/yaffs_guts.h 2010-10-03 17:48:22.718000363 +0300
14394 +++ b/fs/yaffs2/yaffs_guts.h 2010-10-03 18:03:47.542000362 +0300
14397 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14399 - * Copyright (C) 2002-2007 Aleph One Ltd.
14400 + * Copyright (C) 2002-2010 Aleph One Ltd.
14401 * for Toby Churchill Ltd and Brightstar Engineering
14403 * Created by Charles Manning <charles@aleph1.co.uk>
14405 #ifndef __YAFFS_GUTS_H__
14406 #define __YAFFS_GUTS_H__
14408 -#include "devextras.h"
14409 #include "yportenv.h"
14410 +#include "devextras.h"
14411 +#include "yaffs_list.h"
14414 #define YAFFS_FAIL 0
14417 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
14419 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
14421 #define YAFFS_ALLOCATION_NOBJECTS 100
14422 #define YAFFS_ALLOCATION_NTNODES 100
14426 #define YAFFS_OBJECT_SPACE 0x40000
14427 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
14429 -#define YAFFS_CHECKPOINT_VERSION 3
14430 +#define YAFFS_CHECKPOINT_VERSION 4
14432 #ifdef CONFIG_YAFFS_UNICODE
14433 #define YAFFS_MAX_NAME_LENGTH 127
14434 @@ -81,12 +82,11 @@
14435 #define YAFFS_OBJECTID_UNLINKED 3
14436 #define YAFFS_OBJECTID_DELETED 4
14438 -/* Sseudo object ids for checkpointing */
14439 +/* Pseudo object ids for checkpointing */
14440 #define YAFFS_OBJECTID_SB_HEADER 0x10
14441 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
14442 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
14446 #define YAFFS_MAX_SHORT_OP_CACHES 20
14448 @@ -119,11 +119,7 @@ typedef struct {
14450 int nBytes; /* Only valid if the cache is dirty */
14451 int locked; /* Can't push out or flush while locked. */
14452 -#ifdef CONFIG_YAFFS_YAFFS2
14455 - __u8 data[YAFFS_BYTES_PER_CHUNK];
14457 } yaffs_ChunkCache;
14460 @@ -234,6 +230,8 @@ typedef enum {
14461 YAFFS_BLOCK_STATE_UNKNOWN = 0,
14463 YAFFS_BLOCK_STATE_SCANNING,
14464 + /* Being scanned */
14466 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
14467 /* The block might have something on it (ie it is allocating or full, perhaps empty)
14468 * but it needs to be scanned to determine its true state.
14469 @@ -249,21 +247,23 @@ typedef enum {
14470 /* This block is partially allocated.
14471 * At least one page holds valid data.
14472 * This is the one currently being used for page
14473 - * allocation. Should never be more than one of these
14474 + * allocation. Should never be more than one of these.
14475 + * If a block is only partially allocated at mount it is treated as full.
14478 YAFFS_BLOCK_STATE_FULL,
14479 /* All the pages in this block have been allocated.
14480 + * If a block was only partially allocated when mounted we treat
14481 + * it as fully allocated.
14484 YAFFS_BLOCK_STATE_DIRTY,
14485 - /* All pages have been allocated and deleted.
14486 + /* The block was full and now all chunks have been deleted.
14487 * Erase me, reuse me.
14490 YAFFS_BLOCK_STATE_CHECKPOINT,
14491 - /* This block is assigned to holding checkpoint data.
14493 + /* This block is assigned to holding checkpoint data. */
14495 YAFFS_BLOCK_STATE_COLLECTING,
14496 /* This block is being garbage collected */
14497 @@ -351,23 +351,12 @@ typedef struct {
14498 /*--------------------------- Tnode -------------------------- */
14500 union yaffs_Tnode_union {
14501 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
14502 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
14504 union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
14506 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
14510 typedef union yaffs_Tnode_union yaffs_Tnode;
14512 -struct yaffs_TnodeList_struct {
14513 - struct yaffs_TnodeList_struct *next;
14514 - yaffs_Tnode *tnodes;
14517 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
14519 /*------------------------ Object -----------------------------*/
14520 /* An object can be one of:
14521 @@ -387,6 +376,7 @@ typedef struct {
14524 struct ylist_head children; /* list of child links */
14525 + struct ylist_head dirty; /* Entry for list of dirty directories */
14526 } yaffs_DirectoryStructure;
14529 @@ -405,6 +395,8 @@ typedef union {
14530 yaffs_HardLinkStructure hardLinkVariant;
14531 } yaffs_ObjectVariant;
14535 struct yaffs_ObjectStruct {
14536 __u8 deleted:1; /* This should only apply to unlinked files. */
14537 __u8 softDeleted:1; /* it has also been soft deleted */
14538 @@ -424,6 +416,10 @@ struct yaffs_ObjectStruct {
14539 * until the inode is released.
14541 __u8 beingCreated:1; /* This object is still being created so skip some checks. */
14542 + __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */
14544 + __u8 xattrKnown:1; /* We know if this has object has xattribs or not. */
14545 + __u8 hasXattr:1; /* This object has xattribs. Valid if xattrKnown. */
14547 __u8 serial; /* serial number of chunk in NAND. Cached here */
14548 __u16 sum; /* sum of the name to speed searching */
14549 @@ -452,10 +448,6 @@ struct yaffs_ObjectStruct {
14550 YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
14553 -#ifndef __KERNEL__
14557 #ifdef CONFIG_YAFFS_WINCE
14558 __u32 win_ctime[2];
14559 __u32 win_mtime[2];
14560 @@ -470,10 +462,7 @@ struct yaffs_ObjectStruct {
14565 - struct inode *myInode;
14570 yaffs_ObjectType variantType;
14572 @@ -483,13 +472,6 @@ struct yaffs_ObjectStruct {
14574 typedef struct yaffs_ObjectStruct yaffs_Object;
14576 -struct yaffs_ObjectList_struct {
14577 - yaffs_Object *objects;
14578 - struct yaffs_ObjectList_struct *next;
14581 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
14584 struct ylist_head list;
14586 @@ -531,12 +513,18 @@ typedef struct {
14588 /*----------------- Device ---------------------------------*/
14590 -struct yaffs_DeviceStruct {
14591 - struct ylist_head devList;
14592 - const char *name;
14594 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
14595 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
14596 +struct yaffs_DeviceParamStruct {
14597 + const YCHAR *name;
14600 + * Entry parameters set up way early. Yaffs sets up the rest.
14601 + * The structure should be zeroed out before use so that unused
14602 + * and defualt values are zero.
14605 + int inbandTags; /* Use unband tags */
14606 + __u32 totalBytesPerChunk; /* Should be >= 512, does not need to be a power of 2 */
14607 int nChunksPerBlock; /* does not need to be a power of 2 */
14608 int spareBytesPerChunk; /* spare area size */
14609 int startBlock; /* Start block we're allowed to use */
14610 @@ -545,24 +533,24 @@ struct yaffs_DeviceStruct {
14611 /* reserved blocks on NOR and RAM. */
14614 - /* Stuff used by the shared space checkpointing mechanism */
14615 - /* If this value is zero, then this mechanism is disabled */
14617 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
14620 int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
14621 - * the number of short op caches (don't use too many)
14622 + * the number of short op caches (don't use too many).
14623 + * 10 to 20 is a good bet.
14625 + int useNANDECC; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
14626 + int noTagsECC; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
14628 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14629 + int isYaffs2; /* Use yaffs2 mode on this device */
14631 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
14632 + int emptyLostAndFound; /* Auto-empty lost+found directory on mount */
14634 - void *genericDevice; /* Pointer to device context
14635 - * On an mtd this holds the mtd pointer.
14637 - void *superBlock;
14638 + int refreshPeriod; /* How often we should check to do a block refresh */
14640 + /* Checkpoint control. Can be set before or after initialisation */
14641 + __u8 skipCheckpointRead;
14642 + __u8 skipCheckpointWrite;
14644 + int enableXattr; /* Enable xattribs */
14646 /* NAND access functions (Must be set before calling YAFFS)*/
14648 @@ -589,58 +577,68 @@ struct yaffs_DeviceStruct {
14649 yaffs_BlockState *state, __u32 *sequenceNumber);
14654 /* The removeObjectCallback function must be supplied by OS flavours that
14655 - * need it. The Linux kernel does not use this, but yaffs direct does use
14656 - * it to implement the faster readdir
14658 + * yaffs direct uses it to implement the faster readdir.
14659 + * Linux uses it to protect the directory during unlocking.
14661 void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
14663 - /* Callback to mark the superblock dirsty */
14664 - void (*markSuperBlockDirty)(void *superblock);
14665 + /* Callback to mark the superblock dirty */
14666 + void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev);
14668 + /* Callback to control garbage collection. */
14669 + unsigned (*gcControl)(struct yaffs_DeviceStruct *dev);
14671 + /* Debug control flags. Don't use unless you know what you're doing */
14672 + int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14673 + int disableLazyLoad; /* Disable lazy loading on this device */
14674 int wideTnodesDisabled; /* Set to disable wide tnodes */
14675 + int disableSoftDelete; /* yaffs 1 only: Set to disable the use of softdeletion. */
14677 + int deferDirectoryUpdate; /* Set to defer directory updates */
14679 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14682 + int alwaysCheckErased; /* Force chunk erased check always on */
14685 - YCHAR *pathDividers; /* String of legal path dividers */
14686 +typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam;
14688 +struct yaffs_DeviceStruct {
14689 + struct yaffs_DeviceParamStruct param;
14691 - /* End of stuff that must be set before initialisation. */
14692 + /* Context storage. Holds extra OS specific data for this device */
14694 - /* Checkpoint control. Can be set before or after initialisation */
14695 - __u8 skipCheckpointRead;
14696 - __u8 skipCheckpointWrite;
14698 + void *driverContext;
14700 + struct ylist_head devList;
14702 /* Runtime parameters. Set up by YAFFS. */
14703 + int nDataBytesPerChunk;
14705 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
14706 + /* Non-wide tnode stuff */
14707 + __u16 chunkGroupBits; /* Number of bits that need to be resolved if
14708 + * the tnodes are not wide enough.
14710 __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
14712 /* Stuff to support wide tnodes */
14717 /* Stuff for figuring out file offset to chunk conversions */
14718 __u32 chunkShift; /* Shift value */
14719 __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
14720 __u32 chunkMask; /* Mask to use for power-of-2 case */
14722 - /* Stuff to handle inband tags */
14724 - __u32 totalBytesPerChunk;
14728 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
14729 - struct semaphore grossLock; /* Gross locking semaphore */
14730 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
14731 - * at compile time so we have to allocate it.
14733 - void (*putSuperFunc) (struct super_block *sb);
14740 int isCheckpointed;
14743 @@ -682,51 +680,31 @@ struct yaffs_DeviceStruct {
14744 __u32 allocationPage;
14745 int allocationBlockFinder; /* Used to search for next allocation block */
14747 - /* Runtime state */
14748 - int nTnodesCreated;
14749 - yaffs_Tnode *freeTnodes;
14751 - yaffs_TnodeList *allocatedTnodeList;
14757 - int nObjectsCreated;
14758 - yaffs_Object *freeObjects;
14759 - int nFreeObjects;
14760 + /* Object and Tnode memory management */
14767 - yaffs_ObjectList *allocatedObjectList;
14769 yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
14770 + __u32 bucketFinder;
14774 - int currentDirtyChecker; /* Used to find current dirtiest block */
14776 + /* Garbage collection control */
14777 __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
14778 - int nonAggressiveSkip; /* GC state/mode */
14784 - int nBlockErasures;
14785 - int nErasureFailures;
14787 - int garbageCollections;
14788 - int passiveGarbageCollections;
14789 - int nRetriedWrites;
14790 - int nRetiredBlocks;
14793 - int tagsEccFixed;
14794 - int tagsEccUnfixed;
14796 - int nUnmarkedDeletions;
14798 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14799 + unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14800 + unsigned gcDisable;
14801 + unsigned gcBlockFinder;
14802 + unsigned gcDirtiest;
14803 + unsigned gcPagesInUse;
14804 + unsigned gcNotDone;
14805 + unsigned gcBlock;
14806 + unsigned gcChunk;
14809 /* Special directories */
14810 yaffs_Object *rootDir;
14811 @@ -743,8 +721,6 @@ struct yaffs_DeviceStruct {
14812 yaffs_ChunkCache *srCache;
14817 /* Stuff for background deletion and unlinked files.*/
14818 yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
14819 yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
14820 @@ -753,7 +729,6 @@ struct yaffs_DeviceStruct {
14821 int nUnlinkedFiles; /* Count of unlinked files. */
14822 int nBackgroundDeletions; /* Count of background deletions. */
14825 /* Temporary buffer management */
14826 yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
14828 @@ -764,6 +739,36 @@ struct yaffs_DeviceStruct {
14829 /* yaffs2 runtime stuff */
14830 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14831 unsigned oldestDirtySequence;
14832 + unsigned oldestDirtyBlock;
14834 + /* Block refreshing */
14835 + int refreshSkip; /* A skip down counter. Refresh happens when this gets to zero. */
14837 + /* Dirty directory handling */
14838 + struct ylist_head dirtyDirectories; /* List of dirty directories */
14842 + __u32 nPageWrites;
14843 + __u32 nPageReads;
14844 + __u32 nBlockErasures;
14845 + __u32 nErasureFailures;
14848 + __u32 passiveGCs;
14849 + __u32 oldestDirtyGCs;
14851 + __u32 backgroundGCs;
14852 + __u32 nRetriedWrites;
14853 + __u32 nRetiredBlocks;
14855 + __u32 eccUnfixed;
14856 + __u32 tagsEccFixed;
14857 + __u32 tagsEccUnfixed;
14858 + __u32 nDeletions;
14859 + __u32 nUnmarkedDeletions;
14860 + __u32 refreshCount;
14865 @@ -796,7 +801,6 @@ typedef struct {
14867 /* yaffs2 runtime stuff */
14868 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14869 - unsigned oldestDirtySequence;
14871 } yaffs_CheckpointDevice;
14873 @@ -809,6 +813,23 @@ typedef struct {
14874 } yaffs_CheckpointValidity;
14877 +struct yaffs_ShadowFixerStruct {
14880 + struct yaffs_ShadowFixerStruct *next;
14883 +/* Structure for doing xattr modifications */
14885 + int set; /* If 0 then this is a deletion */
14886 + const YCHAR *name;
14887 + const void *data;
14894 /*----------------------- YAFFS Functions -----------------------*/
14896 int yaffs_GutsInitialise(yaffs_Device *dev);
14897 @@ -840,7 +861,8 @@ int yaffs_ResizeFile(yaffs_Object *obj,
14899 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
14900 __u32 mode, __u32 uid, __u32 gid);
14901 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
14903 +int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync);
14905 /* Flushing and checkpointing */
14906 void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
14907 @@ -873,6 +895,12 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Objec
14908 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
14909 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
14912 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags);
14913 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size);
14914 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size);
14915 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name);
14917 /* Special directories */
14918 yaffs_Object *yaffs_Root(yaffs_Device *dev);
14919 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
14920 @@ -882,18 +910,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Dev
14921 void yfsd_WinFileTimeNow(__u32 target[2]);
14926 void yaffs_HandleDeferedFree(yaffs_Object *obj);
14929 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev);
14931 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency);
14934 int yaffs_DumpObject(yaffs_Object *obj);
14936 void yaffs_GutsTest(yaffs_Device *dev);
14938 -/* A few useful functions */
14939 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
14940 +/* A few useful functions to be used within the core files*/
14941 void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
14942 int yaffs_CheckFF(__u8 *buffer, int nBytes);
14943 void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
14944 @@ -901,4 +929,41 @@ void yaffs_HandleChunkError(yaffs_Device
14945 __u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
14946 void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
14948 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
14950 + yaffs_ObjectType type);
14951 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
14952 + int chunkInNAND, int inScan);
14953 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name);
14954 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh);
14955 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14956 + yaffs_Object *obj);
14957 +YCHAR *yaffs_CloneString(const YCHAR *str);
14958 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
14959 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo);
14960 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
14961 + int force, int isShrink, int shadows,
14962 + yaffs_XAttrMod *xop);
14963 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
14964 + int backwardScanning);
14965 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks);
14966 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev);
14967 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
14968 + yaffs_FileStructure *fStruct,
14970 + yaffs_Tnode *passedTn);
14972 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
14973 + int nBytes, int writeThrough);
14974 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize);
14975 +void yaffs_SkipRestOfBlock(yaffs_Device *dev);
14977 +int yaffs_CountFreeChunks(yaffs_Device *dev);
14979 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
14980 + yaffs_FileStructure *fStruct,
14983 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
14986 diff -Nrup a/fs/yaffs2/yaffsinterface.h b/fs/yaffs2/yaffsinterface.h
14987 --- a/fs/yaffs2/yaffsinterface.h 2010-10-03 17:29:32.916000361 +0300
14988 +++ b/fs/yaffs2/yaffsinterface.h 2010-10-03 18:03:47.543000365 +0300
14991 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14993 - * Copyright (C) 2002-2007 Aleph One Ltd.
14994 + * Copyright (C) 2002-2010 Aleph One Ltd.
14995 * for Toby Churchill Ltd and Brightstar Engineering
14997 * Created by Charles Manning <charles@aleph1.co.uk>
14998 diff -Nrup a/fs/yaffs2/yaffs_linux_allocator.c b/fs/yaffs2/yaffs_linux_allocator.c
14999 --- a/fs/yaffs2/yaffs_linux_allocator.c 1970-01-01 02:00:00.000000000 +0200
15000 +++ b/fs/yaffs2/yaffs_linux_allocator.c 2010-10-03 18:03:47.519000366 +0300
15003 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15005 + * Copyright (C) 2002-2010 Aleph One Ltd.
15006 + * for Toby Churchill Ltd and Brightstar Engineering
15008 + * Created by Charles Manning <charles@aleph1.co.uk>
15010 + * This program is free software; you can redistribute it and/or modify
15011 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15012 + * published by the Free Software Foundation.
15014 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15016 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
15020 +#include "yaffs_allocator.h"
15021 +#include "yaffs_guts.h"
15022 +#include "yaffs_trace.h"
15023 +#include "yportenv.h"
15024 +#include "yaffs_linux.h"
15026 + * Start out with the same allocator as yaffs direct.
15027 + * Todo: Change to Linux slab allocator.
15032 +#define NAMELEN 20
15033 +struct yaffs_AllocatorStruct {
15034 + char tnode_name[NAMELEN+1];
15035 + char object_name[NAMELEN+1];
15036 + struct kmem_cache *tnode_cache;
15037 + struct kmem_cache *object_cache;
15040 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
15044 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
15046 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
15048 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
15051 + if(allocator->tnode_cache){
15052 + kmem_cache_destroy(allocator->tnode_cache);
15053 + allocator->tnode_cache = NULL;
15055 + T(YAFFS_TRACE_ALWAYS,
15056 + (TSTR("NULL tnode cache\n")));
15060 + if(allocator->object_cache){
15061 + kmem_cache_destroy(allocator->object_cache);
15062 + allocator->object_cache = NULL;
15064 + T(YAFFS_TRACE_ALWAYS,
15065 + (TSTR("NULL object cache\n")));
15069 + YFREE(allocator);
15072 + T(YAFFS_TRACE_ALWAYS,
15073 + (TSTR("Deinitialising NULL allocator\n")));
15076 + dev->allocator = NULL;
15080 +static void fake_ctor0(void *data){data = data;}
15081 +static void fake_ctor1(void *data){data = data;}
15082 +static void fake_ctor2(void *data){data = data;}
15083 +static void fake_ctor3(void *data){data = data;}
15084 +static void fake_ctor4(void *data){data = data;}
15085 +static void fake_ctor5(void *data){data = data;}
15086 +static void fake_ctor6(void *data){data = data;}
15087 +static void fake_ctor7(void *data){data = data;}
15088 +static void fake_ctor8(void *data){data = data;}
15089 +static void fake_ctor9(void *data){data = data;}
15091 +static void (*fake_ctor_list[10]) (void *) = {
15104 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
15106 + yaffs_Allocator *allocator;
15107 + unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id;
15109 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
15111 + if(dev->allocator)
15113 + else if(mount_id >= 10){
15114 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
15116 + allocator = YMALLOC(sizeof(yaffs_Allocator));
15117 + memset(allocator,0,sizeof(yaffs_Allocator));
15118 + dev->allocator = allocator;
15120 + if(!dev->allocator){
15121 + T(YAFFS_TRACE_ALWAYS,
15122 + (TSTR("yaffs allocator creation failed\n")));
15128 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
15129 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
15131 + allocator->tnode_cache =
15132 + kmem_cache_create(allocator->tnode_name,
15135 + fake_ctor_list[mount_id]);
15136 + if(allocator->tnode_cache)
15137 + T(YAFFS_TRACE_ALLOCATE,
15138 + (TSTR("tnode cache \"%s\" %p\n"),
15139 + allocator->tnode_name,allocator->tnode_cache));
15141 + T(YAFFS_TRACE_ALWAYS,
15142 + (TSTR("yaffs cache creation failed\n")));
15147 + allocator->object_cache =
15148 + kmem_cache_create(allocator->object_name,
15149 + sizeof(yaffs_Object),
15151 + fake_ctor_list[mount_id]);
15153 + if(allocator->object_cache)
15154 + T(YAFFS_TRACE_ALLOCATE,
15155 + (TSTR("object cache \"%s\" %p\n"),
15156 + allocator->object_name,allocator->object_cache));
15159 + T(YAFFS_TRACE_ALWAYS,
15160 + (TSTR("yaffs cache creation failed\n")));
15167 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
15169 + yaffs_Allocator *allocator = dev->allocator;
15170 + if(!allocator || !allocator->tnode_cache){
15174 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
15177 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
15179 + yaffs_Allocator *allocator = dev->allocator;
15180 + kmem_cache_free(allocator->tnode_cache,tn);
15183 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
15185 + yaffs_Allocator *allocator = dev->allocator;
15190 + if(!allocator->object_cache){
15194 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
15197 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
15199 + yaffs_Allocator *allocator = dev->allocator;
15200 + kmem_cache_free(allocator->object_cache,obj);
15202 diff -Nrup a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h
15203 --- a/fs/yaffs2/yaffs_linux.h 1970-01-01 02:00:00.000000000 +0200
15204 +++ b/fs/yaffs2/yaffs_linux.h 2010-10-03 18:03:47.544000367 +0300
15207 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15209 + * Copyright (C) 2002-2010 Aleph One Ltd.
15210 + * for Toby Churchill Ltd and Brightstar Engineering
15212 + * Created by Charles Manning <charles@aleph1.co.uk>
15214 + * This program is free software; you can redistribute it and/or modify
15215 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15216 + * published by the Free Software Foundation.
15218 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15221 +#ifndef __YAFFS_LINUX_H__
15222 +#define __YAFFS_LINUX_H__
15224 +#include "devextras.h"
15225 +#include "yportenv.h"
15227 +struct yaffs_LinuxContext {
15228 + struct ylist_head contextList; /* List of these we have mounted */
15229 + struct yaffs_DeviceStruct *dev;
15230 + struct super_block * superBlock;
15231 + struct task_struct *bgThread; /* Background thread for this device */
15233 + struct semaphore grossLock; /* Gross locking semaphore */
15234 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
15235 + * at compile time so we have to allocate it.
15237 + struct ylist_head searchContexts;
15238 + void (*putSuperFunc)(struct super_block *sb);
15240 + struct task_struct *readdirProcess;
15241 + unsigned mount_id;
15244 +#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext))
15245 +#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext))
15249 diff -Nrup a/fs/yaffs2/yaffs_list.h b/fs/yaffs2/yaffs_list.h
15250 --- a/fs/yaffs2/yaffs_list.h 1970-01-01 02:00:00.000000000 +0200
15251 +++ b/fs/yaffs2/yaffs_list.h 2010-10-03 18:03:47.544000367 +0300
15254 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15256 + * Copyright (C) 2002-2010 Aleph One Ltd.
15257 + * for Toby Churchill Ltd and Brightstar Engineering
15259 + * Created by Charles Manning <charles@aleph1.co.uk>
15261 + * This program is free software; you can redistribute it and/or modify
15262 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15263 + * published by the Free Software Foundation.
15265 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15269 + * This file is just holds extra declarations of macros that would normally
15270 + * be providesd in the Linux kernel. These macros have been written from
15271 + * scratch but are functionally equivalent to the Linux ones.
15275 +#ifndef __YAFFS_LIST_H__
15276 +#define __YAFFS_LIST_H__
15279 +#include "yportenv.h"
15282 + * This is a simple doubly linked list implementation that matches the
15283 + * way the Linux kernel doubly linked list implementation works.
15286 +struct ylist_head {
15287 + struct ylist_head *next; /* next in chain */
15288 + struct ylist_head *prev; /* previous in chain */
15292 +/* Initialise a static list */
15293 +#define YLIST_HEAD(name) \
15294 +struct ylist_head name = { &(name), &(name)}
15298 +/* Initialise a list head to an empty list */
15299 +#define YINIT_LIST_HEAD(p) \
15301 + (p)->next = (p);\
15302 + (p)->prev = (p); \
15306 +/* Add an element to a list */
15307 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
15308 + struct ylist_head *list)
15310 + struct ylist_head *listNext = list->next;
15312 + list->next = newEntry;
15313 + newEntry->prev = list;
15314 + newEntry->next = listNext;
15315 + listNext->prev = newEntry;
15319 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
15320 + struct ylist_head *list)
15322 + struct ylist_head *listPrev = list->prev;
15324 + list->prev = newEntry;
15325 + newEntry->next = list;
15326 + newEntry->prev = listPrev;
15327 + listPrev->next = newEntry;
15332 +/* Take an element out of its current list, with or without
15333 + * reinitialising the links.of the entry*/
15334 +static Y_INLINE void ylist_del(struct ylist_head *entry)
15336 + struct ylist_head *listNext = entry->next;
15337 + struct ylist_head *listPrev = entry->prev;
15339 + listNext->prev = listPrev;
15340 + listPrev->next = listNext;
15344 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
15346 + ylist_del(entry);
15347 + entry->next = entry->prev = entry;
15351 +/* Test if the list is empty */
15352 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
15354 + return (entry->next == entry);
15358 +/* ylist_entry takes a pointer to a list entry and offsets it to that
15359 + * we can find a pointer to the object it is embedded in.
15363 +#define ylist_entry(entry, type, member) \
15364 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
15367 +/* ylist_for_each and list_for_each_safe iterate over lists.
15368 + * ylist_for_each_safe uses temporary storage to make the list delete safe
15371 +#define ylist_for_each(itervar, list) \
15372 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
15374 +#define ylist_for_each_safe(itervar, saveVar, list) \
15375 + for (itervar = (list)->next, saveVar = (list)->next->next; \
15376 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
15380 diff -Nrup a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
15381 --- a/fs/yaffs2/yaffs_mtdif1.c 2010-10-03 17:48:22.719000363 +0300
15382 +++ b/fs/yaffs2/yaffs_mtdif1.c 2010-10-03 18:03:47.519000366 +0300
15384 * YAFFS: Yet another FFS. A NAND-flash specific file system.
15385 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15387 - * Copyright (C) 2002 Aleph One Ltd.
15388 + * Copyright (C) 2002-2010 Aleph One Ltd.
15389 * for Toby Churchill Ltd and Brightstar Engineering
15391 * This program is free software; you can redistribute it and/or modify
15395 #include "yportenv.h"
15396 +#include "yaffs_trace.h"
15397 #include "yaffs_guts.h"
15398 #include "yaffs_packedtags1.h"
15399 #include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
15400 +#include "yaffs_linux.h"
15402 #include "linux/kernel.h"
15403 #include "linux/version.h"
15405 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15406 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
15408 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
15410 #ifndef CONFIG_YAFFS_9BYTE_TAGS
15411 # define YTAG1_SIZE 8
15413 @@ -91,7 +91,7 @@ static struct nand_ecclayout nand_oob_16
15414 int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15415 int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
15417 - struct mtd_info *mtd = dev->genericDevice;
15418 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15419 int chunkBytes = dev->nDataBytesPerChunk;
15420 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15421 struct mtd_oob_ops ops;
15422 @@ -102,8 +102,6 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15423 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15424 compile_time_assertion(sizeof(yaffs_Tags) == 8);
15426 - dev->nPageWrites++;
15428 yaffs_PackTags1(&pt1, etags);
15429 yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15431 @@ -137,9 +135,9 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15433 retval = mtd->write_oob(mtd, addr, &ops);
15435 - yaffs_trace(YAFFS_TRACE_MTD,
15436 - "write_oob failed, chunk %d, mtd error %d\n",
15437 - chunkInNAND, retval);
15438 + T(YAFFS_TRACE_MTD,
15439 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
15440 + chunkInNAND, retval));
15442 return retval ? YAFFS_FAIL : YAFFS_OK;
15444 @@ -171,7 +169,7 @@ static int rettags(yaffs_ExtendedTags *e
15445 int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15446 int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
15448 - struct mtd_info *mtd = dev->genericDevice;
15449 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15450 int chunkBytes = dev->nDataBytesPerChunk;
15451 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15452 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15453 @@ -180,8 +178,6 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15457 - dev->nPageReads++;
15459 memset(&ops, 0, sizeof(ops));
15460 ops.mode = MTD_OOB_AUTO;
15461 ops.len = (data) ? chunkBytes : 0;
15462 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15464 retval = mtd->read_oob(mtd, addr, &ops);
15466 - yaffs_trace(YAFFS_TRACE_MTD,
15467 - "read_oob failed, chunk %d, mtd error %d\n",
15468 - chunkInNAND, retval);
15469 + T(YAFFS_TRACE_MTD,
15470 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
15471 + chunkInNAND, retval));
15475 @@ -284,11 +280,11 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15477 int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15479 - struct mtd_info *mtd = dev->genericDevice;
15480 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15481 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15482 + int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk;
15485 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
15486 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), blockNo));
15488 retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15489 return (retval) ? YAFFS_FAIL : YAFFS_OK;
15490 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
15491 int oobavail = mtd->ecclayout->oobavail;
15493 if (oobavail < YTAG1_SIZE) {
15494 - yaffs_trace(YAFFS_TRACE_ERROR,
15495 - "mtd device has only %d bytes for tags, need %d\n",
15496 - oobavail, YTAG1_SIZE);
15497 + T(YAFFS_TRACE_ERROR,
15498 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
15499 + oobavail, YTAG1_SIZE));
15503 @@ -325,8 +321,8 @@ static int nandmtd1_TestPrerequists(stru
15504 int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15505 yaffs_BlockState *pState, __u32 *pSequenceNumber)
15507 - struct mtd_info *mtd = dev->genericDevice;
15508 - int chunkNo = blockNo * dev->nChunksPerBlock;
15509 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15510 + int chunkNo = blockNo * dev->param.nChunksPerBlock;
15511 loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
15512 yaffs_ExtendedTags etags;
15513 int state = YAFFS_BLOCK_STATE_DEAD;
15514 @@ -342,8 +338,8 @@ int nandmtd1_QueryNANDBlock(struct yaffs
15515 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15516 etags.blockBad = (mtd->block_isbad)(mtd, addr);
15517 if (etags.blockBad) {
15518 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15519 - "block %d is marked bad\n", blockNo);
15520 + T(YAFFS_TRACE_BAD_BLOCKS,
15521 + (TSTR("block %d is marked bad"TENDSTR), blockNo));
15522 state = YAFFS_BLOCK_STATE_DEAD;
15523 } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
15524 /* bad tags, need to look more closely */
15525 diff -Nrup a/fs/yaffs2/yaffs_mtdif1-compat.c b/fs/yaffs2/yaffs_mtdif1-compat.c
15526 --- a/fs/yaffs2/yaffs_mtdif1-compat.c 2010-10-03 17:29:32.916000361 +0300
15527 +++ b/fs/yaffs2/yaffs_mtdif1-compat.c 1970-01-01 02:00:00.000000000 +0200
15529 -From ian@brightstareng.com Fri May 18 15:06:49 2007
15530 -From ian@brightstareng.com Fri May 18 15:08:21 2007
15531 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
15532 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
15533 - (envelope-from <ian@brightstareng.com>)
15534 - id 1Hp380-00011e-T6
15535 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
15536 -Received: from localhost (localhost.localdomain [127.0.0.1])
15537 - by zebra.brightstareng.com (Postfix) with ESMTP
15538 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
15539 -Received: from zebra.brightstareng.com ([127.0.0.1])
15540 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
15541 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
15542 -Received: from pippin (unknown [192.168.1.25])
15543 - by zebra.brightstareng.com (Postfix) with ESMTP
15544 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
15545 -From: Ian McDonnell <ian@brightstareng.com>
15546 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
15547 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
15548 -Date: Fri, 18 May 2007 10:06:49 -0400
15549 -User-Agent: KMail/1.9.1
15550 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
15551 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
15552 -Cc: Andrea Conti <alyf@alyf.net>,
15553 - Charles Manning <manningc2@actrix.gen.nz>
15555 -Content-Type: Multipart/Mixed;
15556 - boundary="Boundary-00=_5LbTGmt62YoutxM"
15557 -Message-Id: <200705181006.49860.ian@brightstareng.com>
15558 -X-Virus-Scanned: by amavisd-new at brightstareng.com
15561 -X-KMail-EncryptionState:
15562 -X-KMail-SignatureState:
15565 ---Boundary-00=_5LbTGmt62YoutxM
15566 -Content-Type: text/plain;
15567 - charset="iso-8859-15"
15568 -Content-Transfer-Encoding: 7bit
15569 -Content-Disposition: inline
15573 -On Friday 18 May 2007 08:34, you wrote:
15574 -> Yea team. With this fix in place (I put it in the wrong place
15575 -> at first) I can now mount and ls the Yaffs partition without
15576 -> an error messages!
15580 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
15581 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
15582 -See the LINUX_VERSION_CODE conditional in
15583 -nandmtd1_ReadChunkWithTagsFromNAND.
15587 ---Boundary-00=_5LbTGmt62YoutxM
15588 -Content-Type: text/x-csrc;
15589 - charset="iso-8859-15";
15590 - name="yaffs_mtdif1.c"
15591 -Content-Transfer-Encoding: 7bit
15592 -Content-Disposition: attachment;
15593 - filename="yaffs_mtdif1.c"
15596 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
15597 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15599 - * Copyright (C) 2002 Aleph One Ltd.
15600 - * for Toby Churchill Ltd and Brightstar Engineering
15602 - * This program is free software; you can redistribute it and/or modify
15603 - * it under the terms of the GNU General Public License version 2 as
15604 - * published by the Free Software Foundation.
15608 - * This module provides the interface between yaffs_nand.c and the
15609 - * MTD API. This version is used when the MTD interface supports the
15610 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
15611 - * and we have small-page NAND device.
15613 - * These functions are invoked via function pointers in yaffs_nand.c.
15614 - * This replaces functionality provided by functions in yaffs_mtdif.c
15615 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
15616 - * called in yaffs_mtdif.c when the function pointers are NULL.
15617 - * We assume the MTD layer is performing ECC (useNANDECC is true).
15620 -#include "yportenv.h"
15621 -#include "yaffs_guts.h"
15622 -#include "yaffs_packedtags1.h"
15623 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
15625 -#include "linux/kernel.h"
15626 -#include "linux/version.h"
15627 -#include "linux/types.h"
15628 -#include "linux/mtd/mtd.h"
15630 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15631 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
15633 -const char *yaffs_mtdif1_c_version = "$Id$";
15635 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15636 -# define YTAG1_SIZE 8
15638 -# define YTAG1_SIZE 9
15642 -/* Use the following nand_ecclayout with MTD when using
15643 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
15644 - * If you have existing Yaffs images and the byte order differs from this,
15645 - * adjust 'oobfree' to match your existing Yaffs data.
15647 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
15648 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
15651 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
15652 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
15653 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
15654 - * byte and B is the small-page bad-block indicator byte.
15656 -static struct nand_ecclayout nand_oob_16 = {
15658 - .eccpos = { 8, 9, 10, 13, 14, 15 },
15660 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
15664 -/* Write a chunk (page) of data to NAND.
15666 - * Caller always provides ExtendedTags data which are converted to a more
15667 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
15668 - * contents of the tags meta-data; used to valid the tags when read.
15670 - * - Pack ExtendedTags to PackedTags1 form
15671 - * - Compute mini-ECC for PackedTags1
15672 - * - Write data and packed tags to NAND.
15674 - * Note: Due to the use of the PackedTags1 meta-data which does not include
15675 - * a full sequence number (as found in the larger PackedTags2 form) it is
15676 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
15677 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
15678 - * to be written just once. When Yaffs performs this operation, this
15679 - * function is called with a NULL data pointer -- calling MTD write_oob
15680 - * without data is valid usage (2.6.17).
15682 - * Any underlying MTD error results in YAFFS_FAIL.
15683 - * Returns YAFFS_OK or YAFFS_FAIL.
15685 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15686 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
15688 - struct mtd_info * mtd = dev->genericDevice;
15689 - int chunkBytes = dev->nDataBytesPerChunk;
15690 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15691 - struct mtd_oob_ops ops;
15692 - yaffs_PackedTags1 pt1;
15695 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
15696 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15697 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
15699 - yaffs_PackTags1(&pt1, etags);
15700 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15702 - /* When deleting a chunk, the upper layer provides only skeletal
15703 - * etags, one with chunkDeleted set. However, we need to update the
15704 - * tags, not erase them completely. So we use the NAND write property
15705 - * that only zeroed-bits stick and set tag bytes to all-ones and
15706 - * zero just the (not) deleted bit.
15708 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15709 - if (etags->chunkDeleted) {
15710 - memset(&pt1, 0xff, 8);
15711 - /* clear delete status bit to indicate deleted */
15715 - ((__u8 *)&pt1)[8] = 0xff;
15716 - if (etags->chunkDeleted) {
15717 - memset(&pt1, 0xff, 8);
15718 - /* zero pageStatus byte to indicate deleted */
15719 - ((__u8 *)&pt1)[8] = 0;
15723 - memset(&ops, 0, sizeof(ops));
15724 - ops.mode = MTD_OOB_AUTO;
15725 - ops.len = (data) ? chunkBytes : 0;
15726 - ops.ooblen = YTAG1_SIZE;
15727 - ops.datbuf = (__u8 *)data;
15728 - ops.oobbuf = (__u8 *)&pt1;
15730 - retval = mtd->write_oob(mtd, addr, &ops);
15732 - yaffs_trace(YAFFS_TRACE_MTD,
15733 - "write_oob failed, chunk %d, mtd error %d\n",
15734 - chunkInNAND, retval);
15736 - return retval ? YAFFS_FAIL : YAFFS_OK;
15739 -/* Return with empty ExtendedTags but add eccResult.
15741 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
15744 - memset(etags, 0, sizeof(*etags));
15745 - etags->eccResult = eccResult;
15750 -/* Read a chunk (page) from NAND.
15752 - * Caller expects ExtendedTags data to be usable even on error; that is,
15753 - * all members except eccResult and blockBad are zeroed.
15755 - * - Check ECC results for data (if applicable)
15756 - * - Check for blank/erased block (return empty ExtendedTags if blank)
15757 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
15758 - * - Convert PackedTags1 to ExtendedTags
15759 - * - Update eccResult and blockBad members to refect state.
15761 - * Returns YAFFS_OK or YAFFS_FAIL.
15763 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15764 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
15766 - struct mtd_info * mtd = dev->genericDevice;
15767 - int chunkBytes = dev->nDataBytesPerChunk;
15768 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15769 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15770 - struct mtd_oob_ops ops;
15771 - yaffs_PackedTags1 pt1;
15775 - memset(&ops, 0, sizeof(ops));
15776 - ops.mode = MTD_OOB_AUTO;
15777 - ops.len = (data) ? chunkBytes : 0;
15778 - ops.ooblen = YTAG1_SIZE;
15779 - ops.datbuf = data;
15780 - ops.oobbuf = (__u8 *)&pt1;
15782 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
15783 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
15784 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
15786 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
15788 - /* Read page and oob using MTD.
15789 - * Check status and determine ECC result.
15791 - retval = mtd->read_oob(mtd, addr, &ops);
15793 - yaffs_trace(YAFFS_TRACE_MTD,
15794 - "read_oob failed, chunk %d, mtd error %d\n",
15795 - chunkInNAND, retval);
15798 - switch (retval) {
15804 - /* MTD's ECC fixed the data */
15805 - eccres = YAFFS_ECC_RESULT_FIXED;
15810 - /* MTD's ECC could not fix the data */
15811 - dev->eccUnfixed++;
15812 - /* fall into... */
15814 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
15815 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
15816 - return YAFFS_FAIL;
15819 - /* Check for a blank/erased chunk.
15821 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
15822 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
15823 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
15826 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15827 - /* Read deleted status (bit) then return it to it's non-deleted
15828 - * state before performing tags mini-ECC check. pt1.deleted is
15831 - deleted = !pt1.deleted;
15834 - (void) deleted; /* not used */
15837 - /* Check the packed tags mini-ECC and correct if necessary/possible.
15839 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
15840 - switch (retval) {
15842 - /* no tags error, use MTD result */
15845 - /* recovered tags-ECC error */
15846 - dev->tagsEccFixed++;
15847 - eccres = YAFFS_ECC_RESULT_FIXED;
15850 - /* unrecovered tags-ECC error */
15851 - dev->tagsEccUnfixed++;
15852 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
15855 - /* Unpack the tags to extended form and set ECC result.
15856 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
15858 - pt1.shouldBeFF = 0xFFFFFFFF;
15859 - yaffs_UnpackTags1(etags, &pt1);
15860 - etags->eccResult = eccres;
15862 - /* Set deleted state.
15864 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15865 - etags->chunkDeleted = deleted;
15867 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
15872 -/* Mark a block bad.
15874 - * This is a persistant state.
15875 - * Use of this function should be rare.
15877 - * Returns YAFFS_OK or YAFFS_FAIL.
15879 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15881 - struct mtd_info * mtd = dev->genericDevice;
15882 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15885 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
15887 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15888 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
15891 -/* Check any MTD prerequists.
15893 - * Returns YAFFS_OK or YAFFS_FAIL.
15895 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
15897 - /* 2.6.18 has mtd->ecclayout->oobavail */
15898 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
15899 - int oobavail = mtd->ecclayout->oobavail;
15901 - if (oobavail < YTAG1_SIZE) {
15902 - yaffs_trace(YAFFS_TRACE_ERROR,
15903 - "mtd device has only %d bytes for tags, need %d",
15904 - oobavail, YTAG1_SIZE);
15905 - return YAFFS_FAIL;
15910 -/* Query for the current state of a specific block.
15912 - * Examine the tags of the first chunk of the block and return the state:
15913 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
15914 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
15915 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
15917 - * Always returns YAFFS_OK.
15919 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15920 - yaffs_BlockState * pState, int *pSequenceNumber)
15922 - struct mtd_info * mtd = dev->genericDevice;
15923 - int chunkNo = blockNo * dev->nChunksPerBlock;
15924 - yaffs_ExtendedTags etags;
15925 - int state = YAFFS_BLOCK_STATE_DEAD;
15929 - /* We don't yet have a good place to test for MTD config prerequists.
15930 - * Do it here as we are called during the initial scan.
15932 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
15933 - return YAFFS_FAIL;
15936 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15937 - if (etags.blockBad) {
15938 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15939 - "block %d is marked bad", blockNo);
15940 - state = YAFFS_BLOCK_STATE_DEAD;
15942 - else if (etags.chunkUsed) {
15943 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
15944 - seqnum = etags.sequenceNumber;
15947 - state = YAFFS_BLOCK_STATE_EMPTY;
15951 - *pSequenceNumber = seqnum;
15953 - /* query always succeeds */
15957 -#endif /*KERNEL_VERSION*/
15959 ---Boundary-00=_5LbTGmt62YoutxM--
15963 diff -Nrup a/fs/yaffs2/yaffs_mtdif1.h b/fs/yaffs2/yaffs_mtdif1.h
15964 --- a/fs/yaffs2/yaffs_mtdif1.h 2010-10-03 17:48:22.719000363 +0300
15965 +++ b/fs/yaffs2/yaffs_mtdif1.h 2010-10-03 18:03:47.545000367 +0300
15968 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
15970 - * Copyright (C) 2002-2007 Aleph One Ltd.
15971 + * Copyright (C) 2002-2010 Aleph One Ltd.
15972 * for Toby Churchill Ltd and Brightstar Engineering
15974 * This program is free software; you can redistribute it and/or modify
15975 diff -Nrup a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
15976 --- a/fs/yaffs2/yaffs_mtdif2.c 2010-10-03 17:48:22.720000363 +0300
15977 +++ b/fs/yaffs2/yaffs_mtdif2.c 2010-10-03 18:03:47.520000367 +0300
15980 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
15982 - * Copyright (C) 2002-2007 Aleph One Ltd.
15983 + * Copyright (C) 2002-2010 Aleph One Ltd.
15984 * for Toby Churchill Ltd and Brightstar Engineering
15986 * Created by Charles Manning <charles@aleph1.co.uk>
15989 /* mtd interface for YAFFS2 */
15991 -const char *yaffs_mtdif2_c_version =
15992 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
15994 #include "yportenv.h"
15996 +#include "yaffs_trace.h"
15998 #include "yaffs_mtdif2.h"
16000 @@ -27,6 +24,8 @@ const char *yaffs_mtdif2_c_version =
16002 #include "yaffs_packedtags2.h"
16004 +#include "yaffs_linux.h"
16006 /* NB For use with inband tags....
16007 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
16008 * use it to load the tags.
16009 @@ -35,7 +34,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16011 const yaffs_ExtendedTags *tags)
16013 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16014 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16015 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16016 struct mtd_oob_ops ops;
16018 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16020 yaffs_PackedTags2 pt;
16022 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
16023 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt;
16027 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
16028 TENDSTR), chunkInNAND, data, tags));
16031 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16032 + addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16034 /* For yaffs2 writing there must be both data and tags.
16035 * If we're using inband tags, then the tags are stuffed into
16036 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16038 if (!data || !tags)
16040 - else if (dev->inbandTags) {
16041 + else if (dev->param.inbandTags) {
16042 yaffs_PackedTags2TagsPart *pt2tp;
16043 pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
16044 yaffs_PackTags2TagsPart(pt2tp, tags);
16046 - yaffs_PackTags2(&pt, tags);
16047 + yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC);
16049 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16050 ops.mode = MTD_OOB_AUTO;
16051 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
16052 - ops.len = dev->totalBytesPerChunk;
16053 + ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size;
16054 + ops.len = dev->param.totalBytesPerChunk;
16056 ops.datbuf = (__u8 *)data;
16057 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
16058 + ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr;
16059 retval = mtd->write_oob(mtd, addr, &ops);
16062 - if (!dev->inbandTags) {
16063 + if (!dev->param.inbandTags) {
16065 mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16066 - &dummy, data, (__u8 *) &pt, NULL);
16067 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
16070 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
16071 + mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy,
16075 @@ -98,7 +100,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16076 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
16077 __u8 *data, yaffs_ExtendedTags *tags)
16079 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16080 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16081 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16082 struct mtd_oob_ops ops;
16084 @@ -106,16 +108,19 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16088 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16089 + loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16091 yaffs_PackedTags2 pt;
16093 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
16094 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt;
16098 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
16099 TENDSTR), chunkInNAND, data, tags));
16101 - if (dev->inbandTags) {
16102 + if (dev->param.inbandTags) {
16106 @@ -127,20 +132,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16109 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16110 - if (dev->inbandTags || (data && !tags))
16111 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
16112 + if (dev->param.inbandTags || (data && !tags))
16113 + retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk,
16116 ops.mode = MTD_OOB_AUTO;
16117 - ops.ooblen = sizeof(pt);
16118 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
16119 + ops.ooblen = packed_tags_size;
16120 + ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size;
16123 - ops.oobbuf = dev->spareBuffer;
16124 + ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer;
16125 retval = mtd->read_oob(mtd, addr, &ops);
16128 - if (!dev->inbandTags && data && tags) {
16129 + if (!dev->param.inbandTags && data && tags) {
16131 retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16132 &dummy, data, dev->spareBuffer,
16133 @@ -150,7 +155,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16135 mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16137 - if (!dev->inbandTags && tags)
16138 + if (!dev->param.inbandTags && tags)
16140 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
16142 @@ -158,7 +163,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16146 - if (dev->inbandTags) {
16147 + if (dev->param.inbandTags) {
16149 yaffs_PackedTags2TagsPart *pt2tp;
16150 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
16151 @@ -166,16 +171,22 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16155 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
16156 - yaffs_UnpackTags2(tags, &pt);
16157 + memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size);
16158 + yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC);
16163 yaffs_ReleaseTempBuffer(dev, data, __LINE__);
16165 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
16166 + if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16167 tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
16168 + dev->eccUnfixed++;
16170 + if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16171 + tags->eccResult = YAFFS_ECC_RESULT_FIXED;
16177 @@ -184,15 +195,15 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16179 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
16181 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16182 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16185 (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
16188 mtd->block_markbad(mtd,
16189 - blockNo * dev->nChunksPerBlock *
16190 - dev->totalBytesPerChunk);
16191 + blockNo * dev->param.nChunksPerBlock *
16192 + dev->param.totalBytesPerChunk);
16196 @@ -204,15 +215,15 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
16197 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
16198 yaffs_BlockState *state, __u32 *sequenceNumber)
16200 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16201 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16205 (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
16207 mtd->block_isbad(mtd,
16208 - blockNo * dev->nChunksPerBlock *
16209 - dev->totalBytesPerChunk);
16210 + blockNo * dev->param.nChunksPerBlock *
16211 + dev->param.totalBytesPerChunk);
16214 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
16215 @@ -223,7 +234,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs
16216 yaffs_ExtendedTags t;
16217 nandmtd2_ReadChunkWithTagsFromNAND(dev,
16219 - dev->nChunksPerBlock, NULL,
16220 + dev->param.nChunksPerBlock, NULL,
16224 diff -Nrup a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h
16225 --- a/fs/yaffs2/yaffs_mtdif2.h 2010-10-03 17:48:22.720000363 +0300
16226 +++ b/fs/yaffs2/yaffs_mtdif2.h 2010-10-03 18:03:47.545000367 +0300
16229 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16231 - * Copyright (C) 2002-2007 Aleph One Ltd.
16232 + * Copyright (C) 2002-2010 Aleph One Ltd.
16233 * for Toby Churchill Ltd and Brightstar Engineering
16235 * Created by Charles Manning <charles@aleph1.co.uk>
16236 diff -Nrup a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c
16237 --- a/fs/yaffs2/yaffs_mtdif.c 2010-10-03 17:48:22.720000363 +0300
16238 +++ b/fs/yaffs2/yaffs_mtdif.c 2010-10-03 18:03:47.521000367 +0300
16241 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16243 - * Copyright (C) 2002-2007 Aleph One Ltd.
16244 + * Copyright (C) 2002-2010 Aleph One Ltd.
16245 * for Toby Churchill Ltd and Brightstar Engineering
16247 * Created by Charles Manning <charles@aleph1.co.uk>
16249 * published by the Free Software Foundation.
16252 -const char *yaffs_mtdif_c_version =
16253 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
16255 #include "yportenv.h"
16258 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
16259 #include "linux/time.h"
16260 #include "linux/mtd/nand.h"
16262 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
16263 -static struct nand_oobinfo yaffs_oobinfo = {
16266 - .eccpos = {8, 9, 10, 13, 14, 15}
16269 -static struct nand_oobinfo yaffs_noeccinfo = {
16274 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16275 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
16277 - oob[0] = spare->tagByte0;
16278 - oob[1] = spare->tagByte1;
16279 - oob[2] = spare->tagByte2;
16280 - oob[3] = spare->tagByte3;
16281 - oob[4] = spare->tagByte4;
16282 - oob[5] = spare->tagByte5 & 0x3f;
16283 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
16284 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
16285 - oob[6] = spare->tagByte6;
16286 - oob[7] = spare->tagByte7;
16289 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
16291 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
16292 - spare->tagByte0 = oob[0];
16293 - spare->tagByte1 = oob[1];
16294 - spare->tagByte2 = oob[2];
16295 - spare->tagByte3 = oob[3];
16296 - spare->tagByte4 = oob[4];
16297 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
16298 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
16299 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
16300 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
16301 - spare->tagByte6 = oob[6];
16302 - spare->tagByte7 = oob[7];
16303 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
16305 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
16309 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16310 - const __u8 *data, const yaffs_Spare *spare)
16312 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16313 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16314 - struct mtd_oob_ops ops;
16319 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16320 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16321 - __u8 spareAsBytes[8]; /* OOB */
16323 - if (data && !spare)
16324 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
16326 - else if (spare) {
16327 - if (dev->useNANDECC) {
16328 - translate_spare2oob(spare, spareAsBytes);
16329 - ops.mode = MTD_OOB_AUTO;
16330 - ops.ooblen = 8; /* temp hack */
16332 - ops.mode = MTD_OOB_RAW;
16333 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16335 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16336 - ops.datbuf = (u8 *)data;
16338 - ops.oobbuf = spareAsBytes;
16339 - retval = mtd->write_oob(mtd, addr, &ops);
16342 - __u8 *spareAsBytes = (__u8 *) spare;
16344 - if (data && spare) {
16345 - if (dev->useNANDECC)
16347 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16348 - &dummy, data, spareAsBytes,
16352 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16353 - &dummy, data, spareAsBytes,
16354 - &yaffs_noeccinfo);
16358 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16362 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16363 - &dummy, spareAsBytes);
16370 - return YAFFS_FAIL;
16373 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16374 - yaffs_Spare *spare)
16376 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16377 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16378 - struct mtd_oob_ops ops;
16383 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16384 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16385 - __u8 spareAsBytes[8]; /* OOB */
16387 - if (data && !spare)
16388 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
16390 - else if (spare) {
16391 - if (dev->useNANDECC) {
16392 - ops.mode = MTD_OOB_AUTO;
16393 - ops.ooblen = 8; /* temp hack */
16395 - ops.mode = MTD_OOB_RAW;
16396 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16398 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16399 - ops.datbuf = data;
16401 - ops.oobbuf = spareAsBytes;
16402 - retval = mtd->read_oob(mtd, addr, &ops);
16403 - if (dev->useNANDECC)
16404 - translate_oob2spare(spare, spareAsBytes);
16407 - __u8 *spareAsBytes = (__u8 *) spare;
16409 - if (data && spare) {
16410 - if (dev->useNANDECC) {
16411 - /* Careful, this call adds 2 ints */
16412 - /* to the end of the spare data. Calling function */
16413 - /* should allocate enough memory for spare, */
16414 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
16416 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16417 - &dummy, data, spareAsBytes,
16421 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16422 - &dummy, data, spareAsBytes,
16423 - &yaffs_noeccinfo);
16428 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16432 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16433 - &dummy, spareAsBytes);
16440 - return YAFFS_FAIL;
16442 +#include "yaffs_linux.h"
16444 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
16446 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16447 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16449 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
16450 - * dev->nChunksPerBlock;
16451 + ((loff_t) blockNumber) * dev->param.totalBytesPerChunk
16452 + * dev->param.nChunksPerBlock;
16453 struct erase_info ei;
16459 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
16460 + ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock;
16463 ei.callback = NULL;
16464 ei.priv = (u_long) dev;
16466 - /* Todo finish off the ei if required */
16468 - sema_init(&dev->sem, 0);
16470 retval = mtd->erase(mtd, &ei);
16473 diff -Nrup a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h
16474 --- a/fs/yaffs2/yaffs_mtdif.h 2010-10-03 17:48:22.721000363 +0300
16475 +++ b/fs/yaffs2/yaffs_mtdif.h 2010-10-03 18:03:47.546000366 +0300
16478 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16480 - * Copyright (C) 2002-2007 Aleph One Ltd.
16481 + * Copyright (C) 2002-2010 Aleph One Ltd.
16482 * for Toby Churchill Ltd and Brightstar Engineering
16484 * Created by Charles Manning <charles@aleph1.co.uk>
16486 extern struct nand_oobinfo yaffs_oobinfo;
16487 extern struct nand_oobinfo yaffs_noeccinfo;
16490 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16491 - const __u8 *data, const yaffs_Spare *spare);
16492 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16493 - yaffs_Spare *spare);
16494 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
16495 int nandmtd_InitialiseNAND(yaffs_Device *dev);
16497 diff -Nrup a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c
16498 --- a/fs/yaffs2/yaffs_nameval.c 1970-01-01 02:00:00.000000000 +0200
16499 +++ b/fs/yaffs2/yaffs_nameval.c 2010-10-03 18:03:47.523000363 +0300
16502 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16504 + * Copyright (C) 2002-2010 Aleph One Ltd.
16505 + * for Toby Churchill Ltd and Brightstar Engineering
16507 + * Created by Charles Manning <charles@aleph1.co.uk>
16509 + * This program is free software; you can redistribute it and/or modify
16510 + * it under the terms of the GNU General Public License version 2 as
16511 + * published by the Free Software Foundation.
16515 + * This simple implementation of a name-value store assumes a small number of values and fits
16516 + * into a small finite buffer.
16518 + * Each attribute is stored as a record:
16519 + * sizeof(int) bytes record size.
16520 + * strnlen+1 bytes name null terminated.
16523 + * total size stored in record size
16525 + * This code has not been tested with unicode yet.
16529 +#include "yaffs_nameval.h"
16531 +#include "yportenv.h"
16533 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
16539 + memcpy(&size,xb,sizeof(int));
16540 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16541 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
16543 + *exist_size = size;
16547 + if(pos < xb_size -sizeof(int))
16548 + memcpy(&size,xb + pos,sizeof(int));
16557 +static int nval_used(const char *xb, int xb_size)
16562 + memcpy(&size,xb + pos,sizeof(int));
16563 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16565 + if(pos < xb_size -sizeof(int))
16566 + memcpy(&size,xb + pos,sizeof(int));
16573 +int nval_del(char *xb, int xb_size, const YCHAR *name)
16575 + int pos = nval_find(xb, xb_size, name, NULL);
16578 + if(pos >= 0 && pos < xb_size){
16579 + /* Find size, shift rest over this record, then zero out the rest of buffer */
16580 + memcpy(&size,xb+pos,sizeof(int));
16581 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
16582 + memset(xb + (xb_size - size),0,size);
16588 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
16591 + int namelen = yaffs_strnlen(name,xb_size);
16593 + int size_exist = 0;
16597 + pos = nval_find(xb,xb_size,name, &size_exist);
16599 + if(flags & XATTR_CREATE && pos >= 0)
16601 + if(flags & XATTR_REPLACE && pos < 0)
16604 + start = nval_used(xb,xb_size);
16605 + space = xb_size - start + size_exist;
16607 + reclen = (sizeof(int) + namelen + 1 + bsize);
16609 + if(reclen > space)
16613 + nval_del(xb,xb_size,name);
16614 + start = nval_used(xb, xb_size);
16619 + memcpy(xb + pos,&reclen,sizeof(int));
16620 + pos +=sizeof(int);
16621 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
16622 + pos+= (namelen+1);
16623 + memcpy(xb + pos,buf,bsize);
16627 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
16629 + int pos = nval_find(xb,xb_size,name,NULL);
16632 + if(pos >= 0 && pos< xb_size){
16634 + memcpy(&size,xb +pos,sizeof(int));
16635 + pos+=sizeof(int); /* advance past record length */
16636 + size -= sizeof(int);
16638 + /* Advance over name string */
16639 + while(xb[pos] && size > 0 && pos < xb_size){
16643 + /*Advance over NUL */
16647 + if(size <= bsize){
16648 + memcpy(buf,xb + pos,size);
16659 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
16667 + memcpy(&size,xb + pos,sizeof(int));
16668 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
16669 + pos+= sizeof(int);
16670 + size-=sizeof(int);
16671 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
16672 + if(ncopied + name_len + 1 < bsize){
16673 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
16677 + if(sizeof(YCHAR) > 1){
16681 + ncopied += (name_len+1);
16685 + if(pos < xb_size -sizeof(int))
16686 + memcpy(&size,xb + pos,sizeof(int));
16694 +int nval_hasvalues(const char *xb, int xb_size)
16696 + return nval_used(xb, xb_size) > 0;
16698 diff -Nrup a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h
16699 --- a/fs/yaffs2/yaffs_nameval.h 1970-01-01 02:00:00.000000000 +0200
16700 +++ b/fs/yaffs2/yaffs_nameval.h 2010-10-03 18:03:47.546000366 +0300
16703 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16705 + * Copyright (C) 2002-2010 Aleph One Ltd.
16706 + * for Toby Churchill Ltd and Brightstar Engineering
16708 + * Created by Charles Manning <charles@aleph1.co.uk>
16710 + * This program is free software; you can redistribute it and/or modify
16711 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16712 + * published by the Free Software Foundation.
16714 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16716 +#ifndef __NAMEVAL_H__
16717 +#define __NAMEVAL_H__
16719 +#include "yportenv.h"
16721 +int nval_del(char *xb, int xb_size, const YCHAR *name);
16722 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
16723 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
16724 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
16725 +int nval_hasvalues(const char *xb, int xb_size);
16727 diff -Nrup a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
16728 --- a/fs/yaffs2/yaffs_nand.c 2010-10-03 17:48:22.721000363 +0300
16729 +++ b/fs/yaffs2/yaffs_nand.c 2010-10-03 18:03:47.524000359 +0300
16732 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16734 - * Copyright (C) 2002-2007 Aleph One Ltd.
16735 + * Copyright (C) 2002-2010 Aleph One Ltd.
16736 * for Toby Churchill Ltd and Brightstar Engineering
16738 * Created by Charles Manning <charles@aleph1.co.uk>
16740 * published by the Free Software Foundation.
16743 -const char *yaffs_nand_c_version =
16744 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
16746 #include "yaffs_nand.h"
16747 #include "yaffs_tagscompat.h"
16748 #include "yaffs_tagsvalidity.h"
16749 @@ -29,12 +26,14 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16751 int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
16753 + dev->nPageReads++;
16755 /* If there are no tags provided, use local tags to get prioritised gc working */
16759 - if (dev->readChunkWithTagsFromNAND)
16760 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16761 + if (dev->param.readChunkWithTagsFromNAND)
16762 + result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16765 result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
16766 @@ -44,7 +43,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16768 tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
16770 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
16771 + yaffs_BlockInfo *bi;
16772 + bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock);
16773 yaffs_HandleChunkError(dev, bi);
16776 @@ -56,6 +56,9 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16777 const __u8 *buffer,
16778 yaffs_ExtendedTags *tags)
16781 + dev->nPageWrites++;
16783 chunkInNAND -= dev->chunkOffset;
16786 @@ -75,8 +78,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16790 - if (dev->writeChunkWithTagsToNAND)
16791 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16792 + if (dev->param.writeChunkWithTagsToNAND)
16793 + return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16796 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
16797 @@ -89,9 +92,9 @@ int yaffs_MarkBlockBad(yaffs_Device *dev
16799 blockNo -= dev->blockOffset;
16802 - if (dev->markNANDBlockBad)
16803 - return dev->markNANDBlockBad(dev, blockNo);
16805 + if (dev->param.markNANDBlockBad)
16806 + return dev->param.markNANDBlockBad(dev, blockNo);
16808 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
16810 @@ -103,8 +106,8 @@ int yaffs_QueryInitialBlockState(yaffs_D
16812 blockNo -= dev->blockOffset;
16814 - if (dev->queryNANDBlock)
16815 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
16816 + if (dev->param.queryNANDBlock)
16817 + return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber);
16819 return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
16821 @@ -119,16 +122,18 @@ int yaffs_EraseBlockInNAND(struct yaffs_
16823 blockInNAND -= dev->blockOffset;
16826 dev->nBlockErasures++;
16827 - result = dev->eraseBlockInNAND(dev, blockInNAND);
16829 + result = dev->param.eraseBlockInNAND(dev, blockInNAND);
16834 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
16836 - return dev->initialiseNAND(dev);
16837 + if(dev->param.initialiseNAND)
16838 + return dev->param.initialiseNAND(dev);
16843 diff -Nrup a/fs/yaffs2/yaffs_nandemul2k.h b/fs/yaffs2/yaffs_nandemul2k.h
16844 --- a/fs/yaffs2/yaffs_nandemul2k.h 2010-10-03 17:48:22.721000364 +0300
16845 +++ b/fs/yaffs2/yaffs_nandemul2k.h 2010-10-03 18:03:47.546000366 +0300
16848 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16850 - * Copyright (C) 2002-2007 Aleph One Ltd.
16851 + * Copyright (C) 2002-2010 Aleph One Ltd.
16852 * for Toby Churchill Ltd and Brightstar Engineering
16854 * Created by Charles Manning <charles@aleph1.co.uk>
16855 diff -Nrup a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
16856 --- a/fs/yaffs2/yaffs_nand.h 2010-10-03 17:48:22.721000364 +0300
16857 +++ b/fs/yaffs2/yaffs_nand.h 2010-10-03 18:03:47.547000363 +0300
16860 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16862 - * Copyright (C) 2002-2007 Aleph One Ltd.
16863 + * Copyright (C) 2002-2010 Aleph One Ltd.
16864 * for Toby Churchill Ltd and Brightstar Engineering
16866 * Created by Charles Manning <charles@aleph1.co.uk>
16867 diff -Nrup a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c
16868 --- a/fs/yaffs2/yaffs_packedtags1.c 2010-10-03 17:48:22.721000364 +0300
16869 +++ b/fs/yaffs2/yaffs_packedtags1.c 2010-10-03 18:03:47.524000359 +0300
16872 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16874 - * Copyright (C) 2002-2007 Aleph One Ltd.
16875 + * Copyright (C) 2002-2010 Aleph One Ltd.
16876 * for Toby Churchill Ltd and Brightstar Engineering
16878 * Created by Charles Manning <charles@aleph1.co.uk>
16879 diff -Nrup a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h
16880 --- a/fs/yaffs2/yaffs_packedtags1.h 2010-10-03 17:48:22.721000364 +0300
16881 +++ b/fs/yaffs2/yaffs_packedtags1.h 2010-10-03 18:03:47.547000363 +0300
16884 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16886 - * Copyright (C) 2002-2007 Aleph One Ltd.
16887 + * Copyright (C) 2002-2010 Aleph One Ltd.
16888 * for Toby Churchill Ltd and Brightstar Engineering
16890 * Created by Charles Manning <charles@aleph1.co.uk>
16891 diff -Nrup a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
16892 --- a/fs/yaffs2/yaffs_packedtags2.c 2010-10-03 17:48:22.722000365 +0300
16893 +++ b/fs/yaffs2/yaffs_packedtags2.c 2010-10-03 18:03:47.524000359 +0300
16896 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16898 - * Copyright (C) 2002-2007 Aleph One Ltd.
16899 + * Copyright (C) 2002-2010 Aleph One Ltd.
16900 * for Toby Churchill Ltd and Brightstar Engineering
16902 * Created by Charles Manning <charles@aleph1.co.uk>
16905 #include "yaffs_packedtags2.h"
16906 #include "yportenv.h"
16907 +#include "yaffs_trace.h"
16908 #include "yaffs_tagsvalidity.h"
16910 /* This code packs a set of extended tags into a binary structure for
16911 @@ -96,17 +97,14 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
16915 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
16916 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC)
16918 yaffs_PackTags2TagsPart(&pt->t, t);
16920 -#ifndef YAFFS_IGNORE_TAGS_ECC
16923 yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16924 sizeof(yaffs_PackedTags2TagsPart),
16931 @@ -158,27 +156,24 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
16935 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
16936 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC)
16939 yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16941 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
16942 - /* Page is in use */
16943 -#ifndef YAFFS_IGNORE_TAGS_ECC
16945 - yaffs_ECCOther ecc;
16947 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16949 - (yaffs_PackedTags2TagsPart),
16952 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16954 - (yaffs_PackedTags2TagsPart),
16956 - switch (result) {
16957 + if (pt->t.sequenceNumber != 0xFFFFFFFF &&
16959 + /* Chunk is in use and we need to do ECC */
16961 + yaffs_ECCOther ecc;
16963 + yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16964 + sizeof(yaffs_PackedTags2TagsPart),
16966 + result = yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16967 + sizeof(yaffs_PackedTags2TagsPart),
16969 + switch (result) {
16971 eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16973 @@ -190,9 +185,7 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16976 eccResult = YAFFS_ECC_RESULT_UNKNOWN;
16982 yaffs_UnpackTags2TagsPart(t, &pt->t);
16983 @@ -201,6 +194,5 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16985 yaffs_DumpPackedTags2(pt);
16986 yaffs_DumpTags2(t);
16990 diff -Nrup a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h
16991 --- a/fs/yaffs2/yaffs_packedtags2.h 2010-10-03 17:48:22.722000365 +0300
16992 +++ b/fs/yaffs2/yaffs_packedtags2.h 2010-10-03 18:03:47.547000363 +0300
16995 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16997 - * Copyright (C) 2002-2007 Aleph One Ltd.
16998 + * Copyright (C) 2002-2010 Aleph One Ltd.
16999 * for Toby Churchill Ltd and Brightstar Engineering
17001 * Created by Charles Manning <charles@aleph1.co.uk>
17002 @@ -34,8 +34,8 @@ typedef struct {
17003 } yaffs_PackedTags2;
17005 /* Full packed tags with ECC, used for oob tags */
17006 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
17007 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
17008 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC);
17009 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC);
17011 /* Only the tags part (no ECC for use with inband tags */
17012 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
17013 diff -Nrup a/fs/yaffs2/yaffs_qsort.h b/fs/yaffs2/yaffs_qsort.h
17014 --- a/fs/yaffs2/yaffs_qsort.h 2010-10-03 17:48:22.724000363 +0300
17015 +++ b/fs/yaffs2/yaffs_qsort.h 2010-10-03 18:03:47.548000359 +0300
17018 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17020 - * Copyright (C) 2002-2007 Aleph One Ltd.
17021 + * Copyright (C) 2002-2010 Aleph One Ltd.
17022 * for Toby Churchill Ltd and Brightstar Engineering
17024 * Created by Charles Manning <charles@aleph1.co.uk>
17026 #ifndef __YAFFS_QSORT_H__
17027 #define __YAFFS_QSORT_H__
17030 +#include <linux/sort.h>
17032 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
17033 + int (*cmp)(const void *, const void *)){
17034 + sort(base, total_elems, size, cmp, NULL);
17039 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
17040 int (*cmp)(const void *, const void *));
17044 diff -Nrup a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
17045 --- a/fs/yaffs2/yaffs_tagscompat.c 2010-10-03 17:48:22.724000363 +0300
17046 +++ b/fs/yaffs2/yaffs_tagscompat.c 2010-10-03 18:03:47.525000359 +0300
17049 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17051 - * Copyright (C) 2002-2007 Aleph One Ltd.
17052 + * Copyright (C) 2002-2010 Aleph One Ltd.
17053 * for Toby Churchill Ltd and Brightstar Engineering
17055 * Created by Charles Manning <charles@aleph1.co.uk>
17057 #include "yaffs_tagscompat.h"
17058 #include "yaffs_ecc.h"
17059 #include "yaffs_getblockinfo.h"
17060 +#include "yaffs_trace.h"
17062 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
17064 @@ -163,15 +164,14 @@ static int yaffs_WriteChunkToNAND(struct
17065 int chunkInNAND, const __u8 *data,
17066 yaffs_Spare *spare)
17068 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
17069 + if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) {
17070 T(YAFFS_TRACE_ERROR,
17071 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
17076 - dev->nPageWrites++;
17077 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
17078 + return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare);
17081 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
17082 @@ -184,16 +184,14 @@ static int yaffs_ReadChunkFromNAND(struc
17084 yaffs_Spare localSpare;
17086 - dev->nPageReads++;
17088 if (!spare && data) {
17089 /* If we don't have a real spare, then we use a local one. */
17090 /* Need this for the calculation of the ecc */
17091 spare = &localSpare;
17094 - if (!dev->useNANDECC) {
17095 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
17096 + if (!dev->param.useNANDECC) {
17097 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare);
17098 if (data && doErrorCorrection) {
17099 /* Do ECC correction */
17100 /* Todo handle any errors */
17101 @@ -254,7 +252,7 @@ static int yaffs_ReadChunkFromNAND(struc
17103 memset(&nspare, 0, sizeof(nspare));
17105 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
17106 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data,
17107 (yaffs_Spare *) &nspare);
17108 memcpy(spare, &nspare, sizeof(yaffs_Spare));
17109 if (data && doErrorCorrection) {
17110 @@ -307,10 +305,10 @@ static int yaffs_CheckChunkErased(struct
17111 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
17112 static __u8 data[YAFFS_BYTES_PER_CHUNK];
17113 /* Might as well always allocate the larger size for */
17114 - /* dev->useNANDECC == true; */
17115 + /* dev->param.useNANDECC == true; */
17116 static __u8 spare[sizeof(struct yaffs_NANDSpare)];
17118 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17119 + dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17122 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
17123 @@ -333,7 +331,7 @@ static int yaffs_CheckChunkErased(struct
17125 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
17127 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17128 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17130 /* Mark the block for retirement */
17131 yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
17132 @@ -365,7 +363,7 @@ static void yaffs_HandleUpdateChunk(yaff
17134 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
17136 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17137 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17139 /* Mark the block for retirement */
17140 yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
17141 @@ -424,7 +422,7 @@ int yaffs_TagsCompatabilityWriteChunkWit
17143 tags.serialNumber = eTags->serialNumber;
17145 - if (!dev->useNANDECC && data)
17146 + if (!dev->param.useNANDECC && data)
17147 yaffs_CalcECC(data, &spare);
17149 yaffs_LoadTagsIntoSpare(&spare, &tags);
17150 @@ -498,9 +496,9 @@ int yaffs_TagsCompatabilityMarkNANDBlock
17152 spare.blockStatus = 'Y';
17154 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
17155 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL,
17157 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
17158 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1,
17162 @@ -525,9 +523,9 @@ int yaffs_TagsCompatabilityQueryNANDBloc
17164 *sequenceNumber = 0;
17166 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
17167 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL,
17168 &spare0, &dummy, 1);
17169 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
17170 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL,
17171 &spare1, &dummy, 1);
17173 if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
17174 diff -Nrup a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h
17175 --- a/fs/yaffs2/yaffs_tagscompat.h 2010-10-03 17:48:22.724000363 +0300
17176 +++ b/fs/yaffs2/yaffs_tagscompat.h 2010-10-03 18:03:47.548000359 +0300
17179 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17181 - * Copyright (C) 2002-2007 Aleph One Ltd.
17182 + * Copyright (C) 2002-2010 Aleph One Ltd.
17183 * for Toby Churchill Ltd and Brightstar Engineering
17185 * Created by Charles Manning <charles@aleph1.co.uk>
17186 diff -Nrup a/fs/yaffs2/yaffs_tagsvalidity.c b/fs/yaffs2/yaffs_tagsvalidity.c
17187 --- a/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-03 17:48:22.725000363 +0300
17188 +++ b/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-03 18:03:47.526000362 +0300
17191 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17193 - * Copyright (C) 2002-2007 Aleph One Ltd.
17194 + * Copyright (C) 2002-2010 Aleph One Ltd.
17195 * for Toby Churchill Ltd and Brightstar Engineering
17197 * Created by Charles Manning <charles@aleph1.co.uk>
17198 diff -Nrup a/fs/yaffs2/yaffs_tagsvalidity.h b/fs/yaffs2/yaffs_tagsvalidity.h
17199 --- a/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-03 17:48:22.725000363 +0300
17200 +++ b/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-03 18:03:47.549000359 +0300
17203 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17205 - * Copyright (C) 2002-2007 Aleph One Ltd.
17206 + * Copyright (C) 2002-2010 Aleph One Ltd.
17207 * for Toby Churchill Ltd and Brightstar Engineering
17209 * Created by Charles Manning <charles@aleph1.co.uk>
17210 diff -Nrup a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h
17211 --- a/fs/yaffs2/yaffs_trace.h 1970-01-01 02:00:00.000000000 +0200
17212 +++ b/fs/yaffs2/yaffs_trace.h 2010-10-03 18:03:47.550000362 +0300
17215 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17217 + * Copyright (C) 2002-2010 Aleph One Ltd.
17218 + * for Toby Churchill Ltd and Brightstar Engineering
17220 + * Created by Charles Manning <charles@aleph1.co.uk>
17222 + * This program is free software; you can redistribute it and/or modify
17223 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17224 + * published by the Free Software Foundation.
17226 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17230 +#ifndef __YTRACE_H__
17231 +#define __YTRACE_H__
17233 +extern unsigned int yaffs_traceMask;
17234 +extern unsigned int yaffs_wr_attempts;
17238 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
17241 +#define YAFFS_TRACE_OS 0x00000002
17242 +#define YAFFS_TRACE_ALLOCATE 0x00000004
17243 +#define YAFFS_TRACE_SCAN 0x00000008
17244 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
17245 +#define YAFFS_TRACE_ERASE 0x00000020
17246 +#define YAFFS_TRACE_GC 0x00000040
17247 +#define YAFFS_TRACE_WRITE 0x00000080
17248 +#define YAFFS_TRACE_TRACING 0x00000100
17249 +#define YAFFS_TRACE_DELETION 0x00000200
17250 +#define YAFFS_TRACE_BUFFERS 0x00000400
17251 +#define YAFFS_TRACE_NANDACCESS 0x00000800
17252 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
17253 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
17254 +#define YAFFS_TRACE_MTD 0x00004000
17255 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
17257 +#define YAFFS_TRACE_VERIFY 0x00010000
17258 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
17259 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
17260 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
17262 +#define YAFFS_TRACE_SYNC 0x00100000
17263 +#define YAFFS_TRACE_BACKGROUND 0x00200000
17264 +#define YAFFS_TRACE_LOCK 0x00400000
17266 +#define YAFFS_TRACE_ERROR 0x40000000
17267 +#define YAFFS_TRACE_BUG 0x80000000
17268 +#define YAFFS_TRACE_ALWAYS 0xF0000000
17271 +#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
17274 diff -Nrup a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c
17275 --- a/fs/yaffs2/yaffs_verify.c 1970-01-01 02:00:00.000000000 +0200
17276 +++ b/fs/yaffs2/yaffs_verify.c 2010-10-03 18:03:47.527000365 +0300
17279 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17281 + * Copyright (C) 2002-2010 Aleph One Ltd.
17282 + * for Toby Churchill Ltd and Brightstar Engineering
17284 + * Created by Charles Manning <charles@aleph1.co.uk>
17286 + * This program is free software; you can redistribute it and/or modify
17287 + * it under the terms of the GNU General Public License version 2 as
17288 + * published by the Free Software Foundation.
17292 +#include "yaffs_verify.h"
17293 +#include "yaffs_trace.h"
17294 +#include "yaffs_bitmap.h"
17295 +#include "yaffs_getblockinfo.h"
17296 +#include "yaffs_nand.h"
17298 +int yaffs_SkipVerification(yaffs_Device *dev)
17301 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
17304 +static int yaffs_SkipFullVerification(yaffs_Device *dev)
17307 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
17310 +static int yaffs_SkipNANDVerification(yaffs_Device *dev)
17313 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
17317 +static const char *blockStateName[] = {
17331 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17333 + int actuallyUsed;
17336 + if (yaffs_SkipVerification(dev))
17339 + /* Report illegal runtime states */
17340 + if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
17341 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
17343 + switch (bi->blockState) {
17344 + case YAFFS_BLOCK_STATE_UNKNOWN:
17345 + case YAFFS_BLOCK_STATE_SCANNING:
17346 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
17347 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
17348 + n, blockStateName[bi->blockState]));
17351 + /* Check pages in use and soft deletions are legal */
17353 + actuallyUsed = bi->pagesInUse - bi->softDeletions;
17355 + if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
17356 + bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
17357 + actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
17358 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
17359 + n, bi->pagesInUse, bi->softDeletions));
17362 + /* Check chunk bitmap legal */
17363 + inUse = yaffs_CountChunkBits(dev, n);
17364 + if (inUse != bi->pagesInUse)
17365 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
17366 + n, bi->pagesInUse, inUse));
17372 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17374 + yaffs_VerifyBlock(dev, bi, n);
17376 + /* After collection the block should be in the erased state */
17378 + if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
17379 + bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
17380 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
17381 + n, bi->blockState));
17385 +void yaffs_VerifyBlocks(yaffs_Device *dev)
17388 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
17389 + int nIllegalBlockStates = 0;
17391 + if (yaffs_SkipVerification(dev))
17394 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
17396 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
17397 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
17398 + yaffs_VerifyBlock(dev, bi, i);
17400 + if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
17401 + nBlocksPerState[bi->blockState]++;
17403 + nIllegalBlockStates++;
17406 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17407 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
17409 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
17410 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
17411 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
17413 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
17414 + T(YAFFS_TRACE_VERIFY,
17415 + (TSTR("%s %d blocks"TENDSTR),
17416 + blockStateName[i], nBlocksPerState[i]));
17418 + if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
17419 + T(YAFFS_TRACE_VERIFY,
17420 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
17421 + dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
17423 + if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
17424 + T(YAFFS_TRACE_VERIFY,
17425 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
17426 + dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
17428 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
17429 + T(YAFFS_TRACE_VERIFY,
17430 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
17431 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
17433 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17438 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
17439 + * case those tests will not be performed.
17441 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
17443 + if (obj && yaffs_SkipVerification(obj->myDev))
17446 + if (!(tags && obj && oh)) {
17447 + T(YAFFS_TRACE_VERIFY,
17448 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
17453 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
17454 + oh->type > YAFFS_OBJECT_TYPE_MAX)
17455 + T(YAFFS_TRACE_VERIFY,
17456 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
17457 + tags->objectId, oh->type));
17459 + if (tags->objectId != obj->objectId)
17460 + T(YAFFS_TRACE_VERIFY,
17461 + (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
17462 + tags->objectId, obj->objectId));
17466 + * Check that the object's parent ids match if parentCheck requested.
17468 + * Tests do not apply to the root object.
17471 + if (parentCheck && tags->objectId > 1 && !obj->parent)
17472 + T(YAFFS_TRACE_VERIFY,
17473 + (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
17474 + tags->objectId, oh->parentObjectId));
17476 + if (parentCheck && obj->parent &&
17477 + oh->parentObjectId != obj->parent->objectId &&
17478 + (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
17479 + obj->parent->objectId != YAFFS_OBJECTID_DELETED))
17480 + T(YAFFS_TRACE_VERIFY,
17481 + (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
17482 + tags->objectId, oh->parentObjectId, obj->parent->objectId));
17484 + if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
17485 + T(YAFFS_TRACE_VERIFY,
17486 + (TSTR("Obj %d header name is NULL"TENDSTR),
17489 + if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
17490 + T(YAFFS_TRACE_VERIFY,
17491 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
17497 +/* Not being used, but don't want to throw away yet */
17498 +int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
17499 + __u32 level, int chunkOffset)
17502 + yaffs_Device *dev = obj->myDev;
17508 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
17509 + if (tn->internal[i]) {
17510 + ok = yaffs_VerifyTnodeWorker(obj,
17513 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
17516 + } else if (level == 0) {
17517 + yaffs_ExtendedTags tags;
17518 + __u32 objectId = obj->objectId;
17520 + chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
17522 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
17523 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17525 + if (theChunk > 0) {
17526 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
17527 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17528 + if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
17529 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17530 + objectId, chunkOffset, theChunk,
17531 + tags.objectId, tags.chunkId));
17545 +void yaffs_VerifyFile(yaffs_Object *obj)
17547 + int requiredTallness;
17548 + int actualTallness;
17552 + yaffs_Device *dev;
17553 + yaffs_ExtendedTags tags;
17560 + if (yaffs_SkipVerification(obj->myDev))
17563 + dev = obj->myDev;
17564 + objectId = obj->objectId;
17566 + /* Check file size is consistent with tnode depth */
17567 + lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
17568 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
17569 + requiredTallness = 0;
17571 + x >>= YAFFS_TNODES_INTERNAL_BITS;
17572 + requiredTallness++;
17575 + actualTallness = obj->variant.fileVariant.topLevel;
17577 + /* Check that the chunks in the tnode tree are all correct.
17578 + * We do this by scanning through the tnode tree and
17579 + * checking the tags for every chunk match.
17582 + if (yaffs_SkipNANDVerification(dev))
17585 + for (i = 1; i <= lastChunk; i++) {
17586 + tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
17589 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17590 + if (theChunk > 0) {
17591 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
17592 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17593 + if (tags.objectId != objectId || tags.chunkId != i) {
17594 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17595 + objectId, i, theChunk,
17596 + tags.objectId, tags.chunkId));
17604 +void yaffs_VerifyHardLink(yaffs_Object *obj)
17606 + if (obj && yaffs_SkipVerification(obj->myDev))
17609 + /* Verify sane equivalent object */
17612 +void yaffs_VerifySymlink(yaffs_Object *obj)
17614 + if (obj && yaffs_SkipVerification(obj->myDev))
17617 + /* Verify symlink string */
17620 +void yaffs_VerifySpecial(yaffs_Object *obj)
17622 + if (obj && yaffs_SkipVerification(obj->myDev))
17626 +void yaffs_VerifyObject(yaffs_Object *obj)
17628 + yaffs_Device *dev;
17634 + __u32 chunkInRange;
17635 + __u32 chunkShouldNotBeDeleted;
17636 + __u32 chunkValid;
17641 + if (obj->beingCreated)
17644 + dev = obj->myDev;
17646 + if (yaffs_SkipVerification(dev))
17649 + /* Check sane object header chunk */
17651 + chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
17652 + chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
17654 + chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
17655 + chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
17656 + chunkValid = chunkInRange &&
17657 + yaffs_CheckChunkBit(dev,
17658 + obj->hdrChunk / dev->param.nChunksPerBlock,
17659 + obj->hdrChunk % dev->param.nChunksPerBlock);
17660 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
17662 + if (!obj->fake &&
17663 + (!chunkIdOk || chunkShouldNotBeDeleted)) {
17664 + T(YAFFS_TRACE_VERIFY,
17665 + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
17666 + obj->objectId, obj->hdrChunk,
17667 + chunkIdOk ? "" : ",out of range",
17668 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
17671 + if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
17672 + yaffs_ExtendedTags tags;
17673 + yaffs_ObjectHeader *oh;
17674 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
17676 + oh = (yaffs_ObjectHeader *)buffer;
17678 + yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
17681 + yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
17683 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
17686 + /* Verify it has a parent */
17687 + if (obj && !obj->fake &&
17688 + (!obj->parent || obj->parent->myDev != dev)) {
17689 + T(YAFFS_TRACE_VERIFY,
17690 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
17691 + obj->objectId, obj->parent));
17694 + /* Verify parent is a directory */
17695 + if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17696 + T(YAFFS_TRACE_VERIFY,
17697 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
17698 + obj->objectId, obj->parent->variantType));
17701 + switch (obj->variantType) {
17702 + case YAFFS_OBJECT_TYPE_FILE:
17703 + yaffs_VerifyFile(obj);
17705 + case YAFFS_OBJECT_TYPE_SYMLINK:
17706 + yaffs_VerifySymlink(obj);
17708 + case YAFFS_OBJECT_TYPE_DIRECTORY:
17709 + yaffs_VerifyDirectory(obj);
17711 + case YAFFS_OBJECT_TYPE_HARDLINK:
17712 + yaffs_VerifyHardLink(obj);
17714 + case YAFFS_OBJECT_TYPE_SPECIAL:
17715 + yaffs_VerifySpecial(obj);
17717 + case YAFFS_OBJECT_TYPE_UNKNOWN:
17719 + T(YAFFS_TRACE_VERIFY,
17720 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
17721 + obj->objectId, obj->variantType));
17726 +void yaffs_VerifyObjects(yaffs_Device *dev)
17728 + yaffs_Object *obj;
17730 + struct ylist_head *lh;
17732 + if (yaffs_SkipVerification(dev))
17735 + /* Iterate through the objects in each hash entry */
17737 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
17738 + ylist_for_each(lh, &dev->objectBucket[i].list) {
17740 + obj = ylist_entry(lh, yaffs_Object, hashLink);
17741 + yaffs_VerifyObject(obj);
17748 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
17750 + struct ylist_head *lh;
17751 + yaffs_Object *listObj;
17756 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
17761 + if (yaffs_SkipVerification(obj->myDev))
17764 + if (!obj->parent) {
17765 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
17770 + if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17771 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
17775 + /* Iterate through the objects in each hash entry */
17777 + ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
17779 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17780 + yaffs_VerifyObject(listObj);
17781 + if (obj == listObj)
17786 + if (count != 1) {
17787 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
17792 +void yaffs_VerifyDirectory(yaffs_Object *directory)
17794 + struct ylist_head *lh;
17795 + yaffs_Object *listObj;
17797 + if (!directory) {
17802 + if (yaffs_SkipFullVerification(directory->myDev))
17805 + if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17806 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
17810 + /* Iterate through the objects in each hash entry */
17812 + ylist_for_each(lh, &directory->variant.directoryVariant.children) {
17814 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17815 + if (listObj->parent != directory) {
17816 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
17819 + yaffs_VerifyObjectInDirectory(listObj);
17824 +static int yaffs_freeVerificationFailures;
17826 +void yaffs_VerifyFreeChunks(yaffs_Device *dev)
17831 + if (yaffs_SkipVerification(dev))
17834 + counted = yaffs_CountFreeChunks(dev);
17836 + difference = dev->nFreeChunks - counted;
17838 + if (difference) {
17839 + T(YAFFS_TRACE_ALWAYS,
17840 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
17841 + dev->nFreeChunks, counted, difference));
17842 + yaffs_freeVerificationFailures++;
17846 +int yaffs_VerifyFileSanity(yaffs_Object *in)
17855 + yaffs_Tags localTags;
17856 + yaffs_Tags *tags = &localTags;
17858 + int chunkDeleted;
17860 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
17861 + return YAFFS_FAIL;
17863 + objId = in->objectId;
17864 + fSize = in->variant.fileVariant.fileSize;
17866 + (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
17868 + for (chunk = 1; chunk <= nChunks; chunk++) {
17869 + tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
17874 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
17876 + if (yaffs_CheckChunkBits
17877 + (dev, theChunk / dev->param.nChunksPerBlock,
17878 + theChunk % dev->param.nChunksPerBlock)) {
17880 + yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
17883 + if (yaffs_TagsMatch
17884 + (tags, in->objectId, chunk, chunkDeleted)) {
17894 + /* T(("No level 0 found for %d\n", chunk)); */
17898 + return failed ? YAFFS_FAIL : YAFFS_OK;
17904 diff -Nrup a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h
17905 --- a/fs/yaffs2/yaffs_verify.h 1970-01-01 02:00:00.000000000 +0200
17906 +++ b/fs/yaffs2/yaffs_verify.h 2010-10-03 18:03:47.551000365 +0300
17909 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17911 + * Copyright (C) 2002-2010 Aleph One Ltd.
17912 + * for Toby Churchill Ltd and Brightstar Engineering
17914 + * Created by Charles Manning <charles@aleph1.co.uk>
17916 + * This program is free software; you can redistribute it and/or modify
17917 + * it under the terms of the GNU General Public License version 2 as
17918 + * published by the Free Software Foundation.
17921 +#ifndef __YAFFS_VERIFY_H__
17922 +#define __YAFFS_VERIFY_H__
17924 +#include "yaffs_guts.h"
17926 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17927 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17928 +void yaffs_VerifyBlocks(yaffs_Device *dev);
17930 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck);
17931 +void yaffs_VerifyFile(yaffs_Object *obj);
17932 +void yaffs_VerifyHardLink(yaffs_Object *obj);
17933 +void yaffs_VerifySymlink(yaffs_Object *obj);
17934 +void yaffs_VerifySpecial(yaffs_Object *obj);
17935 +void yaffs_VerifyObject(yaffs_Object *obj);
17936 +void yaffs_VerifyObjects(yaffs_Device *dev);
17937 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj);
17938 +void yaffs_VerifyDirectory(yaffs_Object *directory);
17939 +void yaffs_VerifyFreeChunks(yaffs_Device *dev);
17941 +int yaffs_VerifyFileSanity(yaffs_Object *obj);
17943 +int yaffs_SkipVerification(yaffs_Device *dev);
17947 diff -Nrup a/fs/yaffs2/yaffs_vfs_glue.c b/fs/yaffs2/yaffs_vfs_glue.c
17948 --- a/fs/yaffs2/yaffs_vfs_glue.c 1970-01-01 02:00:00.000000000 +0200
17949 +++ b/fs/yaffs2/yaffs_vfs_glue.c 2010-10-03 18:03:47.557000359 +0300
17952 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17954 + * Copyright (C) 2002-2010 Aleph One Ltd.
17955 + * for Toby Churchill Ltd and Brightstar Engineering
17957 + * Created by Charles Manning <charles@aleph1.co.uk>
17958 + * Acknowledgements:
17959 + * Luc van OostenRyck for numerous patches.
17960 + * Nick Bane for numerous patches.
17961 + * Nick Bane for 2.5/2.6 integration.
17962 + * Andras Toth for mknod rdev issue.
17963 + * Michael Fischer for finding the problem with inode inconsistency.
17964 + * Some code bodily lifted from JFFS
17966 + * This program is free software; you can redistribute it and/or modify
17967 + * it under the terms of the GNU General Public License version 2 as
17968 + * published by the Free Software Foundation.
17973 + * This is the file system front-end to YAFFS that hooks it up to
17977 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
17978 + * this superblock
17979 + * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
17981 + * >> inode->u.generic_ip points to the associated yaffs_Object.
17985 + * There are two variants of the VFS glue code. This variant should compile
17986 + * for any version of Linux.
17988 +#include <linux/version.h>
17990 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
17991 +#define YAFFS_COMPILE_BACKGROUND
17992 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
17993 +#define YAFFS_COMPILE_FREEZER
17997 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
17998 +#define YAFFS_COMPILE_EXPORTFS
18001 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
18002 +#define YAFFS_USE_SETATTR_COPY
18003 +#define YAFFS_USE_TRUNCATE_SETSIZE
18005 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
18006 +#define YAFFS_HAS_EVICT_INODE
18009 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
18010 +#define YAFFS_NEW_FOLLOW_LINK 1
18012 +#define YAFFS_NEW_FOLLOW_LINK 0
18015 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
18016 +#include <linux/config.h>
18019 +#include <linux/kernel.h>
18020 +#include <linux/module.h>
18021 +#include <linux/slab.h>
18022 +#include <linux/init.h>
18023 +#include <linux/fs.h>
18024 +#include <linux/proc_fs.h>
18025 +#include <linux/smp_lock.h>
18026 +#include <linux/pagemap.h>
18027 +#include <linux/mtd/mtd.h>
18028 +#include <linux/interrupt.h>
18029 +#include <linux/string.h>
18030 +#include <linux/ctype.h>
18032 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18033 +#include <linux/namei.h>
18036 +#ifdef YAFFS_COMPILE_EXPORTFS
18037 +#include <linux/exportfs.h>
18040 +#ifdef YAFFS_COMPILE_BACKGROUND
18041 +#include <linux/kthread.h>
18042 +#include <linux/delay.h>
18044 +#ifdef YAFFS_COMPILE_FREEZER
18045 +#include <linux/freezer.h>
18048 +#include <asm/div64.h>
18050 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18052 +#include <linux/statfs.h>
18054 +#define UnlockPage(p) unlock_page(p)
18055 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
18057 +/* FIXME: use sb->s_id instead ? */
18058 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
18062 +#include <linux/locks.h>
18063 +#define BDEVNAME_SIZE 0
18064 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
18066 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
18067 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
18073 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
18074 +#define YPROC_ROOT (&proc_root)
18076 +#define YPROC_ROOT NULL
18079 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
18080 +#define Y_INIT_TIMER(a) init_timer(a)
18082 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
18085 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18086 +#define WRITE_SIZE_STR "writesize"
18087 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
18089 +#define WRITE_SIZE_STR "oobblock"
18090 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
18093 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
18094 +#define YAFFS_USE_WRITE_BEGIN_END 1
18096 +#define YAFFS_USE_WRITE_BEGIN_END 0
18099 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
18100 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
18102 + uint64_t result = partition_size;
18103 + do_div(result, block_size);
18104 + return (uint32_t)result;
18107 +#define YCALCBLOCKS(s, b) ((s)/(b))
18110 +#include <linux/uaccess.h>
18111 +#include <linux/mtd/mtd.h>
18113 +#include "yportenv.h"
18114 +#include "yaffs_trace.h"
18115 +#include "yaffs_guts.h"
18117 +#include "yaffs_linux.h"
18119 +#include "yaffs_mtdif.h"
18120 +#include "yaffs_mtdif1.h"
18121 +#include "yaffs_mtdif2.h"
18123 +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
18124 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
18125 +unsigned int yaffs_auto_checkpoint = 1;
18126 +unsigned int yaffs_gc_control = 1;
18127 +unsigned int yaffs_bg_enable = 1;
18129 +/* Module Parameters */
18130 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18131 +module_param(yaffs_traceMask, uint, 0644);
18132 +module_param(yaffs_wr_attempts, uint, 0644);
18133 +module_param(yaffs_auto_checkpoint, uint, 0644);
18134 +module_param(yaffs_gc_control, uint, 0644);
18135 +module_param(yaffs_bg_enable, uint, 0644);
18137 +MODULE_PARM(yaffs_traceMask, "i");
18138 +MODULE_PARM(yaffs_wr_attempts, "i");
18139 +MODULE_PARM(yaffs_auto_checkpoint, "i");
18140 +MODULE_PARM(yaffs_gc_control, "i");
18143 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
18144 +/* use iget and read_inode */
18145 +#define Y_IGET(sb, inum) iget((sb), (inum))
18146 +static void yaffs_read_inode(struct inode *inode);
18149 +/* Call local equivalent */
18150 +#define YAFFS_USE_OWN_IGET
18151 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
18153 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
18156 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18157 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
18159 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
18162 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
18163 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
18165 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18166 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
18168 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
18172 +#define update_dir_time(dir) do {\
18173 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
18176 +static void yaffs_put_super(struct super_block *sb);
18178 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
18180 +static ssize_t yaffs_hold_space(struct file *f);
18181 +static void yaffs_release_space(struct file *f);
18183 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18184 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
18186 +static int yaffs_file_flush(struct file *file);
18189 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
18190 +static int yaffs_sync_object(struct file *file, int datasync);
18192 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
18196 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
18198 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18199 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
18200 + struct nameidata *n);
18201 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18202 + struct nameidata *n);
18204 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
18205 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
18207 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
18208 + struct dentry *dentry);
18209 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
18210 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
18211 + const char *symname);
18212 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
18214 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18215 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18218 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18221 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
18222 + struct inode *new_dir, struct dentry *new_dentry);
18223 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
18225 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18226 +static int yaffs_sync_fs(struct super_block *sb, int wait);
18227 +static void yaffs_write_super(struct super_block *sb);
18229 +static int yaffs_sync_fs(struct super_block *sb);
18230 +static int yaffs_write_super(struct super_block *sb);
18233 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18234 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
18235 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18236 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
18238 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
18241 +#ifdef YAFFS_HAS_PUT_INODE
18242 +static void yaffs_put_inode(struct inode *inode);
18245 +#ifdef YAFFS_HAS_EVICT_INODE
18246 +static void yaffs_evict_inode(struct inode *);
18248 +static void yaffs_delete_inode(struct inode *);
18249 +static void yaffs_clear_inode(struct inode *);
18252 +static int yaffs_readpage(struct file *file, struct page *page);
18253 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18254 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
18256 +static int yaffs_writepage(struct page *page);
18259 +#ifdef CONFIG_YAFFS_XATTR
18260 +int yaffs_setxattr(struct dentry *dentry, const char *name,
18261 + const void *value, size_t size, int flags);
18262 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
18264 +int yaffs_removexattr(struct dentry *dentry, const char *name);
18265 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
18269 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
18270 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
18271 + loff_t pos, unsigned len, unsigned flags,
18272 + struct page **pagep, void **fsdata);
18273 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
18274 + loff_t pos, unsigned len, unsigned copied,
18275 + struct page *pg, void *fsdadata);
18277 +static int yaffs_prepare_write(struct file *f, struct page *pg,
18278 + unsigned offset, unsigned to);
18279 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
18284 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18286 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18287 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
18288 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18290 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18293 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
18295 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
18297 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
18300 +static struct address_space_operations yaffs_file_address_operations = {
18301 + .readpage = yaffs_readpage,
18302 + .writepage = yaffs_writepage,
18303 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
18304 + .write_begin = yaffs_write_begin,
18305 + .write_end = yaffs_write_end,
18307 + .prepare_write = yaffs_prepare_write,
18308 + .commit_write = yaffs_commit_write,
18313 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
18314 +static const struct file_operations yaffs_file_operations = {
18315 + .read = do_sync_read,
18316 + .write = do_sync_write,
18317 + .aio_read = generic_file_aio_read,
18318 + .aio_write = generic_file_aio_write,
18319 + .mmap = generic_file_mmap,
18320 + .flush = yaffs_file_flush,
18321 + .fsync = yaffs_sync_object,
18322 + .splice_read = generic_file_splice_read,
18323 + .splice_write = generic_file_splice_write,
18324 + .llseek = generic_file_llseek,
18327 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18329 +static const struct file_operations yaffs_file_operations = {
18330 + .read = do_sync_read,
18331 + .write = do_sync_write,
18332 + .aio_read = generic_file_aio_read,
18333 + .aio_write = generic_file_aio_write,
18334 + .mmap = generic_file_mmap,
18335 + .flush = yaffs_file_flush,
18336 + .fsync = yaffs_sync_object,
18337 + .sendfile = generic_file_sendfile,
18342 +static const struct file_operations yaffs_file_operations = {
18343 + .read = generic_file_read,
18344 + .write = generic_file_write,
18345 + .mmap = generic_file_mmap,
18346 + .flush = yaffs_file_flush,
18347 + .fsync = yaffs_sync_object,
18348 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18349 + .sendfile = generic_file_sendfile,
18354 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
18355 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
18357 + void * kaddr = kmap_atomic(page, KM_USER0);
18358 + memset(kaddr + start, 0, end - start);
18359 + kunmap_atomic(kaddr, KM_USER0);
18360 + flush_dcache_page(page);
18365 +static const struct inode_operations yaffs_file_inode_operations = {
18366 + .setattr = yaffs_setattr,
18367 +#ifdef CONFIG_YAFFS_XATTR
18368 + .setxattr = yaffs_setxattr,
18369 + .getxattr = yaffs_getxattr,
18370 + .listxattr = yaffs_listxattr,
18371 + .removexattr = yaffs_removexattr,
18375 +static const struct inode_operations yaffs_symlink_inode_operations = {
18376 + .readlink = yaffs_readlink,
18377 + .follow_link = yaffs_follow_link,
18378 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18379 + .put_link = yaffs_put_link,
18381 + .setattr = yaffs_setattr,
18382 +#ifdef CONFIG_YAFFS_XATTR
18383 + .setxattr = yaffs_setxattr,
18384 + .getxattr = yaffs_getxattr,
18385 + .listxattr = yaffs_listxattr,
18386 + .removexattr = yaffs_removexattr,
18390 +static const struct inode_operations yaffs_dir_inode_operations = {
18391 + .create = yaffs_create,
18392 + .lookup = yaffs_lookup,
18393 + .link = yaffs_link,
18394 + .unlink = yaffs_unlink,
18395 + .symlink = yaffs_symlink,
18396 + .mkdir = yaffs_mkdir,
18397 + .rmdir = yaffs_unlink,
18398 + .mknod = yaffs_mknod,
18399 + .rename = yaffs_rename,
18400 + .setattr = yaffs_setattr,
18401 +#ifdef CONFIG_YAFFS_XATTR
18402 + .setxattr = yaffs_setxattr,
18403 + .getxattr = yaffs_getxattr,
18404 + .listxattr = yaffs_listxattr,
18405 + .removexattr = yaffs_removexattr,
18409 +static const struct file_operations yaffs_dir_operations = {
18410 + .read = generic_read_dir,
18411 + .readdir = yaffs_readdir,
18412 + .fsync = yaffs_sync_object,
18413 + .llseek = yaffs_dir_llseek,
18416 +static const struct super_operations yaffs_super_ops = {
18417 + .statfs = yaffs_statfs,
18419 +#ifndef YAFFS_USE_OWN_IGET
18420 + .read_inode = yaffs_read_inode,
18422 +#ifdef YAFFS_HAS_PUT_INODE
18423 + .put_inode = yaffs_put_inode,
18425 + .put_super = yaffs_put_super,
18426 +#ifdef YAFFS_HAS_EVICT_INODE
18427 + .evict_inode = yaffs_evict_inode,
18429 + .delete_inode = yaffs_delete_inode,
18430 + .clear_inode = yaffs_clear_inode,
18432 + .sync_fs = yaffs_sync_fs,
18433 + .write_super = yaffs_write_super,
18437 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
18439 +#ifdef YAFFS_USE_SETATTR_COPY
18440 + setattr_copy(inode,attr);
18443 + return inode_setattr(inode, attr);
18448 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
18450 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
18451 + truncate_setsize(inode,newsize);
18454 + truncate_inode_pages(&inode->i_data,newsize);
18460 +static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
18462 + return yaffs_gc_control;
18465 +static void yaffs_GrossLock(yaffs_Device *dev)
18467 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
18468 + down(&(yaffs_DeviceToLC(dev)->grossLock));
18469 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
18472 +static void yaffs_GrossUnlock(yaffs_Device *dev)
18474 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
18475 + up(&(yaffs_DeviceToLC(dev)->grossLock));
18478 +#ifdef YAFFS_COMPILE_EXPORTFS
18480 +static struct inode *
18481 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
18483 + return Y_IGET(sb, ino);
18486 +static struct dentry *
18487 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18489 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
18492 +static struct dentry *
18493 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18495 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
18498 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
18501 + struct super_block *sb = dentry->d_inode->i_sb;
18502 + struct dentry *parent = ERR_PTR(-ENOENT);
18503 + struct inode *inode;
18504 + unsigned long parent_ino;
18505 + yaffs_Object *d_obj;
18506 + yaffs_Object *parent_obj;
18508 + d_obj = yaffs_InodeToObject(dentry->d_inode);
18511 + parent_obj = d_obj->parent;
18512 + if (parent_obj) {
18513 + parent_ino = yaffs_GetObjectInode(parent_obj);
18514 + inode = Y_IGET(sb, parent_ino);
18516 + if (IS_ERR(inode)) {
18517 + parent = ERR_CAST(inode);
18519 + parent = d_obtain_alias(inode);
18520 + if (!IS_ERR(parent)) {
18521 + parent = ERR_PTR(-ENOMEM);
18531 +/* Just declare a zero structure as a NULL value implies
18532 + * using the default functions of exportfs.
18535 +static struct export_operations yaffs_export_ops =
18537 + .fh_to_dentry = yaffs2_fh_to_dentry,
18538 + .fh_to_parent = yaffs2_fh_to_parent,
18539 + .get_parent = yaffs2_get_parent,
18544 +/*-----------------------------------------------------------------*/
18545 +/* Directory search context allows us to unlock access to yaffs during
18546 + * filldir without causing problems with the directory being modified.
18547 + * This is similar to the tried and tested mechanism used in yaffs direct.
18549 + * A search context iterates along a doubly linked list of siblings in the
18550 + * directory. If the iterating object is deleted then this would corrupt
18551 + * the list iteration, likely causing a crash. The search context avoids
18552 + * this by using the removeObjectCallback to move the search context to the
18553 + * next object before the object is deleted.
18555 + * Many readdirs (and thus seach conexts) may be alive simulateously so
18556 + * each yaffs_Device has a list of these.
18558 + * A seach context lives for the duration of a readdir.
18560 + * All these functions must be called while yaffs is locked.
18563 +struct yaffs_SearchContext {
18564 + yaffs_Device *dev;
18565 + yaffs_Object *dirObj;
18566 + yaffs_Object *nextReturn;
18567 + struct ylist_head others;
18571 + * yaffs_NewSearch() creates a new search context, initialises it and
18572 + * adds it to the device's search context list.
18574 + * Called at start of readdir.
18576 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
18578 + yaffs_Device *dev = dir->myDev;
18579 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
18581 + sc->dirObj = dir;
18583 + if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18584 + sc->nextReturn = NULL;
18586 + sc->nextReturn = ylist_entry(
18587 + dir->variant.directoryVariant.children.next,
18588 + yaffs_Object,siblings);
18589 + YINIT_LIST_HEAD(&sc->others);
18590 + ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
18596 + * yaffs_EndSearch() disposes of a search context and cleans up.
18598 +static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
18601 + ylist_del(&sc->others);
18607 + * yaffs_SearchAdvance() moves a search context to the next object.
18608 + * Called when the search iterates or when an object removal causes
18609 + * the search context to be moved to the next object.
18611 +static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
18616 + if( sc->nextReturn == NULL ||
18617 + ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18618 + sc->nextReturn = NULL;
18620 + struct ylist_head *next = sc->nextReturn->siblings.next;
18622 + if( next == &sc->dirObj->variant.directoryVariant.children)
18623 + sc->nextReturn = NULL; /* end of list */
18625 + sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
18630 + * yaffs_RemoveObjectCallback() is called when an object is unlinked.
18631 + * We check open search contexts and advance any which are currently
18632 + * on the object being iterated.
18634 +static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
18637 + struct ylist_head *i;
18638 + struct yaffs_SearchContext *sc;
18639 + struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
18642 + /* Iterate through the directory search contexts.
18643 + * If any are currently on the object being removed, then advance
18644 + * the search context to the next object to prevent a hanging pointer.
18646 + ylist_for_each(i, search_contexts) {
18648 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
18649 + if(sc->nextReturn == obj)
18650 + yaffs_SearchAdvance(sc);
18657 +/*-----------------------------------------------------------------*/
18659 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18662 + unsigned char *alias;
18665 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18667 + yaffs_GrossLock(dev);
18669 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18671 + yaffs_GrossUnlock(dev);
18676 + ret = vfs_readlink(dentry, buffer, buflen, alias);
18681 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18682 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18684 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18687 + unsigned char *alias;
18689 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18691 + yaffs_GrossLock(dev);
18693 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18694 + yaffs_GrossUnlock(dev);
18701 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18702 + nd_set_link(nd, alias);
18703 + ret = (int)alias;
18705 + return ERR_PTR(ret);
18707 + ret = vfs_follow_link(nd, alias);
18714 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18715 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
18720 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
18721 + yaffs_Object *obj);
18724 + * Lookup is used to find objects in the fs
18726 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18728 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18729 + struct nameidata *n)
18731 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
18734 + yaffs_Object *obj;
18735 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
18737 + yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
18739 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18740 + yaffs_GrossLock(dev);
18742 + T(YAFFS_TRACE_OS,
18743 + (TSTR("yaffs_lookup for %d:%s\n"),
18744 + yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
18746 + obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
18747 + dentry->d_name.name);
18749 + obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
18751 + /* Can't hold gross lock when calling yaffs_get_inode() */
18752 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18753 + yaffs_GrossUnlock(dev);
18756 + T(YAFFS_TRACE_OS,
18757 + (TSTR("yaffs_lookup found %d\n"), obj->objectId));
18759 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
18762 + T(YAFFS_TRACE_OS,
18763 + (TSTR("yaffs_loookup dentry \n")));
18764 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
18765 + * d_add even if NULL inode */
18767 + /*dget(dentry); // try to solve directory bug */
18768 + d_add(dentry, inode);
18770 + /* return dentry; */
18776 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
18780 +/* added NCB for 2.5/6 compatability - forces add even if inode is
18781 + * NULL which creates dentry hash */
18782 + d_add(dentry, inode);
18788 +#ifdef YAFFS_HAS_PUT_INODE
18790 +/* For now put inode is just for debugging
18791 + * Put inode is called when the inode **structure** is put.
18793 +static void yaffs_put_inode(struct inode *inode)
18795 + T(YAFFS_TRACE_OS,
18796 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
18797 + atomic_read(&inode->i_count)));
18803 +static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj)
18805 + /* Clear the association between the inode and
18806 + * the yaffs_Object.
18808 + obj->myInode = NULL;
18809 + yaffs_InodeToObjectLV(inode) = NULL;
18811 + /* If the object freeing was deferred, then the real
18812 + * free happens now.
18813 + * This should fix the inode inconsistency problem.
18815 + yaffs_HandleDeferedFree(obj);
18818 +#ifdef YAFFS_HAS_EVICT_INODE
18819 +/* yaffs_evict_inode combines into one operation what was previously done in
18820 + * yaffs_clear_inode() and yaffs_delete_inode()
18823 +static void yaffs_evict_inode( struct inode *inode)
18825 + yaffs_Object *obj;
18826 + yaffs_Device *dev;
18827 + int deleteme = 0;
18829 + obj = yaffs_InodeToObject(inode);
18831 + T(YAFFS_TRACE_OS,
18832 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18833 + atomic_read(&inode->i_count),
18834 + obj ? "object exists" : "null object"));
18836 + if (!inode->i_nlink && !is_bad_inode(inode))
18838 + truncate_inode_pages(&inode->i_data,0);
18839 + end_writeback(inode);
18841 + if(deleteme && obj){
18842 + dev = obj->myDev;
18843 + yaffs_GrossLock(dev);
18844 + yaffs_DeleteObject(obj);
18845 + yaffs_GrossUnlock(dev);
18848 + dev = obj->myDev;
18849 + yaffs_GrossLock(dev);
18850 + yaffs_UnstitchObject(inode,obj);
18851 + yaffs_GrossUnlock(dev);
18858 +/* clear is called to tell the fs to release any per-inode data it holds.
18859 + * The object might still exist on disk and is just being thrown out of the cache
18860 + * or else the object has actually been deleted and we're being called via
18862 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
18865 +static void yaffs_clear_inode(struct inode *inode)
18867 + yaffs_Object *obj;
18868 + yaffs_Device *dev;
18870 + obj = yaffs_InodeToObject(inode);
18872 + T(YAFFS_TRACE_OS,
18873 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18874 + atomic_read(&inode->i_count),
18875 + obj ? "object exists" : "null object"));
18878 + dev = obj->myDev;
18879 + yaffs_GrossLock(dev);
18880 + yaffs_UnstitchObject(inode,obj);
18881 + yaffs_GrossUnlock(dev);
18886 +/* delete is called when the link count is zero and the inode
18887 + * is put (ie. nobody wants to know about it anymore, time to
18888 + * delete the file).
18889 + * NB Must call clear_inode()
18891 +static void yaffs_delete_inode(struct inode *inode)
18893 + yaffs_Object *obj = yaffs_InodeToObject(inode);
18894 + yaffs_Device *dev;
18896 + T(YAFFS_TRACE_OS,
18897 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18898 + atomic_read(&inode->i_count),
18899 + obj ? "object exists" : "null object"));
18902 + dev = obj->myDev;
18903 + yaffs_GrossLock(dev);
18904 + yaffs_DeleteObject(obj);
18905 + yaffs_GrossUnlock(dev);
18907 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
18908 + truncate_inode_pages(&inode->i_data, 0);
18910 + clear_inode(inode);
18915 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18916 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
18918 +static int yaffs_file_flush(struct file *file)
18921 + yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
18923 + yaffs_Device *dev = obj->myDev;
18925 + T(YAFFS_TRACE_OS,
18926 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId,
18927 + obj->dirty ? "dirty" : "clean"));
18929 + yaffs_GrossLock(dev);
18931 + yaffs_FlushFile(obj, 1, 0);
18933 + yaffs_GrossUnlock(dev);
18938 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
18940 + /* Lifted from jffs2 */
18942 + yaffs_Object *obj;
18943 + unsigned char *pg_buf;
18946 + yaffs_Device *dev;
18948 + T(YAFFS_TRACE_OS,
18949 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
18950 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
18951 + (unsigned)PAGE_CACHE_SIZE));
18953 + obj = yaffs_DentryToObject(f->f_dentry);
18955 + dev = obj->myDev;
18957 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18958 + BUG_ON(!PageLocked(pg));
18960 + if (!PageLocked(pg))
18964 + pg_buf = kmap(pg);
18965 + /* FIXME: Can kmap fail? */
18967 + yaffs_GrossLock(dev);
18969 + ret = yaffs_ReadDataFromFile(obj, pg_buf,
18970 + pg->index << PAGE_CACHE_SHIFT,
18971 + PAGE_CACHE_SIZE);
18973 + yaffs_GrossUnlock(dev);
18979 + ClearPageUptodate(pg);
18980 + SetPageError(pg);
18982 + SetPageUptodate(pg);
18983 + ClearPageError(pg);
18986 + flush_dcache_page(pg);
18989 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
18993 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
18995 + int ret = yaffs_readpage_nolock(f, pg);
19000 +static int yaffs_readpage(struct file *f, struct page *pg)
19004 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
19005 + ret=yaffs_readpage_unlock(f, pg);
19006 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
19010 +/* writepage inspired by/stolen from smbfs */
19012 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19013 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
19015 +static int yaffs_writepage(struct page *page)
19018 + yaffs_Device *dev;
19019 + struct address_space *mapping = page->mapping;
19020 + struct inode *inode;
19021 + unsigned long end_index;
19023 + yaffs_Object *obj;
19024 + int nWritten = 0;
19030 + inode = mapping->host;
19033 + i_size = i_size_read(inode);
19035 + end_index = i_size >> PAGE_CACHE_SHIFT;
19037 + if(page->index < end_index)
19038 + nBytes = PAGE_CACHE_SIZE;
19040 + nBytes = i_size & (PAGE_CACHE_SIZE -1);
19042 + if (page->index > end_index || !nBytes) {
19043 + T(YAFFS_TRACE_OS,
19044 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
19045 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
19046 + (unsigned)inode->i_size));
19047 + T(YAFFS_TRACE_OS,
19048 + (TSTR(" -> don't care!!\n")));
19050 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
19051 + set_page_writeback(page);
19052 + unlock_page(page);
19053 + end_page_writeback(page);
19058 + if(nBytes != PAGE_CACHE_SIZE)
19059 + zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
19063 + buffer = kmap(page);
19065 + obj = yaffs_InodeToObject(inode);
19066 + dev = obj->myDev;
19067 + yaffs_GrossLock(dev);
19069 + T(YAFFS_TRACE_OS,
19070 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
19071 + (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
19072 + T(YAFFS_TRACE_OS,
19073 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
19074 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19076 + nWritten = yaffs_WriteDataToFile(obj, buffer,
19077 + page->index << PAGE_CACHE_SHIFT, nBytes, 0);
19079 + yaffs_MarkSuperBlockDirty(dev);
19081 + T(YAFFS_TRACE_OS,
19082 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
19083 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19085 + yaffs_GrossUnlock(dev);
19088 + set_page_writeback(page);
19089 + unlock_page(page);
19090 + end_page_writeback(page);
19093 + return (nWritten == nBytes) ? 0 : -ENOSPC;
19097 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19098 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
19099 + loff_t pos, unsigned len, unsigned flags,
19100 + struct page **pagep, void **fsdata)
19102 + struct page *pg = NULL;
19103 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
19106 + int space_held = 0;
19109 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
19110 + pg = grab_cache_page_write_begin(mapping, index, flags);
19112 + pg = __grab_cache_page(mapping, index);
19120 + T(YAFFS_TRACE_OS,
19121 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
19122 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
19124 + /* Get fs space */
19125 + space_held = yaffs_hold_space(filp);
19127 + if (!space_held) {
19132 + /* Update page if required */
19134 + if (!Page_Uptodate(pg))
19135 + ret = yaffs_readpage_nolock(filp, pg);
19140 + /* Happy path return */
19141 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
19146 + T(YAFFS_TRACE_OS,
19147 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
19149 + yaffs_release_space(filp);
19152 + page_cache_release(pg);
19159 +static int yaffs_prepare_write(struct file *f, struct page *pg,
19160 + unsigned offset, unsigned to)
19162 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
19164 + if (!Page_Uptodate(pg))
19165 + return yaffs_readpage_nolock(f, pg);
19170 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19171 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
19172 + loff_t pos, unsigned len, unsigned copied,
19173 + struct page *pg, void *fsdadata)
19176 + void *addr, *kva;
19177 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
19180 + addr = kva + offset_into_page;
19182 + T(YAFFS_TRACE_OS,
19183 + ("yaffs_write_end addr %p pos %x nBytes %d\n",
19184 + addr,(unsigned)pos, copied));
19186 + ret = yaffs_file_write(filp, addr, copied, &pos);
19188 + if (ret != copied) {
19189 + T(YAFFS_TRACE_OS,
19190 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
19192 + SetPageError(pg);
19199 + yaffs_release_space(filp);
19201 + page_cache_release(pg);
19206 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
19209 + void *addr, *kva;
19211 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
19212 + int nBytes = to - offset;
19215 + unsigned spos = pos;
19219 + addr = kva + offset;
19221 + saddr = (unsigned) addr;
19223 + T(YAFFS_TRACE_OS,
19224 + (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"),
19225 + saddr, spos, nBytes));
19227 + nWritten = yaffs_file_write(f, addr, nBytes, &pos);
19229 + if (nWritten != nBytes) {
19230 + T(YAFFS_TRACE_OS,
19231 + (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"),
19232 + nWritten, nBytes));
19233 + SetPageError(pg);
19240 + T(YAFFS_TRACE_OS,
19241 + (TSTR("yaffs_commit_write returning %d\n"),
19242 + nWritten == nBytes ? 0 : nWritten));
19244 + return nWritten == nBytes ? 0 : nWritten;
19249 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
19251 + if (inode && obj) {
19254 + /* Check mode against the variant type and attempt to repair if broken. */
19255 + __u32 mode = obj->yst_mode;
19256 + switch (obj->variantType) {
19257 + case YAFFS_OBJECT_TYPE_FILE:
19258 + if (!S_ISREG(mode)) {
19259 + obj->yst_mode &= ~S_IFMT;
19260 + obj->yst_mode |= S_IFREG;
19264 + case YAFFS_OBJECT_TYPE_SYMLINK:
19265 + if (!S_ISLNK(mode)) {
19266 + obj->yst_mode &= ~S_IFMT;
19267 + obj->yst_mode |= S_IFLNK;
19271 + case YAFFS_OBJECT_TYPE_DIRECTORY:
19272 + if (!S_ISDIR(mode)) {
19273 + obj->yst_mode &= ~S_IFMT;
19274 + obj->yst_mode |= S_IFDIR;
19278 + case YAFFS_OBJECT_TYPE_UNKNOWN:
19279 + case YAFFS_OBJECT_TYPE_HARDLINK:
19280 + case YAFFS_OBJECT_TYPE_SPECIAL:
19286 + inode->i_flags |= S_NOATIME;
19288 + inode->i_ino = obj->objectId;
19289 + inode->i_mode = obj->yst_mode;
19290 + inode->i_uid = obj->yst_uid;
19291 + inode->i_gid = obj->yst_gid;
19292 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
19293 + inode->i_blksize = inode->i_sb->s_blocksize;
19295 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19297 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
19298 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
19299 + inode->i_atime.tv_nsec = 0;
19300 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
19301 + inode->i_mtime.tv_nsec = 0;
19302 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
19303 + inode->i_ctime.tv_nsec = 0;
19305 + inode->i_rdev = obj->yst_rdev;
19306 + inode->i_atime = obj->yst_atime;
19307 + inode->i_mtime = obj->yst_mtime;
19308 + inode->i_ctime = obj->yst_ctime;
19310 + inode->i_size = yaffs_GetObjectFileLength(obj);
19311 + inode->i_blocks = (inode->i_size + 511) >> 9;
19313 + inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19315 + T(YAFFS_TRACE_OS,
19316 + (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"),
19317 + inode->i_mode, inode->i_uid, inode->i_gid,
19318 + (int)inode->i_size, atomic_read(&inode->i_count)));
19320 + switch (obj->yst_mode & S_IFMT) {
19321 + default: /* fifo, device or socket */
19322 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19323 + init_special_inode(inode, obj->yst_mode,
19324 + old_decode_dev(obj->yst_rdev));
19326 + init_special_inode(inode, obj->yst_mode,
19327 + (dev_t) (obj->yst_rdev));
19330 + case S_IFREG: /* file */
19331 + inode->i_op = &yaffs_file_inode_operations;
19332 + inode->i_fop = &yaffs_file_operations;
19333 + inode->i_mapping->a_ops =
19334 + &yaffs_file_address_operations;
19336 + case S_IFDIR: /* directory */
19337 + inode->i_op = &yaffs_dir_inode_operations;
19338 + inode->i_fop = &yaffs_dir_operations;
19340 + case S_IFLNK: /* symlink */
19341 + inode->i_op = &yaffs_symlink_inode_operations;
19345 + yaffs_InodeToObjectLV(inode) = obj;
19347 + obj->myInode = inode;
19350 + T(YAFFS_TRACE_OS,
19351 + (TSTR("yaffs_FileInode invalid parameters\n")));
19356 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
19357 + yaffs_Object *obj)
19359 + struct inode *inode;
19362 + T(YAFFS_TRACE_OS,
19363 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
19369 + T(YAFFS_TRACE_OS,
19370 + (TSTR("yaffs_get_inode for NULL object!!\n")));
19375 + T(YAFFS_TRACE_OS,
19376 + (TSTR("yaffs_get_inode for object %d\n"), obj->objectId));
19378 + inode = Y_IGET(sb, obj->objectId);
19379 + if (IS_ERR(inode))
19382 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
19383 + /* iget also increments the inode's i_count */
19384 + /* NB You can't be holding grossLock or deadlock will happen! */
19389 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
19392 + yaffs_Object *obj;
19393 + int nWritten, ipos;
19394 + struct inode *inode;
19395 + yaffs_Device *dev;
19397 + obj = yaffs_DentryToObject(f->f_dentry);
19399 + dev = obj->myDev;
19401 + yaffs_GrossLock(dev);
19403 + inode = f->f_dentry->d_inode;
19405 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
19406 + ipos = inode->i_size;
19411 + T(YAFFS_TRACE_OS,
19412 + (TSTR("yaffs_file_write: hey obj is null!\n")));
19414 + T(YAFFS_TRACE_OS,
19415 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
19416 + "to object %d at %d(%x)\n"),
19417 + (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
19419 + nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
19421 + yaffs_MarkSuperBlockDirty(dev);
19423 + T(YAFFS_TRACE_OS,
19424 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
19425 + (unsigned )n,(unsigned)n));
19427 + if (nWritten > 0) {
19428 + ipos += nWritten;
19430 + if (ipos > inode->i_size) {
19431 + inode->i_size = ipos;
19432 + inode->i_blocks = (ipos + 511) >> 9;
19434 + T(YAFFS_TRACE_OS,
19435 + (TSTR("yaffs_file_write size updated to %d bytes, "
19437 + ipos, (int)(inode->i_blocks)));
19441 + yaffs_GrossUnlock(dev);
19442 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
19445 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
19446 +/* For now we just assume few parallel writes and check against a small number. */
19447 +/* Todo: need to do this with a counter to handle parallel reads better */
19449 +static ssize_t yaffs_hold_space(struct file *f)
19451 + yaffs_Object *obj;
19452 + yaffs_Device *dev;
19457 + obj = yaffs_DentryToObject(f->f_dentry);
19459 + dev = obj->myDev;
19461 + yaffs_GrossLock(dev);
19463 + nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
19465 + yaffs_GrossUnlock(dev);
19467 + return (nFreeChunks > 20) ? 1 : 0;
19470 +static void yaffs_release_space(struct file *f)
19472 + yaffs_Object *obj;
19473 + yaffs_Device *dev;
19476 + obj = yaffs_DentryToObject(f->f_dentry);
19478 + dev = obj->myDev;
19480 + yaffs_GrossLock(dev);
19483 + yaffs_GrossUnlock(dev);
19487 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
19489 + long long retval;
19495 + offset += i_size_read(file->f_path.dentry->d_inode);
19498 + offset += file->f_pos;
19500 + retval = -EINVAL;
19502 + if (offset >= 0){
19503 + if (offset != file->f_pos)
19504 + file->f_pos = offset;
19513 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
19515 + yaffs_Object *obj;
19516 + yaffs_Device *dev;
19517 + struct yaffs_SearchContext *sc;
19518 + struct inode *inode = f->f_dentry->d_inode;
19519 + unsigned long offset, curoffs;
19523 + char name[YAFFS_MAX_NAME_LENGTH + 1];
19525 + obj = yaffs_DentryToObject(f->f_dentry);
19526 + dev = obj->myDev;
19528 + yaffs_GrossLock(dev);
19530 + yaffs_DeviceToLC(dev)->readdirProcess = current;
19532 + offset = f->f_pos;
19534 + sc = yaffs_NewSearch(obj);
19536 + retVal = -ENOMEM;
19540 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
19542 + if (offset == 0) {
19543 + T(YAFFS_TRACE_OS,
19544 + (TSTR("yaffs_readdir: entry . ino %d \n"),
19545 + (int)inode->i_ino));
19546 + yaffs_GrossUnlock(dev);
19547 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
19548 + yaffs_GrossLock(dev);
19551 + yaffs_GrossLock(dev);
19555 + if (offset == 1) {
19556 + T(YAFFS_TRACE_OS,
19557 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
19558 + (int)f->f_dentry->d_parent->d_inode->i_ino));
19559 + yaffs_GrossUnlock(dev);
19560 + if (filldir(dirent, "..", 2, offset,
19561 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
19562 + yaffs_GrossLock(dev);
19565 + yaffs_GrossLock(dev);
19572 + /* If the directory has changed since the open or last call to
19573 + readdir, rewind to after the 2 canned entries. */
19574 + if (f->f_version != inode->i_version) {
19576 + f->f_pos = offset;
19577 + f->f_version = inode->i_version;
19580 + while(sc->nextReturn){
19582 + l = sc->nextReturn;
19583 + if (curoffs >= offset) {
19584 + int this_inode = yaffs_GetObjectInode(l);
19585 + int this_type = yaffs_GetObjectType(l);
19587 + yaffs_GetObjectName(l, name,
19588 + YAFFS_MAX_NAME_LENGTH + 1);
19589 + T(YAFFS_TRACE_OS,
19590 + (TSTR("yaffs_readdir: %s inode %d\n"),
19591 + name, yaffs_GetObjectInode(l)));
19593 + yaffs_GrossUnlock(dev);
19595 + if (filldir(dirent,
19601 + yaffs_GrossLock(dev);
19605 + yaffs_GrossLock(dev);
19610 + yaffs_SearchAdvance(sc);
19614 + yaffs_EndSearch(sc);
19615 + yaffs_DeviceToLC(dev)->readdirProcess = NULL;
19616 + yaffs_GrossUnlock(dev);
19624 + * File creation. Allocate an inode, and we're done..
19627 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
19628 +#define YCRED(x) x
19630 +#define YCRED(x) (x->cred)
19633 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19634 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19637 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19641 + struct inode *inode;
19643 + yaffs_Object *obj = NULL;
19644 + yaffs_Device *dev;
19646 + yaffs_Object *parent = yaffs_InodeToObject(dir);
19648 + int error = -ENOSPC;
19649 + uid_t uid = YCRED(current)->fsuid;
19650 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19652 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
19656 + T(YAFFS_TRACE_OS,
19657 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
19658 + parent->objectId, parent->variantType));
19660 + T(YAFFS_TRACE_OS,
19661 + (TSTR("yaffs_mknod: could not get parent object\n")));
19665 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
19666 + "mode %x dev %x\n"),
19667 + dentry->d_name.name, mode, rdev));
19669 + dev = parent->myDev;
19671 + yaffs_GrossLock(dev);
19673 + switch (mode & S_IFMT) {
19675 + /* Special (socket, fifo, device...) */
19676 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
19677 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19678 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19679 + gid, old_encode_dev(rdev));
19681 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19685 + case S_IFREG: /* file */
19686 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
19687 + obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
19690 + case S_IFDIR: /* directory */
19691 + T(YAFFS_TRACE_OS,
19692 + (TSTR("yaffs_mknod: making directory\n")));
19693 + obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
19696 + case S_IFLNK: /* symlink */
19697 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
19698 + obj = NULL; /* Do we ever get here? */
19702 + /* Can not call yaffs_get_inode() with gross lock held */
19703 + yaffs_GrossUnlock(dev);
19706 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
19707 + d_instantiate(dentry, inode);
19708 + update_dir_time(dir);
19709 + T(YAFFS_TRACE_OS,
19710 + (TSTR("yaffs_mknod created object %d count = %d\n"),
19711 + obj->objectId, atomic_read(&inode->i_count)));
19713 + yaffs_FillInodeFromObject(dir,parent);
19715 + T(YAFFS_TRACE_OS,
19716 + (TSTR("yaffs_mknod failed making object\n")));
19723 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
19726 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
19727 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
19731 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19732 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
19733 + struct nameidata *n)
19735 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
19738 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
19739 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
19742 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
19746 + yaffs_Device *dev;
19747 + yaffs_Object *obj;
19749 + T(YAFFS_TRACE_OS,
19750 + (TSTR("yaffs_unlink %d:%s\n"),
19751 + (int)(dir->i_ino),
19752 + dentry->d_name.name));
19753 + obj = yaffs_InodeToObject(dir);
19754 + dev = obj->myDev;
19756 + yaffs_GrossLock(dev);
19758 + retVal = yaffs_Unlink(obj, dentry->d_name.name);
19760 + if (retVal == YAFFS_OK) {
19761 + dentry->d_inode->i_nlink--;
19762 + dir->i_version++;
19763 + yaffs_GrossUnlock(dev);
19764 + mark_inode_dirty(dentry->d_inode);
19765 + update_dir_time(dir);
19768 + yaffs_GrossUnlock(dev);
19769 + return -ENOTEMPTY;
19773 + * Create a link...
19775 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
19776 + struct dentry *dentry)
19778 + struct inode *inode = old_dentry->d_inode;
19779 + yaffs_Object *obj = NULL;
19780 + yaffs_Object *link = NULL;
19781 + yaffs_Device *dev;
19783 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
19785 + obj = yaffs_InodeToObject(inode);
19786 + dev = obj->myDev;
19788 + yaffs_GrossLock(dev);
19790 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
19791 + link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
19795 + old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19796 + d_instantiate(dentry, old_dentry->d_inode);
19797 + atomic_inc(&old_dentry->d_inode->i_count);
19798 + T(YAFFS_TRACE_OS,
19799 + (TSTR("yaffs_link link count %d i_count %d\n"),
19800 + old_dentry->d_inode->i_nlink,
19801 + atomic_read(&old_dentry->d_inode->i_count)));
19804 + yaffs_GrossUnlock(dev);
19807 + update_dir_time(dir);
19814 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
19815 + const char *symname)
19817 + yaffs_Object *obj;
19818 + yaffs_Device *dev;
19819 + uid_t uid = YCRED(current)->fsuid;
19820 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19822 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
19824 + dev = yaffs_InodeToObject(dir)->myDev;
19825 + yaffs_GrossLock(dev);
19826 + obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
19827 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
19828 + yaffs_GrossUnlock(dev);
19831 + struct inode *inode;
19833 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
19834 + d_instantiate(dentry, inode);
19835 + update_dir_time(dir);
19836 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
19839 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
19845 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19846 +static int yaffs_sync_object(struct file *file, int datasync)
19848 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
19853 + yaffs_Object *obj;
19854 + yaffs_Device *dev;
19855 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19856 + struct dentry *dentry = file->f_path.dentry;
19859 + obj = yaffs_DentryToObject(dentry);
19861 + dev = obj->myDev;
19863 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
19864 + (TSTR("yaffs_sync_object\n")));
19865 + yaffs_GrossLock(dev);
19866 + yaffs_FlushFile(obj, 1, datasync);
19867 + yaffs_GrossUnlock(dev);
19872 + * The VFS layer already does all the dentry stuff for rename.
19874 + * NB: POSIX says you can rename an object over an old object of the same name
19876 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
19877 + struct inode *new_dir, struct dentry *new_dentry)
19879 + yaffs_Device *dev;
19880 + int retVal = YAFFS_FAIL;
19881 + yaffs_Object *target;
19883 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
19884 + dev = yaffs_InodeToObject(old_dir)->myDev;
19886 + yaffs_GrossLock(dev);
19888 + /* Check if the target is an existing directory that is not empty. */
19889 + target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
19890 + new_dentry->d_name.name);
19894 + if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
19895 + !ylist_empty(&target->variant.directoryVariant.children)) {
19897 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
19899 + retVal = YAFFS_FAIL;
19901 + /* Now does unlinking internally using shadowing mechanism */
19902 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n")));
19904 + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
19905 + old_dentry->d_name.name,
19906 + yaffs_InodeToObject(new_dir),
19907 + new_dentry->d_name.name);
19909 + yaffs_GrossUnlock(dev);
19911 + if (retVal == YAFFS_OK) {
19913 + new_dentry->d_inode->i_nlink--;
19914 + mark_inode_dirty(new_dentry->d_inode);
19917 + update_dir_time(old_dir);
19918 + if(old_dir != new_dir)
19919 + update_dir_time(new_dir);
19922 + return -ENOTEMPTY;
19926 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
19928 + struct inode *inode = dentry->d_inode;
19930 + yaffs_Device *dev;
19932 + T(YAFFS_TRACE_OS,
19933 + (TSTR("yaffs_setattr of object %d\n"),
19934 + yaffs_InodeToObject(inode)->objectId));
19936 + /* Fail if a requested resize >= 2GB */
19937 + if (attr->ia_valid & ATTR_SIZE &&
19938 + (attr->ia_size >> 31))
19942 + error = inode_change_ok(inode, attr);
19943 + if (error == 0) {
19946 + error = yaffs_vfs_setattr(inode, attr);
19947 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
19948 + if (attr->ia_valid & ATTR_SIZE){
19949 + yaffs_vfs_setsize(inode,attr->ia_size);
19950 + inode->i_blocks = (inode->i_size + 511) >> 9;
19953 + dev = yaffs_InodeToObject(inode)->myDev;
19954 + if (attr->ia_valid & ATTR_SIZE){
19955 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
19956 + (int)(attr->ia_size),(int)(attr->ia_size)));
19958 + yaffs_GrossLock(dev);
19959 + result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
19960 + if(result == YAFFS_OK) {
19965 + yaffs_GrossUnlock(dev);
19969 + T(YAFFS_TRACE_OS,
19970 + (TSTR("yaffs_setattr done returning %d\n"),error));
19975 +#ifdef CONFIG_YAFFS_XATTR
19976 +int yaffs_setxattr(struct dentry *dentry, const char *name,
19977 + const void *value, size_t size, int flags)
19979 + struct inode *inode = dentry->d_inode;
19981 + yaffs_Device *dev;
19982 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19984 + T(YAFFS_TRACE_OS,
19985 + (TSTR("yaffs_setxattr of object %d\n"),
19989 + if (error == 0) {
19991 + dev = obj->myDev;
19992 + yaffs_GrossLock(dev);
19993 + result = yaffs_SetXAttribute(obj, name, value, size, flags);
19994 + if(result == YAFFS_OK)
19996 + else if(result < 0)
19998 + yaffs_GrossUnlock(dev);
20001 + T(YAFFS_TRACE_OS,
20002 + (TSTR("yaffs_setxattr done returning %d\n"),error));
20008 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
20011 + struct inode *inode = dentry->d_inode;
20013 + yaffs_Device *dev;
20014 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20016 + T(YAFFS_TRACE_OS,
20017 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
20018 + name, obj->objectId));
20020 + if (error == 0) {
20021 + dev = obj->myDev;
20022 + yaffs_GrossLock(dev);
20023 + error = yaffs_GetXAttribute(obj, name, buff, size);
20024 + yaffs_GrossUnlock(dev);
20027 + T(YAFFS_TRACE_OS,
20028 + (TSTR("yaffs_getxattr done returning %d\n"),error));
20033 +int yaffs_removexattr(struct dentry *dentry, const char *name)
20035 + struct inode *inode = dentry->d_inode;
20037 + yaffs_Device *dev;
20038 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20040 + T(YAFFS_TRACE_OS,
20041 + (TSTR("yaffs_removexattr of object %d\n"),
20045 + if (error == 0) {
20047 + dev = obj->myDev;
20048 + yaffs_GrossLock(dev);
20049 + result = yaffs_RemoveXAttribute(obj, name);
20050 + if(result == YAFFS_OK)
20052 + else if(result < 0)
20054 + yaffs_GrossUnlock(dev);
20057 + T(YAFFS_TRACE_OS,
20058 + (TSTR("yaffs_removexattr done returning %d\n"),error));
20063 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
20065 + struct inode *inode = dentry->d_inode;
20067 + yaffs_Device *dev;
20068 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20070 + T(YAFFS_TRACE_OS,
20071 + (TSTR("yaffs_listxattr of object %d\n"),
20075 + if (error == 0) {
20076 + dev = obj->myDev;
20077 + yaffs_GrossLock(dev);
20078 + error = yaffs_ListXAttributes(obj, buff, size);
20079 + yaffs_GrossUnlock(dev);
20082 + T(YAFFS_TRACE_OS,
20083 + (TSTR("yaffs_listxattr done returning %d\n"),error));
20091 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20092 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
20094 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
20095 + struct super_block *sb = dentry->d_sb;
20096 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20097 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
20099 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20101 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
20103 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20106 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
20108 + yaffs_GrossLock(dev);
20110 + buf->f_type = YAFFS_MAGIC;
20111 + buf->f_bsize = sb->s_blocksize;
20112 + buf->f_namelen = 255;
20114 + if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
20115 + /* Do this if chunk size is not a power of 2 */
20117 + uint64_t bytesInDev;
20118 + uint64_t bytesFree;
20120 + bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) *
20121 + ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk));
20123 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
20124 + buf->f_blocks = bytesInDev;
20126 + bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
20127 + ((uint64_t)(dev->nDataBytesPerChunk));
20129 + do_div(bytesFree, sb->s_blocksize);
20131 + buf->f_bfree = bytesFree;
20133 + } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
20136 + (dev->param.endBlock - dev->param.startBlock + 1) *
20137 + dev->param.nChunksPerBlock /
20138 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20140 + yaffs_GetNumberOfFreeChunks(dev) /
20141 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20144 + (dev->param.endBlock - dev->param.startBlock + 1) *
20145 + dev->param.nChunksPerBlock *
20146 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20149 + yaffs_GetNumberOfFreeChunks(dev) *
20150 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20153 + buf->f_files = 0;
20154 + buf->f_ffree = 0;
20155 + buf->f_bavail = buf->f_bfree;
20157 + yaffs_GrossUnlock(dev);
20163 +static void yaffs_FlushInodes(struct super_block *sb)
20165 + struct inode *iptr;
20166 + yaffs_Object *obj;
20168 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
20169 + obj = yaffs_InodeToObject(iptr);
20171 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
20173 + yaffs_FlushFile(obj,1,0);
20179 +static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
20181 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20185 + yaffs_FlushInodes(sb);
20186 + yaffs_UpdateDirtyDirectories(dev);
20187 + yaffs_FlushEntireDeviceCache(dev);
20188 + if(do_checkpoint)
20189 + yaffs_CheckpointSave(dev);
20193 +static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
20195 + unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
20196 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20197 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
20199 + if(erasedChunks < dev->nFreeChunks)
20200 + scatteredFree = (dev->nFreeChunks - erasedChunks);
20202 + if(!context->bgRunning)
20204 + else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
20206 + else if(erasedChunks > dev->nFreeChunks/2)
20208 + else if(erasedChunks > dev->nFreeChunks/4)
20214 +static int yaffs_do_sync_fs(struct super_block *sb,
20215 + int request_checkpoint)
20218 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20219 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
20220 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
20221 + int do_checkpoint;
20223 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20224 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
20226 + sb->s_dirt ? "dirty" : "clean",
20227 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
20228 + oneshot_checkpoint ? " one-shot" : "" ));
20230 + yaffs_GrossLock(dev);
20231 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
20232 + oneshot_checkpoint) &&
20233 + !dev->isCheckpointed;
20235 + if (sb->s_dirt || do_checkpoint) {
20236 + yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
20238 + if(oneshot_checkpoint)
20239 + yaffs_auto_checkpoint &= ~4;
20241 + yaffs_GrossUnlock(dev);
20247 + * yaffs background thread functions .
20248 + * yaffs_BackgroundThread() the thread function
20249 + * yaffs_BackgroundStart() launches the background thread.
20250 + * yaffs_BackgroundStop() cleans up the background thread.
20253 + * The thread should only run after the yaffs is initialised
20254 + * The thread should be stopped before yaffs is unmounted.
20255 + * The thread should not do any writing while the fs is in read only.
20258 +#ifdef YAFFS_COMPILE_BACKGROUND
20260 +void yaffs_background_waker(unsigned long data)
20262 + wake_up_process((struct task_struct *)data);
20265 +static int yaffs_BackgroundThread(void *data)
20267 + yaffs_Device *dev = (yaffs_Device *)data;
20268 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20269 + unsigned long now = jiffies;
20270 + unsigned long next_dir_update = now;
20271 + unsigned long next_gc = now;
20272 + unsigned long expires;
20273 + unsigned int urgency;
20276 + struct timer_list timer;
20278 + T(YAFFS_TRACE_BACKGROUND,
20279 + (TSTR("yaffs_background starting for dev %p\n"),
20282 +#ifdef YAFFS_COMPILE_FREEZER
20285 + while(context->bgRunning){
20286 + T(YAFFS_TRACE_BACKGROUND,
20287 + (TSTR("yaffs_background\n")));
20289 + if(kthread_should_stop())
20292 +#ifdef YAFFS_COMPILE_FREEZER
20293 + if(try_to_freeze())
20296 + yaffs_GrossLock(dev);
20300 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
20301 + yaffs_UpdateDirtyDirectories(dev);
20302 + next_dir_update = now + HZ;
20305 + if(time_after(now,next_gc) && yaffs_bg_enable){
20306 + if(!dev->isCheckpointed){
20307 + urgency = yaffs_bg_gc_urgency(dev);
20308 + gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
20310 + next_gc = now + HZ/20+1;
20311 + else if(urgency > 0)
20312 + next_gc = now + HZ/10+1;
20314 + next_gc = now + HZ * 2;
20316 + * gc not running so set to next_dir_update
20317 + * to cut down on wake ups
20319 + next_gc = next_dir_update;
20321 + yaffs_GrossUnlock(dev);
20323 + expires = next_dir_update;
20324 + if (time_before(next_gc,expires))
20325 + expires = next_gc;
20326 + if(time_before(expires,now))
20327 + expires = now + HZ;
20329 + Y_INIT_TIMER(&timer);
20330 + timer.expires = expires+1;
20331 + timer.data = (unsigned long) current;
20332 + timer.function = yaffs_background_waker;
20334 + set_current_state(TASK_INTERRUPTIBLE);
20335 + add_timer(&timer);
20337 + del_timer_sync(&timer);
20346 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20349 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20351 + if(dev->readOnly)
20354 + context->bgRunning = 1;
20356 + context->bgThread = kthread_run(yaffs_BackgroundThread,
20357 + (void *)dev,"yaffs-bg-%d",context->mount_id);
20359 + if(IS_ERR(context->bgThread)){
20360 + retval = PTR_ERR(context->bgThread);
20361 + context->bgThread = NULL;
20362 + context->bgRunning = 0;
20367 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20369 + struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
20371 + ctxt->bgRunning = 0;
20373 + if( ctxt->bgThread){
20374 + kthread_stop(ctxt->bgThread);
20375 + ctxt->bgThread = NULL;
20379 +static int yaffs_BackgroundThread(void *data)
20384 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20389 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20395 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20396 +static void yaffs_write_super(struct super_block *sb)
20398 +static int yaffs_write_super(struct super_block *sb)
20401 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
20403 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20404 + (TSTR("yaffs_write_super%s\n"),
20405 + request_checkpoint ? " checkpt" : ""));
20407 + yaffs_do_sync_fs(sb, request_checkpoint);
20409 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
20415 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20416 +static int yaffs_sync_fs(struct super_block *sb, int wait)
20418 +static int yaffs_sync_fs(struct super_block *sb)
20421 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
20423 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
20424 + (TSTR("yaffs_sync_fs%s\n"),
20425 + request_checkpoint ? " checkpt" : ""));
20427 + yaffs_do_sync_fs(sb, request_checkpoint);
20432 +#ifdef YAFFS_USE_OWN_IGET
20434 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
20436 + struct inode *inode;
20437 + yaffs_Object *obj;
20438 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20440 + T(YAFFS_TRACE_OS,
20441 + (TSTR("yaffs_iget for %lu\n"), ino));
20443 + inode = iget_locked(sb, ino);
20445 + return ERR_PTR(-ENOMEM);
20446 + if (!(inode->i_state & I_NEW))
20449 + /* NB This is called as a side effect of other functions, but
20450 + * we had to release the lock to prevent deadlocks, so
20451 + * need to lock again.
20454 + yaffs_GrossLock(dev);
20456 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20458 + yaffs_FillInodeFromObject(inode, obj);
20460 + yaffs_GrossUnlock(dev);
20462 + unlock_new_inode(inode);
20468 +static void yaffs_read_inode(struct inode *inode)
20470 + /* NB This is called as a side effect of other functions, but
20471 + * we had to release the lock to prevent deadlocks, so
20472 + * need to lock again.
20475 + yaffs_Object *obj;
20476 + yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
20478 + T(YAFFS_TRACE_OS,
20479 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
20481 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20482 + yaffs_GrossLock(dev);
20484 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20486 + yaffs_FillInodeFromObject(inode, obj);
20488 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20489 + yaffs_GrossUnlock(dev);
20494 +static YLIST_HEAD(yaffs_context_list);
20495 +struct semaphore yaffs_context_lock;
20497 +static void yaffs_put_super(struct super_block *sb)
20499 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20501 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
20503 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20504 + (TSTR("Shutting down yaffs background thread\n")));
20505 + yaffs_BackgroundStop(dev);
20506 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20507 + (TSTR("yaffs background thread shut down\n")));
20509 + yaffs_GrossLock(dev);
20511 + yaffs_FlushSuperBlock(sb,1);
20513 + if (yaffs_DeviceToLC(dev)->putSuperFunc)
20514 + yaffs_DeviceToLC(dev)->putSuperFunc(sb);
20517 + yaffs_Deinitialise(dev);
20519 + yaffs_GrossUnlock(dev);
20521 + down(&yaffs_context_lock);
20522 + ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
20523 + up(&yaffs_context_lock);
20525 + if (yaffs_DeviceToLC(dev)->spareBuffer) {
20526 + YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
20527 + yaffs_DeviceToLC(dev)->spareBuffer = NULL;
20534 +static void yaffs_MTDPutSuper(struct super_block *sb)
20536 + struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
20541 + put_mtd_device(mtd);
20545 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
20547 + struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
20549 + T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
20556 + int skip_checkpoint_read;
20557 + int skip_checkpoint_write;
20560 + int tags_ecc_overridden;
20561 + int lazy_loading_enabled;
20562 + int lazy_loading_overridden;
20563 + int empty_lost_and_found;
20564 + int empty_lost_and_found_overridden;
20567 +#define MAX_OPT_LEN 30
20568 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
20570 + char cur_opt[MAX_OPT_LEN + 1];
20574 + /* Parse through the options which is a comma seperated list */
20576 + while (options_str && *options_str && !error) {
20577 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
20580 + while(*options_str == ',')
20583 + while (*options_str && *options_str != ',') {
20584 + if (p < MAX_OPT_LEN) {
20585 + cur_opt[p] = *options_str;
20591 + if (!strcmp(cur_opt, "inband-tags"))
20592 + options->inband_tags = 1;
20593 + else if (!strcmp(cur_opt, "tags-ecc-off")){
20594 + options->tags_ecc_on = 0;
20595 + options->tags_ecc_overridden=1;
20596 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
20597 + options->tags_ecc_on = 1;
20598 + options->tags_ecc_overridden = 1;
20599 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
20600 + options->lazy_loading_enabled = 0;
20601 + options->lazy_loading_overridden=1;
20602 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
20603 + options->lazy_loading_enabled = 1;
20604 + options->lazy_loading_overridden = 1;
20605 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
20606 + options->empty_lost_and_found = 0;
20607 + options->empty_lost_and_found_overridden=1;
20608 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
20609 + options->empty_lost_and_found = 1;
20610 + options->empty_lost_and_found_overridden=1;
20611 + } else if (!strcmp(cur_opt, "no-cache"))
20612 + options->no_cache = 1;
20613 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
20614 + options->skip_checkpoint_read = 1;
20615 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
20616 + options->skip_checkpoint_write = 1;
20617 + else if (!strcmp(cur_opt, "no-checkpoint")) {
20618 + options->skip_checkpoint_read = 1;
20619 + options->skip_checkpoint_write = 1;
20621 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
20630 +static struct super_block *yaffs_internal_read_super(int yaffsVersion,
20631 + struct super_block *sb,
20632 + void *data, int silent)
20635 + struct inode *inode = NULL;
20636 + struct dentry *root;
20637 + yaffs_Device *dev = 0;
20638 + char devname_buf[BDEVNAME_SIZE + 1];
20639 + struct mtd_info *mtd;
20641 + char *data_str = (char *)data;
20642 + struct yaffs_LinuxContext *context = NULL;
20643 + yaffs_DeviceParam *param;
20645 + int readOnly = 0;
20647 + yaffs_options options;
20649 + unsigned mount_id;
20651 + struct yaffs_LinuxContext *context_iterator;
20652 + struct ylist_head *l;
20654 + sb->s_magic = YAFFS_MAGIC;
20655 + sb->s_op = &yaffs_super_ops;
20656 + sb->s_flags |= MS_NOATIME;
20658 + readOnly =((sb->s_flags & MS_RDONLY) != 0);
20661 +#ifdef YAFFS_COMPILE_EXPORTFS
20662 + sb->s_export_op = &yaffs_export_ops;
20666 + printk(KERN_INFO "yaffs: sb is NULL\n");
20667 + else if (!sb->s_dev)
20668 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
20669 + else if (!yaffs_devname(sb, devname_buf))
20670 + printk(KERN_INFO "yaffs: devname is NULL\n");
20672 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
20674 + yaffs_devname(sb, devname_buf),
20675 + readOnly ? "ro" : "rw");
20680 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
20682 + memset(&options, 0, sizeof(options));
20684 + if (yaffs_parse_options(&options, data_str)) {
20685 + /* Option parsing failed */
20690 + sb->s_blocksize = PAGE_CACHE_SIZE;
20691 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
20693 + T(YAFFS_TRACE_OS,
20694 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
20695 + T(YAFFS_TRACE_OS,
20696 + (TSTR("yaffs_read_super: block size %d\n"),
20697 + (int)(sb->s_blocksize)));
20699 + T(YAFFS_TRACE_ALWAYS,
20700 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
20701 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
20702 + yaffs_devname(sb, devname_buf)));
20704 + /* Check it's an mtd device..... */
20705 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
20706 + return NULL; /* This isn't an mtd device */
20708 + /* Get the device */
20709 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
20711 + T(YAFFS_TRACE_ALWAYS,
20712 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
20713 + MINOR(sb->s_dev)));
20716 + /* Check it's NAND */
20717 + if (mtd->type != MTD_NANDFLASH) {
20718 + T(YAFFS_TRACE_ALWAYS,
20719 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
20724 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
20725 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
20726 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
20727 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
20728 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
20729 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
20730 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
20731 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
20732 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
20733 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
20734 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
20735 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
20737 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
20740 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
20742 + if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
20743 + T(YAFFS_TRACE_ALWAYS,
20744 + (TSTR("yaffs: auto selecting yaffs2\n")));
20745 + yaffsVersion = 2;
20748 + /* Added NCB 26/5/2006 for completeness */
20749 + if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
20750 + T(YAFFS_TRACE_ALWAYS,
20751 + (TSTR("yaffs: auto selecting yaffs1\n")));
20752 + yaffsVersion = 1;
20757 + if (yaffsVersion == 2) {
20758 + /* Check for version 2 style functions */
20759 + if (!mtd->erase ||
20760 + !mtd->block_isbad ||
20761 + !mtd->block_markbad ||
20764 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20765 + !mtd->read_oob || !mtd->write_oob) {
20767 + !mtd->write_ecc ||
20768 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20770 + T(YAFFS_TRACE_ALWAYS,
20771 + (TSTR("yaffs: MTD device does not support required "
20772 + "functions\n")));
20776 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
20777 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
20778 + !options.inband_tags) {
20779 + T(YAFFS_TRACE_ALWAYS,
20780 + (TSTR("yaffs: MTD device does not have the "
20781 + "right page sizes\n")));
20785 + /* Check for V1 style functions */
20786 + if (!mtd->erase ||
20789 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20790 + !mtd->read_oob || !mtd->write_oob) {
20792 + !mtd->write_ecc ||
20793 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20795 + T(YAFFS_TRACE_ALWAYS,
20796 + (TSTR("yaffs: MTD device does not support required "
20797 + "functions\n")));
20801 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
20802 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
20803 + T(YAFFS_TRACE_ALWAYS,
20804 + (TSTR("yaffs: MTD device does not support have the "
20805 + "right page sizes\n")));
20810 + /* OK, so if we got here, we have an MTD that's NAND and looks
20811 + * like it has the right capabilities
20812 + * Set the yaffs_Device up for mtd
20815 + if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
20817 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
20818 + sb->s_flags |= MS_RDONLY;
20821 + dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
20822 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
20824 + if(!dev || !context ){
20834 + /* Deep shit could not allocate device structure */
20835 + T(YAFFS_TRACE_ALWAYS,
20836 + (TSTR("yaffs_read_super: Failed trying to allocate "
20837 + "yaffs_Device. \n")));
20840 + memset(dev, 0, sizeof(yaffs_Device));
20841 + param = &(dev->param);
20843 + memset(context,0,sizeof(struct yaffs_LinuxContext));
20844 + dev->osContext = context;
20845 + YINIT_LIST_HEAD(&(context->contextList));
20846 + context->dev = dev;
20847 + context->superBlock = sb;
20849 + dev->readOnly = readOnly;
20851 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20852 + sb->s_fs_info = dev;
20854 + sb->u.generic_sbp = dev;
20857 + dev->driverContext = mtd;
20858 + param->name = mtd->name;
20860 + /* Set up the memory size parameters.... */
20862 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
20864 + param->startBlock = 0;
20865 + param->endBlock = nBlocks - 1;
20866 + param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
20867 + param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
20868 + param->nReservedBlocks = 5;
20869 + param->nShortOpCaches = (options.no_cache) ? 0 : 10;
20870 + param->inbandTags = options.inband_tags;
20872 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
20873 + param->disableLazyLoad = 1;
20875 +#ifdef CONFIG_YAFFS_XATTR
20876 + param->enableXattr = 1;
20878 + if(options.lazy_loading_overridden)
20879 + param->disableLazyLoad = !options.lazy_loading_enabled;
20881 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
20882 + param->noTagsECC = 1;
20885 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
20887 + param->deferDirectoryUpdate = 1;
20890 + if(options.tags_ecc_overridden)
20891 + param->noTagsECC = !options.tags_ecc_on;
20893 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
20894 + param->emptyLostAndFound = 1;
20897 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
20898 + param->refreshPeriod = 0;
20900 + param->refreshPeriod = 500;
20903 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
20904 + param->alwaysCheckErased = 1;
20907 + if(options.empty_lost_and_found_overridden)
20908 + param->emptyLostAndFound = options.empty_lost_and_found;
20910 + /* ... and the functions. */
20911 + if (yaffsVersion == 2) {
20912 + param->writeChunkWithTagsToNAND =
20913 + nandmtd2_WriteChunkWithTagsToNAND;
20914 + param->readChunkWithTagsFromNAND =
20915 + nandmtd2_ReadChunkWithTagsFromNAND;
20916 + param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
20917 + param->queryNANDBlock = nandmtd2_QueryNANDBlock;
20918 + yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
20919 + param->isYaffs2 = 1;
20920 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20921 + param->totalBytesPerChunk = mtd->writesize;
20922 + param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
20924 + param->totalBytesPerChunk = mtd->oobblock;
20925 + param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
20927 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
20929 + param->startBlock = 0;
20930 + param->endBlock = nBlocks - 1;
20932 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20933 + /* use the MTD interface in yaffs_mtdif1.c */
20934 + param->writeChunkWithTagsToNAND =
20935 + nandmtd1_WriteChunkWithTagsToNAND;
20936 + param->readChunkWithTagsFromNAND =
20937 + nandmtd1_ReadChunkWithTagsFromNAND;
20938 + param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
20939 + param->queryNANDBlock = nandmtd1_QueryNANDBlock;
20941 + param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
20942 + param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
20944 + param->isYaffs2 = 0;
20946 + /* ... and common functions */
20947 + param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
20948 + param->initialiseNAND = nandmtd_InitialiseNAND;
20950 + yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
20952 + param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
20953 + param->gcControl = yaffs_gc_control_callback;
20955 + yaffs_DeviceToLC(dev)->superBlock= sb;
20958 +#ifndef CONFIG_YAFFS_DOES_ECC
20959 + param->useNANDECC = 1;
20962 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
20963 + param->wideTnodesDisabled = 1;
20966 + param->skipCheckpointRead = options.skip_checkpoint_read;
20967 + param->skipCheckpointWrite = options.skip_checkpoint_write;
20969 + down(&yaffs_context_lock);
20970 + /* Get a mount id */
20972 + for(mount_id=0; ! found; mount_id++){
20974 + ylist_for_each(l,&yaffs_context_list){
20975 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
20976 + if(context_iterator->mount_id == mount_id)
20980 + context->mount_id = mount_id;
20982 + ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
20983 + up(&yaffs_context_lock);
20985 + /* Directory search handling...*/
20986 + YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
20987 + param->removeObjectCallback = yaffs_RemoveObjectCallback;
20989 + init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
20991 + yaffs_GrossLock(dev);
20993 + err = yaffs_GutsInitialise(dev);
20995 + T(YAFFS_TRACE_OS,
20996 + (TSTR("yaffs_read_super: guts initialised %s\n"),
20997 + (err == YAFFS_OK) ? "OK" : "FAILED"));
20999 + if(err == YAFFS_OK)
21000 + yaffs_BackgroundStart(dev);
21002 + if(!context->bgThread)
21003 + param->deferDirectoryUpdate = 0;
21006 + /* Release lock before yaffs_get_inode() */
21007 + yaffs_GrossUnlock(dev);
21009 + /* Create root inode */
21010 + if (err == YAFFS_OK)
21011 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
21012 + yaffs_Root(dev));
21017 + inode->i_op = &yaffs_dir_inode_operations;
21018 + inode->i_fop = &yaffs_dir_operations;
21020 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
21022 + root = d_alloc_root(inode);
21024 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
21030 + sb->s_root = root;
21031 + sb->s_dirt = !dev->isCheckpointed;
21032 + T(YAFFS_TRACE_ALWAYS,
21033 + (TSTR("yaffs_read_super: isCheckpointed %d\n"),
21034 + dev->isCheckpointed));
21036 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
21041 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21042 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
21045 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
21048 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21049 +static int yaffs_read_super(struct file_system_type *fs,
21050 + int flags, const char *dev_name,
21051 + void *data, struct vfsmount *mnt)
21054 + return get_sb_bdev(fs, flags, dev_name, data,
21055 + yaffs_internal_read_super_mtd, mnt);
21058 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
21059 + int flags, const char *dev_name,
21063 + return get_sb_bdev(fs, flags, dev_name, data,
21064 + yaffs_internal_read_super_mtd);
21068 +static struct file_system_type yaffs_fs_type = {
21069 + .owner = THIS_MODULE,
21071 + .get_sb = yaffs_read_super,
21072 + .kill_sb = kill_block_super,
21073 + .fs_flags = FS_REQUIRES_DEV,
21076 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
21079 + return yaffs_internal_read_super(1, sb, data, silent);
21082 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
21083 + FS_REQUIRES_DEV);
21087 +#ifdef CONFIG_YAFFS_YAFFS2
21089 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21090 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
21093 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
21096 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21097 +static int yaffs2_read_super(struct file_system_type *fs,
21098 + int flags, const char *dev_name, void *data,
21099 + struct vfsmount *mnt)
21101 + return get_sb_bdev(fs, flags, dev_name, data,
21102 + yaffs2_internal_read_super_mtd, mnt);
21105 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
21106 + int flags, const char *dev_name,
21110 + return get_sb_bdev(fs, flags, dev_name, data,
21111 + yaffs2_internal_read_super_mtd);
21115 +static struct file_system_type yaffs2_fs_type = {
21116 + .owner = THIS_MODULE,
21117 + .name = "yaffs2",
21118 + .get_sb = yaffs2_read_super,
21119 + .kill_sb = kill_block_super,
21120 + .fs_flags = FS_REQUIRES_DEV,
21123 +static struct super_block *yaffs2_read_super(struct super_block *sb,
21124 + void *data, int silent)
21126 + return yaffs_internal_read_super(2, sb, data, silent);
21129 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
21130 + FS_REQUIRES_DEV);
21133 +#endif /* CONFIG_YAFFS_YAFFS2 */
21135 +static struct proc_dir_entry *my_proc_entry;
21136 +static struct proc_dir_entry *debug_proc_entry;
21138 +static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
21140 + buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
21141 + buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
21142 + buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
21143 + buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
21144 + buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
21145 + buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
21146 + buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
21147 + buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
21148 + buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
21149 + buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
21150 + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
21151 + buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks);
21152 + buf += sprintf(buf, "alwaysCheckErased.. %d\n", dev->param.alwaysCheckErased);
21154 + buf += sprintf(buf, "\n");
21160 +static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
21162 + buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
21163 + buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
21164 + buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
21165 + buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
21166 + buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
21167 + buf += sprintf(buf, "\n");
21168 + buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
21169 + buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
21170 + buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
21171 + buf += sprintf(buf, "\n");
21172 + buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
21173 + buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
21174 + buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
21175 + buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
21176 + buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
21177 + buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
21178 + buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
21179 + buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks);
21180 + buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
21181 + buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
21182 + buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
21183 + buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
21184 + buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed);
21185 + buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed);
21186 + buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed);
21187 + buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits);
21188 + buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles);
21189 + buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles);
21190 + buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount);
21192 + sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions);
21197 +static int yaffs_proc_read(char *page,
21199 + off_t offset, int count, int *eof, void *data)
21201 + struct ylist_head *item;
21202 + char *buf = page;
21203 + int step = offset;
21206 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
21207 + * We use 'offset' (*ppos) to indicate where we are in devList.
21208 + * This also assumes the user has posted a read buffer large
21209 + * enough to hold the complete output; but that's life in /proc.
21212 + *(int *)start = 1;
21214 + /* Print header first */
21216 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
21217 + else if (step == 1)
21218 + buf += sprintf(buf,"\n");
21222 + down(&yaffs_context_lock);
21224 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21225 + ylist_for_each(item, &yaffs_context_list) {
21226 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21227 + yaffs_Device *dev = dc->dev;
21229 + if (n < (step & ~1)) {
21233 + if((step & 1)==0){
21234 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
21235 + buf = yaffs_dump_dev_part0(buf, dev);
21237 + buf = yaffs_dump_dev_part1(buf, dev);
21241 + up(&yaffs_context_lock);
21244 + return buf - page < count ? buf - page : count;
21247 +static int yaffs_stats_proc_read(char *page,
21249 + off_t offset, int count, int *eof, void *data)
21251 + struct ylist_head *item;
21252 + char *buf = page;
21255 + down(&yaffs_context_lock);
21257 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21258 + ylist_for_each(item, &yaffs_context_list) {
21259 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21260 + yaffs_Device *dev = dc->dev;
21262 + int erasedChunks;
21264 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
21266 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
21267 + n, dev->nFreeChunks, erasedChunks,
21268 + dev->backgroundGCs, dev->oldestDirtyGCs,
21269 + dev->nObjects, dev->nTnodes);
21271 + up(&yaffs_context_lock);
21274 + return buf - page < count ? buf - page : count;
21278 + * Set the verbosity of the warnings and error messages.
21280 + * Note that the names can only be a..z or _ with the current code.
21285 + unsigned mask_bitfield;
21286 +} mask_flags[] = {
21287 + {"allocate", YAFFS_TRACE_ALLOCATE},
21288 + {"always", YAFFS_TRACE_ALWAYS},
21289 + {"background", YAFFS_TRACE_BACKGROUND},
21290 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
21291 + {"buffers", YAFFS_TRACE_BUFFERS},
21292 + {"bug", YAFFS_TRACE_BUG},
21293 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
21294 + {"deletion", YAFFS_TRACE_DELETION},
21295 + {"erase", YAFFS_TRACE_ERASE},
21296 + {"error", YAFFS_TRACE_ERROR},
21297 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
21298 + {"gc", YAFFS_TRACE_GC},
21299 + {"lock", YAFFS_TRACE_LOCK},
21300 + {"mtd", YAFFS_TRACE_MTD},
21301 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
21302 + {"os", YAFFS_TRACE_OS},
21303 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
21304 + {"scan", YAFFS_TRACE_SCAN},
21305 + {"tracing", YAFFS_TRACE_TRACING},
21306 + {"sync", YAFFS_TRACE_SYNC},
21307 + {"write", YAFFS_TRACE_WRITE},
21309 + {"verify", YAFFS_TRACE_VERIFY},
21310 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
21311 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
21312 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
21314 + {"all", 0xffffffff},
21319 +#define MAX_MASK_NAME_LENGTH 40
21320 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
21321 + unsigned long count, void *data)
21323 + unsigned rg = 0, mask_bitfield;
21327 + char substring[MAX_MASK_NAME_LENGTH + 1];
21330 + int add, len = 0;
21333 + rg = yaffs_traceMask;
21335 + while (!done && (pos < count)) {
21337 + while ((pos < count) && isspace(buf[pos]))
21340 + switch (buf[pos]) {
21352 + mask_name = NULL;
21354 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
21356 + if (end > buf + pos) {
21357 + mask_name = "numeral";
21358 + len = end - (buf + pos);
21362 + for (x = buf + pos, i = 0;
21363 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
21364 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
21365 + substring[i] = *x;
21366 + substring[i] = '\0';
21368 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21369 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
21370 + mask_name = mask_flags[i].mask_name;
21371 + mask_bitfield = mask_flags[i].mask_bitfield;
21378 + if (mask_name != NULL) {
21382 + rg &= ~mask_bitfield;
21385 + rg |= mask_bitfield;
21388 + rg = mask_bitfield;
21391 + rg |= mask_bitfield;
21397 + yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
21399 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
21401 + if (rg & YAFFS_TRACE_ALWAYS) {
21402 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21404 + flag = ((rg & mask_flags[i].mask_bitfield) ==
21405 + mask_flags[i].mask_bitfield) ? '+' : '-';
21406 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
21414 +static int yaffs_proc_write(struct file *file, const char *buf,
21415 + unsigned long count, void *data)
21417 + return yaffs_proc_write_trace_options(file, buf, count, data);
21420 +/* Stuff to handle installation of file systems */
21421 +struct file_system_to_install {
21422 + struct file_system_type *fst;
21426 +static struct file_system_to_install fs_to_install[] = {
21427 + {&yaffs_fs_type, 0},
21428 + {&yaffs2_fs_type, 0},
21432 +static int __init init_yaffs_fs(void)
21435 + struct file_system_to_install *fsinst;
21437 + T(YAFFS_TRACE_ALWAYS,
21438 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
21440 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
21441 + T(YAFFS_TRACE_ALWAYS,
21442 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
21448 + init_MUTEX(&yaffs_context_lock);
21450 + /* Install the proc_fs entries */
21451 + my_proc_entry = create_proc_entry("yaffs",
21452 + S_IRUGO | S_IFREG,
21455 + if (my_proc_entry) {
21456 + my_proc_entry->write_proc = yaffs_proc_write;
21457 + my_proc_entry->read_proc = yaffs_proc_read;
21458 + my_proc_entry->data = NULL;
21462 + debug_proc_entry = create_proc_entry("yaffs_stats",
21463 + S_IRUGO | S_IFREG,
21466 + if (debug_proc_entry) {
21467 + debug_proc_entry->write_proc = NULL;
21468 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
21469 + debug_proc_entry->data = NULL;
21473 + /* Now add the file system entries */
21475 + fsinst = fs_to_install;
21477 + while (fsinst->fst && !error) {
21478 + error = register_filesystem(fsinst->fst);
21480 + fsinst->installed = 1;
21484 + /* Any errors? uninstall */
21486 + fsinst = fs_to_install;
21488 + while (fsinst->fst) {
21489 + if (fsinst->installed) {
21490 + unregister_filesystem(fsinst->fst);
21491 + fsinst->installed = 0;
21500 +static void __exit exit_yaffs_fs(void)
21503 + struct file_system_to_install *fsinst;
21505 + T(YAFFS_TRACE_ALWAYS,
21506 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
21508 + remove_proc_entry("yaffs", YPROC_ROOT);
21509 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
21511 + fsinst = fs_to_install;
21513 + while (fsinst->fst) {
21514 + if (fsinst->installed) {
21515 + unregister_filesystem(fsinst->fst);
21516 + fsinst->installed = 0;
21522 +module_init(init_yaffs_fs)
21523 +module_exit(exit_yaffs_fs)
21525 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
21526 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
21527 +MODULE_LICENSE("GPL");
21528 diff -Nrup a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c
21529 --- a/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 02:00:00.000000000 +0200
21530 +++ b/fs/yaffs2/yaffs_yaffs1.c 2010-10-03 18:03:47.535000365 +0300
21533 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21535 + * Copyright (C) 2002-2010 Aleph One Ltd.
21536 + * for Toby Churchill Ltd and Brightstar Engineering
21538 + * Created by Charles Manning <charles@aleph1.co.uk>
21540 + * This program is free software; you can redistribute it and/or modify
21541 + * it under the terms of the GNU General Public License version 2 as
21542 + * published by the Free Software Foundation.
21544 +#include "yaffs_yaffs1.h"
21545 +#include "yportenv.h"
21546 +#include "yaffs_trace.h"
21547 +#include "yaffs_bitmap.h"
21548 +#include "yaffs_getblockinfo.h"
21549 +#include "yaffs_nand.h"
21552 +int yaffs1_Scan(yaffs_Device *dev)
21554 + yaffs_ExtendedTags tags;
21556 + int blockIterator;
21557 + int startIterator;
21564 + yaffs_BlockState state;
21565 + yaffs_Object *hardList = NULL;
21566 + yaffs_BlockInfo *bi;
21567 + __u32 sequenceNumber;
21568 + yaffs_ObjectHeader *oh;
21569 + yaffs_Object *in;
21570 + yaffs_Object *parent;
21572 + int alloc_failed = 0;
21574 + struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
21581 + T(YAFFS_TRACE_SCAN,
21582 + (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
21583 + dev->internalStartBlock, dev->internalEndBlock));
21585 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
21587 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
21589 + /* Scan all the blocks to determine their state */
21590 + bi = dev->blockInfo;
21591 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
21592 + yaffs_ClearChunkBits(dev, blk);
21593 + bi->pagesInUse = 0;
21594 + bi->softDeletions = 0;
21596 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
21598 + bi->blockState = state;
21599 + bi->sequenceNumber = sequenceNumber;
21601 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
21602 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
21604 + T(YAFFS_TRACE_SCAN_DEBUG,
21605 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
21606 + state, sequenceNumber));
21608 + if (state == YAFFS_BLOCK_STATE_DEAD) {
21609 + T(YAFFS_TRACE_BAD_BLOCKS,
21610 + (TSTR("block %d is bad" TENDSTR), blk));
21611 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
21612 + T(YAFFS_TRACE_SCAN_DEBUG,
21613 + (TSTR("Block empty " TENDSTR)));
21614 + dev->nErasedBlocks++;
21615 + dev->nFreeChunks += dev->param.nChunksPerBlock;
21620 + startIterator = dev->internalStartBlock;
21621 + endIterator = dev->internalEndBlock;
21623 + /* For each block.... */
21624 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
21625 + blockIterator++) {
21631 + blk = blockIterator;
21633 + bi = yaffs_GetBlockInfo(dev, blk);
21634 + state = bi->blockState;
21638 + /* For each chunk in each block that needs scanning....*/
21639 + for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&
21640 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
21641 + /* Read the tags and decide what to do */
21642 + chunk = blk * dev->param.nChunksPerBlock + c;
21644 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
21647 + /* Let's have a good look at this chunk... */
21649 + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
21650 + /* YAFFS1 only...
21651 + * A deleted chunk
21654 + dev->nFreeChunks++;
21655 + /*T((" %d %d deleted\n",blk,c)); */
21656 + } else if (!tags.chunkUsed) {
21657 + /* An unassigned chunk in the block
21658 + * This means that either the block is empty or
21659 + * this is the one being allocated from
21663 + /* We're looking at the first chunk in the block so the block is unused */
21664 + state = YAFFS_BLOCK_STATE_EMPTY;
21665 + dev->nErasedBlocks++;
21667 + /* this is the block being allocated from */
21668 + T(YAFFS_TRACE_SCAN,
21670 + (" Allocating from %d %d" TENDSTR),
21672 + state = YAFFS_BLOCK_STATE_ALLOCATING;
21673 + dev->allocationBlock = blk;
21674 + dev->allocationPage = c;
21675 + dev->allocationBlockFinder = blk;
21676 + /* Set block finder here to encourage the allocator to go forth from here. */
21680 + dev->nFreeChunks += (dev->param.nChunksPerBlock - c);
21681 + } else if (tags.chunkId > 0) {
21682 + /* chunkId > 0 so it is a data chunk... */
21683 + unsigned int endpos;
21685 + yaffs_SetChunkBit(dev, blk, c);
21686 + bi->pagesInUse++;
21688 + in = yaffs_FindOrCreateObjectByNumber(dev,
21691 + YAFFS_OBJECT_TYPE_FILE);
21692 + /* PutChunkIntoFile checks for a clash (two data chunks with
21693 + * the same chunkId).
21697 + alloc_failed = 1;
21700 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
21701 + alloc_failed = 1;
21705 + (tags.chunkId - 1) * dev->nDataBytesPerChunk +
21708 + in->variantType == YAFFS_OBJECT_TYPE_FILE
21709 + && in->variant.fileVariant.scannedFileSize <
21711 + in->variant.fileVariant.
21712 + scannedFileSize = endpos;
21713 + if (!dev->param.useHeaderFileSize) {
21714 + in->variant.fileVariant.
21716 + in->variant.fileVariant.
21721 + /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
21723 + /* chunkId == 0, so it is an ObjectHeader.
21724 + * Thus, we read in the object header and make the object
21726 + yaffs_SetChunkBit(dev, blk, c);
21727 + bi->pagesInUse++;
21729 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
21733 + oh = (yaffs_ObjectHeader *) chunkData;
21735 + in = yaffs_FindObjectByNumber(dev,
21737 + if (in && in->variantType != oh->type) {
21738 + /* This should not happen, but somehow
21739 + * Wev'e ended up with an objectId that has been reused but not yet
21740 + * deleted, and worse still it has changed type. Delete the old object.
21743 + yaffs_DeleteObject(in);
21748 + in = yaffs_FindOrCreateObjectByNumber(dev,
21754 + alloc_failed = 1;
21756 + if (in && oh->shadowsObject > 0) {
21758 + struct yaffs_ShadowFixerStruct *fixer;
21759 + fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
21761 + fixer->next = shadowFixerList;
21762 + shadowFixerList = fixer;
21763 + fixer->objectId = tags.objectId;
21764 + fixer->shadowedId = oh->shadowsObject;
21765 + T(YAFFS_TRACE_SCAN,
21767 + (" Shadow fixer: %d shadows %d" TENDSTR),
21768 + fixer->objectId, fixer->shadowedId));
21774 + if (in && in->valid) {
21775 + /* We have already filled this one. We have a duplicate and need to resolve it. */
21777 + unsigned existingSerial = in->serial;
21778 + unsigned newSerial = tags.serialNumber;
21780 + if (((existingSerial + 1) & 3) == newSerial) {
21781 + /* Use new one - destroy the exisiting one */
21782 + yaffs_DeleteChunk(dev,
21787 + /* Use existing - destroy this one. */
21788 + yaffs_DeleteChunk(dev, chunk, 1,
21793 + if (in && !in->valid &&
21794 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
21795 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
21796 + /* We only load some info, don't fiddle with directory structure */
21798 + in->variantType = oh->type;
21800 + in->yst_mode = oh->yst_mode;
21801 +#ifdef CONFIG_YAFFS_WINCE
21802 + in->win_atime[0] = oh->win_atime[0];
21803 + in->win_ctime[0] = oh->win_ctime[0];
21804 + in->win_mtime[0] = oh->win_mtime[0];
21805 + in->win_atime[1] = oh->win_atime[1];
21806 + in->win_ctime[1] = oh->win_ctime[1];
21807 + in->win_mtime[1] = oh->win_mtime[1];
21809 + in->yst_uid = oh->yst_uid;
21810 + in->yst_gid = oh->yst_gid;
21811 + in->yst_atime = oh->yst_atime;
21812 + in->yst_mtime = oh->yst_mtime;
21813 + in->yst_ctime = oh->yst_ctime;
21814 + in->yst_rdev = oh->yst_rdev;
21816 + in->hdrChunk = chunk;
21817 + in->serial = tags.serialNumber;
21819 + } else if (in && !in->valid) {
21820 + /* we need to load this info */
21823 + in->variantType = oh->type;
21825 + in->yst_mode = oh->yst_mode;
21826 +#ifdef CONFIG_YAFFS_WINCE
21827 + in->win_atime[0] = oh->win_atime[0];
21828 + in->win_ctime[0] = oh->win_ctime[0];
21829 + in->win_mtime[0] = oh->win_mtime[0];
21830 + in->win_atime[1] = oh->win_atime[1];
21831 + in->win_ctime[1] = oh->win_ctime[1];
21832 + in->win_mtime[1] = oh->win_mtime[1];
21834 + in->yst_uid = oh->yst_uid;
21835 + in->yst_gid = oh->yst_gid;
21836 + in->yst_atime = oh->yst_atime;
21837 + in->yst_mtime = oh->yst_mtime;
21838 + in->yst_ctime = oh->yst_ctime;
21839 + in->yst_rdev = oh->yst_rdev;
21841 + in->hdrChunk = chunk;
21842 + in->serial = tags.serialNumber;
21844 + yaffs_SetObjectNameFromOH(in, oh);
21847 + /* directory stuff...
21848 + * hook up to parent
21852 + yaffs_FindOrCreateObjectByNumber
21853 + (dev, oh->parentObjectId,
21854 + YAFFS_OBJECT_TYPE_DIRECTORY);
21856 + alloc_failed = 1;
21857 + if (parent && parent->variantType ==
21858 + YAFFS_OBJECT_TYPE_UNKNOWN) {
21859 + /* Set up as a directory */
21860 + parent->variantType =
21861 + YAFFS_OBJECT_TYPE_DIRECTORY;
21862 + YINIT_LIST_HEAD(&parent->variant.
21863 + directoryVariant.
21865 + } else if (!parent || parent->variantType !=
21866 + YAFFS_OBJECT_TYPE_DIRECTORY) {
21867 + /* Hoosterman, another problem....
21868 + * We're trying to use a non-directory as a directory
21871 + T(YAFFS_TRACE_ERROR,
21873 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
21875 + parent = dev->lostNFoundDir;
21878 + yaffs_AddObjectToDirectory(parent, in);
21880 + if (0 && (parent == dev->deletedDir ||
21881 + parent == dev->unlinkedDir)) {
21882 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
21883 + dev->nDeletedFiles++;
21885 + /* Note re hardlinks.
21886 + * Since we might scan a hardlink before its equivalent object is scanned
21887 + * we put them all in a list.
21888 + * After scanning is complete, we should have all the objects, so we run through this
21889 + * list and fix up all the chains.
21892 + switch (in->variantType) {
21893 + case YAFFS_OBJECT_TYPE_UNKNOWN:
21894 + /* Todo got a problem */
21896 + case YAFFS_OBJECT_TYPE_FILE:
21897 + if (dev->param.useHeaderFileSize)
21899 + in->variant.fileVariant.
21904 + case YAFFS_OBJECT_TYPE_HARDLINK:
21905 + in->variant.hardLinkVariant.
21906 + equivalentObjectId =
21907 + oh->equivalentObjectId;
21908 + in->hardLinks.next =
21909 + (struct ylist_head *)
21913 + case YAFFS_OBJECT_TYPE_DIRECTORY:
21916 + case YAFFS_OBJECT_TYPE_SPECIAL:
21919 + case YAFFS_OBJECT_TYPE_SYMLINK:
21920 + in->variant.symLinkVariant.alias =
21921 + yaffs_CloneString(oh->alias);
21922 + if (!in->variant.symLinkVariant.alias)
21923 + alloc_failed = 1;
21931 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
21932 + /* If we got this far while scanning, then the block is fully allocated.*/
21933 + state = YAFFS_BLOCK_STATE_FULL;
21936 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
21937 + /* If the block was partially allocated then treat it as fully allocated.*/
21938 + state = YAFFS_BLOCK_STATE_FULL;
21939 + dev->allocationBlock = -1;
21942 + bi->blockState = state;
21944 + /* Now let's see if it was dirty */
21945 + if (bi->pagesInUse == 0 &&
21946 + !bi->hasShrinkHeader &&
21947 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
21948 + yaffs_BlockBecameDirty(dev, blk);
21954 + /* Ok, we've done all the scanning.
21955 + * Fix up the hard link chains.
21956 + * We should now have scanned all the objects, now it's time to add these
21960 + yaffs_HardlinkFixup(dev, hardList);
21962 + /* Fix up any shadowed objects */
21964 + struct yaffs_ShadowFixerStruct *fixer;
21965 + yaffs_Object *obj;
21967 + while (shadowFixerList) {
21968 + fixer = shadowFixerList;
21969 + shadowFixerList = fixer->next;
21970 + /* Complete the rename transaction by deleting the shadowed object
21971 + * then setting the object header to unshadowed.
21973 + obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
21975 + yaffs_DeleteObject(obj);
21977 + obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
21980 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
21986 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
21988 + if (alloc_failed)
21989 + return YAFFS_FAIL;
21991 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
21997 diff -Nrup a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h
21998 --- a/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 02:00:00.000000000 +0200
21999 +++ b/fs/yaffs2/yaffs_yaffs1.h 2010-10-03 18:03:47.551000365 +0300
22002 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
22004 + * Copyright (C) 2002-2010 Aleph One Ltd.
22005 + * for Toby Churchill Ltd and Brightstar Engineering
22007 + * Created by Charles Manning <charles@aleph1.co.uk>
22009 + * This program is free software; you can redistribute it and/or modify
22010 + * it under the terms of the GNU Lesser General Public License version 2.1 as
22011 + * published by the Free Software Foundation.
22013 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
22016 +#ifndef __YAFFS_YAFFS1_H__
22017 +#define __YAFFS_YAFFS1_H__
22019 +#include "yaffs_guts.h"
22020 +int yaffs1_Scan(yaffs_Device *dev);
22023 diff -Nrup a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c
22024 --- a/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 02:00:00.000000000 +0200
22025 +++ b/fs/yaffs2/yaffs_yaffs2.c 2010-10-03 18:03:47.536000367 +0300
22028 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
22030 + * Copyright (C) 2002-2010 Aleph One Ltd.
22031 + * for Toby Churchill Ltd and Brightstar Engineering
22033 + * Created by Charles Manning <charles@aleph1.co.uk>
22035 + * This program is free software; you can redistribute it and/or modify
22036 + * it under the terms of the GNU General Public License version 2 as
22037 + * published by the Free Software Foundation.
22041 +#include "yaffs_guts.h"
22042 +#include "yaffs_trace.h"
22043 +#include "yaffs_yaffs2.h"
22044 +#include "yaffs_checkptrw.h"
22045 +#include "yaffs_bitmap.h"
22046 +#include "yaffs_qsort.h"
22047 +#include "yaffs_nand.h"
22048 +#include "yaffs_getblockinfo.h"
22049 +#include "yaffs_verify.h"
22052 + * Checkpoints are really no benefit on very small partitions.
22054 + * To save space on small partitions don't bother with checkpoints unless
22055 + * the partition is at least this big.
22057 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
22059 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
22063 + * Oldest Dirty Sequence Number handling.
22066 +/* yaffs2_CalcOldestDirtySequence()
22067 + * yaffs2_FindOldestDirtySequence()
22068 + * Calculate the oldest dirty sequence number if we don't know it.
22070 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
22074 + unsigned blockNo = 0;
22075 + yaffs_BlockInfo *b;
22077 + if(!dev->param.isYaffs2)
22080 + /* Find the oldest dirty sequence number. */
22081 + seq = dev->sequenceNumber + 1;
22082 + b = dev->blockInfo;
22083 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
22084 + if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
22085 + (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock &&
22086 + b->sequenceNumber < seq) {
22087 + seq = b->sequenceNumber;
22094 + dev->oldestDirtySequence = seq;
22095 + dev->oldestDirtyBlock = blockNo;
22101 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
22103 + if(!dev->param.isYaffs2)
22106 + if(!dev->oldestDirtySequence)
22107 + yaffs2_CalcOldestDirtySequence(dev);
22111 + * yaffs_ClearOldestDirtySequence()
22112 + * Called when a block is erased or marked bad. (ie. when its sequenceNumber
22113 + * becomes invalid). If the value matches the oldest then we clear
22114 + * dev->oldestDirtySequence to force its recomputation.
22116 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
22119 + if(!dev->param.isYaffs2)
22122 + if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
22123 + dev->oldestDirtySequence = 0;
22124 + dev->oldestDirtyBlock = 0;
22129 + * yaffs2_UpdateOldestDirtySequence()
22130 + * Update the oldest dirty sequence number whenever we dirty a block.
22131 + * Only do this if the oldestDirtySequence is actually being tracked.
22133 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
22135 + if(!dev->param.isYaffs2)
22138 + if(dev->oldestDirtySequence){
22139 + if(dev->oldestDirtySequence > bi->sequenceNumber){
22140 + dev->oldestDirtySequence = bi->sequenceNumber;
22141 + dev->oldestDirtyBlock = blockNo;
22146 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
22147 + yaffs_BlockInfo *bi)
22150 + if (!dev->param.isYaffs2)
22151 + return 1; /* disqualification only applies to yaffs2. */
22153 + if (!bi->hasShrinkHeader)
22154 + return 1; /* can gc */
22156 + yaffs2_FindOldestDirtySequence(dev);
22158 + /* Can't do gc of this block if there are any blocks older than this one that have
22159 + * discarded pages.
22161 + return (bi->sequenceNumber <= dev->oldestDirtySequence);
22165 + * yaffs2_FindRefreshBlock()
22166 + * periodically finds the oldest full block by sequence number for refreshing.
22167 + * Only for yaffs2.
22169 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
22173 + __u32 oldest = 0;
22174 + __u32 oldestSequence = 0;
22176 + yaffs_BlockInfo *bi;
22178 + if(!dev->param.isYaffs2)
22182 + * If refresh period < 10 then refreshing is disabled.
22184 + if(dev->param.refreshPeriod < 10)
22188 + * Fix broken values.
22190 + if(dev->refreshSkip > dev->param.refreshPeriod)
22191 + dev->refreshSkip = dev->param.refreshPeriod;
22193 + if(dev->refreshSkip > 0)
22197 + * Refresh skip is now zero.
22198 + * We'll do a refresh this time around....
22199 + * Update the refresh skip and find the oldest block.
22201 + dev->refreshSkip = dev->param.refreshPeriod;
22202 + dev->refreshCount++;
22203 + bi = dev->blockInfo;
22204 + for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
22206 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
22209 + bi->sequenceNumber < oldestSequence){
22211 + oldestSequence = bi->sequenceNumber;
22217 + if (oldest > 0) {
22218 + T(YAFFS_TRACE_GC,
22219 + (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
22220 + dev->refreshCount, oldest, oldestSequence));
22226 +int yaffs2_CheckpointRequired(yaffs_Device *dev)
22230 + if(!dev->param.isYaffs2)
22233 + nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
22235 + return !dev->param.skipCheckpointWrite &&
22236 + !dev->readOnly &&
22237 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
22240 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
22244 + if(!dev->param.isYaffs2)
22247 + if (!dev->nCheckpointBlocksRequired &&
22248 + yaffs2_CheckpointRequired(dev)){
22249 + /* Not a valid value so recalculate */
22252 + int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
22254 + nBytes += sizeof(yaffs_CheckpointValidity);
22255 + nBytes += sizeof(yaffs_CheckpointDevice);
22256 + nBytes += devBlocks * sizeof(yaffs_BlockInfo);
22257 + nBytes += devBlocks * dev->chunkBitmapStride;
22258 + nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
22259 + nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
22260 + nBytes += sizeof(yaffs_CheckpointValidity);
22261 + nBytes += sizeof(__u32); /* checksum*/
22263 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
22265 + nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
22267 + dev->nCheckpointBlocksRequired = nBlocks;
22270 + retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
22276 +/*--------------------- Checkpointing --------------------*/
22279 +static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
22281 + yaffs_CheckpointValidity cp;
22283 + memset(&cp, 0, sizeof(cp));
22285 + cp.structType = sizeof(cp);
22286 + cp.magic = YAFFS_MAGIC;
22287 + cp.version = YAFFS_CHECKPOINT_VERSION;
22288 + cp.head = (head) ? 1 : 0;
22290 + return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
22294 +static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
22296 + yaffs_CheckpointValidity cp;
22299 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22302 + ok = (cp.structType == sizeof(cp)) &&
22303 + (cp.magic == YAFFS_MAGIC) &&
22304 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
22305 + (cp.head == ((head) ? 1 : 0));
22306 + return ok ? 1 : 0;
22309 +static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
22310 + yaffs_Device *dev)
22312 + cp->nErasedBlocks = dev->nErasedBlocks;
22313 + cp->allocationBlock = dev->allocationBlock;
22314 + cp->allocationPage = dev->allocationPage;
22315 + cp->nFreeChunks = dev->nFreeChunks;
22317 + cp->nDeletedFiles = dev->nDeletedFiles;
22318 + cp->nUnlinkedFiles = dev->nUnlinkedFiles;
22319 + cp->nBackgroundDeletions = dev->nBackgroundDeletions;
22320 + cp->sequenceNumber = dev->sequenceNumber;
22324 +static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
22325 + yaffs_CheckpointDevice *cp)
22327 + dev->nErasedBlocks = cp->nErasedBlocks;
22328 + dev->allocationBlock = cp->allocationBlock;
22329 + dev->allocationPage = cp->allocationPage;
22330 + dev->nFreeChunks = cp->nFreeChunks;
22332 + dev->nDeletedFiles = cp->nDeletedFiles;
22333 + dev->nUnlinkedFiles = cp->nUnlinkedFiles;
22334 + dev->nBackgroundDeletions = cp->nBackgroundDeletions;
22335 + dev->sequenceNumber = cp->sequenceNumber;
22339 +static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
22341 + yaffs_CheckpointDevice cp;
22343 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22347 + /* Write device runtime values*/
22348 + yaffs2_DeviceToCheckpointDevice(&cp, dev);
22349 + cp.structType = sizeof(cp);
22351 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22353 + /* Write block info */
22355 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22356 + ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
22359 + /* Write chunk bits */
22361 + nBytes = nBlocks * dev->chunkBitmapStride;
22362 + ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
22364 + return ok ? 1 : 0;
22368 +static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
22370 + yaffs_CheckpointDevice cp;
22372 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22376 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22380 + if (cp.structType != sizeof(cp))
22384 + yaffs2_CheckpointDeviceToDevice(dev, &cp);
22386 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22388 + ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
22392 + nBytes = nBlocks * dev->chunkBitmapStride;
22394 + ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
22396 + return ok ? 1 : 0;
22399 +static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
22400 + yaffs_Object *obj)
22403 + cp->objectId = obj->objectId;
22404 + cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
22405 + cp->hdrChunk = obj->hdrChunk;
22406 + cp->variantType = obj->variantType;
22407 + cp->deleted = obj->deleted;
22408 + cp->softDeleted = obj->softDeleted;
22409 + cp->unlinked = obj->unlinked;
22410 + cp->fake = obj->fake;
22411 + cp->renameAllowed = obj->renameAllowed;
22412 + cp->unlinkAllowed = obj->unlinkAllowed;
22413 + cp->serial = obj->serial;
22414 + cp->nDataChunks = obj->nDataChunks;
22416 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22417 + cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
22418 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22419 + cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
22422 +static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
22425 + yaffs_Object *parent;
22427 + if (obj->variantType != cp->variantType) {
22428 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
22429 + TCONT("chunk %d does not match existing object type %d")
22430 + TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
22431 + obj->variantType));
22435 + obj->objectId = cp->objectId;
22437 + if (cp->parentId)
22438 + parent = yaffs_FindOrCreateObjectByNumber(
22441 + YAFFS_OBJECT_TYPE_DIRECTORY);
22446 + if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
22447 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
22448 + TCONT(" chunk %d Parent type, %d, not directory")
22450 + cp->objectId, cp->parentId, cp->variantType,
22451 + cp->hdrChunk, parent->variantType));
22454 + yaffs_AddObjectToDirectory(parent, obj);
22457 + obj->hdrChunk = cp->hdrChunk;
22458 + obj->variantType = cp->variantType;
22459 + obj->deleted = cp->deleted;
22460 + obj->softDeleted = cp->softDeleted;
22461 + obj->unlinked = cp->unlinked;
22462 + obj->fake = cp->fake;
22463 + obj->renameAllowed = cp->renameAllowed;
22464 + obj->unlinkAllowed = cp->unlinkAllowed;
22465 + obj->serial = cp->serial;
22466 + obj->nDataChunks = cp->nDataChunks;
22468 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22469 + obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
22470 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22471 + obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
22473 + if (obj->hdrChunk > 0)
22474 + obj->lazyLoaded = 1;
22480 +static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
22481 + __u32 level, int chunkOffset)
22484 + yaffs_Device *dev = in->myDev;
22490 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
22491 + if (tn->internal[i]) {
22492 + ok = yaffs2_CheckpointTnodeWorker(in,
22495 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
22498 + } else if (level == 0) {
22499 + __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
22500 + ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
22502 + ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22510 +static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
22512 + __u32 endMarker = ~0;
22515 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22516 + ok = yaffs2_CheckpointTnodeWorker(obj,
22517 + obj->variant.fileVariant.top,
22518 + obj->variant.fileVariant.topLevel,
22521 + ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
22522 + sizeof(endMarker));
22525 + return ok ? 1 : 0;
22528 +static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
22532 + yaffs_Device *dev = obj->myDev;
22533 + yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
22537 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22539 + while (ok && (~baseChunk)) {
22541 + /* Read level 0 tnode */
22544 + tn = yaffs_GetTnode(dev);
22546 + ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22551 + ok = yaffs_AddOrFindLevel0Tnode(dev,
22557 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22561 + T(YAFFS_TRACE_CHECKPOINT, (
22562 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
22563 + nread, baseChunk, ok));
22565 + return ok ? 1 : 0;
22569 +static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
22571 + yaffs_Object *obj;
22572 + yaffs_CheckpointObject cp;
22575 + struct ylist_head *lh;
22578 + /* Iterate through the objects in each hash entry,
22579 + * dumping them to the checkpointing stream.
22582 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
22583 + ylist_for_each(lh, &dev->objectBucket[i].list) {
22585 + obj = ylist_entry(lh, yaffs_Object, hashLink);
22586 + if (!obj->deferedFree) {
22587 + yaffs2_ObjectToCheckpointObject(&cp, obj);
22588 + cp.structType = sizeof(cp);
22590 + T(YAFFS_TRACE_CHECKPOINT, (
22591 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
22592 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
22594 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22596 + if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22597 + ok = yaffs2_WriteCheckpointTnodes(obj);
22603 + /* Dump end of list */
22604 + memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
22605 + cp.structType = sizeof(cp);
22608 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22610 + return ok ? 1 : 0;
22613 +static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
22615 + yaffs_Object *obj;
22616 + yaffs_CheckpointObject cp;
22619 + yaffs_Object *hardList = NULL;
22621 + while (ok && !done) {
22622 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22623 + if (cp.structType != sizeof(cp)) {
22624 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
22625 + cp.structType, (int)sizeof(cp), ok));
22629 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
22630 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
22632 + if (ok && cp.objectId == ~0)
22635 + obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
22637 + ok = yaffs2_CheckpointObjectToObject(obj, &cp);
22640 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22641 + ok = yaffs2_ReadCheckpointTnodes(obj);
22642 + } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
22643 + obj->hardLinks.next =
22644 + (struct ylist_head *) hardList;
22653 + yaffs_HardlinkFixup(dev, hardList);
22655 + return ok ? 1 : 0;
22658 +static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
22660 + __u32 checkpointSum;
22663 + yaffs2_GetCheckpointSum(dev, &checkpointSum);
22665 + ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
22673 +static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
22675 + __u32 checkpointSum0;
22676 + __u32 checkpointSum1;
22679 + yaffs2_GetCheckpointSum(dev, &checkpointSum0);
22681 + ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
22686 + if (checkpointSum0 != checkpointSum1)
22693 +static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
22697 + if (!yaffs2_CheckpointRequired(dev)) {
22698 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
22703 + ok = yaffs2_CheckpointOpen(dev, 1);
22706 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22707 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
22710 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
22711 + ok = yaffs2_WriteCheckpointDevice(dev);
22714 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
22715 + ok = yaffs2_WriteCheckpointObjects(dev);
22718 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22719 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
22723 + ok = yaffs2_WriteCheckpointSum(dev);
22725 + if (!yaffs2_CheckpointClose(dev))
22729 + dev->isCheckpointed = 1;
22731 + dev->isCheckpointed = 0;
22733 + return dev->isCheckpointed;
22736 +static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
22740 + if(!dev->param.isYaffs2)
22743 + if (ok && dev->param.skipCheckpointRead) {
22744 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
22749 + ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
22752 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22753 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
22756 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
22757 + ok = yaffs2_ReadCheckpointDevice(dev);
22760 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
22761 + ok = yaffs2_ReadCheckpointObjects(dev);
22764 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22765 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
22769 + ok = yaffs2_ReadCheckpointSum(dev);
22770 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
22773 + if (!yaffs2_CheckpointClose(dev))
22777 + dev->isCheckpointed = 1;
22779 + dev->isCheckpointed = 0;
22781 + return ok ? 1 : 0;
22785 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
22787 + if (dev->isCheckpointed ||
22788 + dev->blocksInCheckpoint > 0) {
22789 + dev->isCheckpointed = 0;
22790 + yaffs2_CheckpointInvalidateStream(dev);
22792 + if (dev->param.markSuperBlockDirty)
22793 + dev->param.markSuperBlockDirty(dev);
22797 +int yaffs_CheckpointSave(yaffs_Device *dev)
22800 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22802 + yaffs_VerifyObjects(dev);
22803 + yaffs_VerifyBlocks(dev);
22804 + yaffs_VerifyFreeChunks(dev);
22806 + if (!dev->isCheckpointed) {
22807 + yaffs2_InvalidateCheckpoint(dev);
22808 + yaffs2_WriteCheckpointData(dev);
22811 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22813 + return dev->isCheckpointed;
22816 +int yaffs2_CheckpointRestore(yaffs_Device *dev)
22819 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22821 + retval = yaffs2_ReadCheckpointData(dev);
22823 + if (dev->isCheckpointed) {
22824 + yaffs_VerifyObjects(dev);
22825 + yaffs_VerifyBlocks(dev);
22826 + yaffs_VerifyFreeChunks(dev);
22829 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22834 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
22836 + /* if newsSize > oldFileSize.
22837 + * We're going to be writing a hole.
22838 + * If the hole is small then write zeros otherwise write a start of hole marker.
22842 + loff_t oldFileSize;
22845 + int result = YAFFS_OK;
22846 + yaffs_Device *dev = NULL;
22848 + __u8 *localBuffer = NULL;
22850 + int smallIncreaseOk = 0;
22853 + return YAFFS_FAIL;
22855 + if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
22856 + return YAFFS_FAIL;
22858 + dev = obj->myDev;
22860 + /* Bail out if not yaffs2 mode */
22861 + if(!dev->param.isYaffs2)
22864 + oldFileSize = obj->variant.fileVariant.fileSize;
22866 + if (newSize <= oldFileSize)
22869 + increase = newSize - oldFileSize;
22871 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
22872 + yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
22878 + localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
22881 + /* fill hole with zero bytes */
22882 + int pos = oldFileSize;
22885 + memset(localBuffer,0,dev->nDataBytesPerChunk);
22886 + smallIncreaseOk = 1;
22888 + while(increase > 0 && smallIncreaseOk){
22889 + thisWrite = increase;
22890 + if(thisWrite > dev->nDataBytesPerChunk)
22891 + thisWrite = dev->nDataBytesPerChunk;
22892 + written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
22893 + if(written == thisWrite){
22894 + pos += thisWrite;
22895 + increase -= thisWrite;
22897 + smallIncreaseOk = 0;
22900 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
22902 + /* If we were out of space then reverse any chunks we've added */
22903 + if(!smallIncreaseOk)
22904 + yaffs_ResizeDown(obj, oldFileSize);
22907 + if (!smallIncreaseOk &&
22909 + obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
22910 + obj->parent->objectId != YAFFS_OBJECTID_DELETED){
22911 + /* Write a hole start header with the old file size */
22912 + yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
22923 +} yaffs_BlockIndex;
22926 +static int yaffs2_ybicmp(const void *a, const void *b)
22928 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
22929 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
22930 + register int ablock = ((yaffs_BlockIndex *)a)->block;
22931 + register int bblock = ((yaffs_BlockIndex *)b)->block;
22932 + if (aseq == bseq)
22933 + return ablock - bblock;
22935 + return aseq - bseq;
22938 +int yaffs2_ScanBackwards(yaffs_Device *dev)
22940 + yaffs_ExtendedTags tags;
22942 + int blockIterator;
22943 + int startIterator;
22945 + int nBlocksToScan = 0;
22951 + yaffs_BlockState state;
22952 + yaffs_Object *hardList = NULL;
22953 + yaffs_BlockInfo *bi;
22954 + __u32 sequenceNumber;
22955 + yaffs_ObjectHeader *oh;
22956 + yaffs_Object *in;
22957 + yaffs_Object *parent;
22958 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
22964 + int foundChunksInBlock;
22965 + int equivalentObjectId;
22966 + int alloc_failed = 0;
22969 + yaffs_BlockIndex *blockIndex = NULL;
22970 + int altBlockIndex = 0;
22972 + T(YAFFS_TRACE_SCAN,
22974 + ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
22975 + TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
22978 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
22980 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
22982 + if (!blockIndex) {
22983 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
22984 + altBlockIndex = 1;
22987 + if (!blockIndex) {
22988 + T(YAFFS_TRACE_SCAN,
22989 + (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
22990 + return YAFFS_FAIL;
22993 + dev->blocksInCheckpoint = 0;
22995 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
22997 + /* Scan all the blocks to determine their state */
22998 + bi = dev->blockInfo;
22999 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
23000 + yaffs_ClearChunkBits(dev, blk);
23001 + bi->pagesInUse = 0;
23002 + bi->softDeletions = 0;
23004 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
23006 + bi->blockState = state;
23007 + bi->sequenceNumber = sequenceNumber;
23009 + if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
23010 + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
23011 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
23012 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
23014 + T(YAFFS_TRACE_SCAN_DEBUG,
23015 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
23016 + state, sequenceNumber));
23019 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
23020 + dev->blocksInCheckpoint++;
23022 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
23023 + T(YAFFS_TRACE_BAD_BLOCKS,
23024 + (TSTR("block %d is bad" TENDSTR), blk));
23025 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
23026 + T(YAFFS_TRACE_SCAN_DEBUG,
23027 + (TSTR("Block empty " TENDSTR)));
23028 + dev->nErasedBlocks++;
23029 + dev->nFreeChunks += dev->param.nChunksPerBlock;
23030 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
23032 + /* Determine the highest sequence number */
23033 + if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
23034 + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
23036 + blockIndex[nBlocksToScan].seq = sequenceNumber;
23037 + blockIndex[nBlocksToScan].block = blk;
23041 + if (sequenceNumber >= dev->sequenceNumber)
23042 + dev->sequenceNumber = sequenceNumber;
23044 + /* TODO: Nasty sequence number! */
23045 + T(YAFFS_TRACE_SCAN,
23047 + ("Block scanning block %d has bad sequence number %d"
23048 + TENDSTR), blk, sequenceNumber));
23055 + T(YAFFS_TRACE_SCAN,
23056 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
23062 + /* Sort the blocks by sequence number*/
23063 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
23067 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
23069 + /* Now scan the blocks looking at the data. */
23070 + startIterator = 0;
23071 + endIterator = nBlocksToScan - 1;
23072 + T(YAFFS_TRACE_SCAN_DEBUG,
23073 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
23075 + /* For each block.... backwards */
23076 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
23077 + blockIterator--) {
23078 + /* Cooperative multitasking! This loop can run for so
23079 + long that watchdog timers expire. */
23082 + /* get the block to scan in the correct order */
23083 + blk = blockIndex[blockIterator].block;
23085 + bi = yaffs_GetBlockInfo(dev, blk);
23088 + state = bi->blockState;
23092 + /* For each chunk in each block that needs scanning.... */
23093 + foundChunksInBlock = 0;
23094 + for (c = dev->param.nChunksPerBlock - 1;
23095 + !alloc_failed && c >= 0 &&
23096 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23097 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
23098 + /* Scan backwards...
23099 + * Read the tags and decide what to do
23102 + chunk = blk * dev->param.nChunksPerBlock + c;
23104 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
23107 + /* Let's have a good look at this chunk... */
23109 + if (!tags.chunkUsed) {
23110 + /* An unassigned chunk in the block.
23111 + * If there are used chunks after this one, then
23112 + * it is a chunk that was skipped due to failing the erased
23113 + * check. Just skip it so that it can be deleted.
23114 + * But, more typically, We get here when this is an unallocated
23115 + * chunk and his means that either the block is empty or
23116 + * this is the one being allocated from
23119 + if (foundChunksInBlock) {
23120 + /* This is a chunk that was skipped due to failing the erased check */
23121 + } else if (c == 0) {
23122 + /* We're looking at the first chunk in the block so the block is unused */
23123 + state = YAFFS_BLOCK_STATE_EMPTY;
23124 + dev->nErasedBlocks++;
23126 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23127 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
23128 + if (dev->sequenceNumber == bi->sequenceNumber) {
23129 + /* this is the block being allocated from */
23131 + T(YAFFS_TRACE_SCAN,
23133 + (" Allocating from %d %d"
23134 + TENDSTR), blk, c));
23136 + state = YAFFS_BLOCK_STATE_ALLOCATING;
23137 + dev->allocationBlock = blk;
23138 + dev->allocationPage = c;
23139 + dev->allocationBlockFinder = blk;
23141 + /* This is a partially written block that is not
23142 + * the current allocation block.
23145 + T(YAFFS_TRACE_SCAN,
23146 + (TSTR("Partially written block %d detected" TENDSTR),
23152 + dev->nFreeChunks++;
23154 + } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
23155 + T(YAFFS_TRACE_SCAN,
23156 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
23159 + dev->nFreeChunks++;
23161 + } else if (tags.objectId > YAFFS_MAX_OBJECT_ID ||
23162 + tags.chunkId > YAFFS_MAX_CHUNK_ID ||
23163 + (tags.chunkId > 0 && tags.byteCount > dev->nDataBytesPerChunk) ||
23164 + tags.sequenceNumber != bi->sequenceNumber ) {
23165 + T(YAFFS_TRACE_SCAN,
23166 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunkId = %d, byteCount = %d, ignored"TENDSTR),
23167 + blk, c,tags.objectId, tags.chunkId, tags.byteCount));
23169 + dev->nFreeChunks++;
23171 + } else if (tags.chunkId > 0) {
23172 + /* chunkId > 0 so it is a data chunk... */
23173 + unsigned int endpos;
23174 + __u32 chunkBase =
23175 + (tags.chunkId - 1) * dev->nDataBytesPerChunk;
23177 + foundChunksInBlock = 1;
23180 + yaffs_SetChunkBit(dev, blk, c);
23181 + bi->pagesInUse++;
23183 + in = yaffs_FindOrCreateObjectByNumber(dev,
23186 + YAFFS_OBJECT_TYPE_FILE);
23188 + /* Out of memory */
23189 + alloc_failed = 1;
23193 + in->variantType == YAFFS_OBJECT_TYPE_FILE
23194 + && chunkBase < in->variant.fileVariant.shrinkSize) {
23195 + /* This has not been invalidated by a resize */
23196 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
23197 + alloc_failed = 1;
23200 + /* File size is calculated by looking at the data chunks if we have not
23201 + * seen an object header yet. Stop this practice once we find an object header.
23203 + endpos = chunkBase + tags.byteCount;
23205 + if (!in->valid && /* have not got an object header yet */
23206 + in->variant.fileVariant.scannedFileSize < endpos) {
23207 + in->variant.fileVariant.scannedFileSize = endpos;
23208 + in->variant.fileVariant.fileSize = endpos;
23212 + /* This chunk has been invalidated by a resize, or a past file deletion
23213 + * so delete the chunk*/
23214 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23218 + /* chunkId == 0, so it is an ObjectHeader.
23219 + * Thus, we read in the object header and make the object
23221 + foundChunksInBlock = 1;
23223 + yaffs_SetChunkBit(dev, blk, c);
23224 + bi->pagesInUse++;
23229 + if (tags.extraHeaderInfoAvailable) {
23230 + in = yaffs_FindOrCreateObjectByNumber(dev,
23232 + tags.extraObjectType);
23234 + alloc_failed = 1;
23238 + (!in->valid && dev->param.disableLazyLoad) ||
23239 + tags.extraShadows ||
23241 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23242 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
23244 + /* If we don't have valid info then we need to read the chunk
23245 + * TODO In future we can probably defer reading the chunk and
23246 + * living with invalid data until needed.
23249 + result = yaffs_ReadChunkWithTagsFromNAND(dev,
23254 + oh = (yaffs_ObjectHeader *) chunkData;
23256 + if (dev->param.inbandTags) {
23257 + /* Fix up the header if they got corrupted by inband tags */
23258 + oh->shadowsObject = oh->inbandShadowsObject;
23259 + oh->isShrink = oh->inbandIsShrink;
23263 + in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
23265 + alloc_failed = 1;
23271 + /* TODO Hoosterman we have a problem! */
23272 + T(YAFFS_TRACE_ERROR,
23274 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
23275 + TENDSTR), tags.objectId, chunk));
23280 + /* We have already filled this one.
23281 + * We have a duplicate that will be discarded, but
23282 + * we first have to suck out resize info if it is a file.
23285 + if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
23287 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
23288 + (tags.extraHeaderInfoAvailable &&
23289 + tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
23291 + (oh) ? oh->fileSize : tags.
23293 + __u32 parentObjectId =
23295 + parentObjectId : tags.
23296 + extraParentObjectId;
23300 + (oh) ? oh->isShrink : tags.
23301 + extraIsShrinkHeader;
23303 + /* If it is deleted (unlinked at start also means deleted)
23304 + * we treat the file size as being zeroed at this point.
23306 + if (parentObjectId ==
23307 + YAFFS_OBJECTID_DELETED
23308 + || parentObjectId ==
23309 + YAFFS_OBJECTID_UNLINKED) {
23314 + if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
23315 + in->variant.fileVariant.shrinkSize = thisSize;
23318 + bi->hasShrinkHeader = 1;
23321 + /* Use existing - destroy this one. */
23322 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23326 + if (!in->valid && in->variantType !=
23327 + (oh ? oh->type : tags.extraObjectType))
23328 + T(YAFFS_TRACE_ERROR, (
23329 + TSTR("yaffs tragedy: Bad object type, "
23330 + TCONT("%d != %d, for object %d at chunk ")
23331 + TCONT("%d during scan")
23333 + oh->type : tags.extraObjectType,
23334 + in->variantType, tags.objectId,
23337 + if (!in->valid &&
23338 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23340 + YAFFS_OBJECTID_LOSTNFOUND)) {
23341 + /* We only load some info, don't fiddle with directory structure */
23346 + in->yst_mode = oh->yst_mode;
23347 +#ifdef CONFIG_YAFFS_WINCE
23348 + in->win_atime[0] = oh->win_atime[0];
23349 + in->win_ctime[0] = oh->win_ctime[0];
23350 + in->win_mtime[0] = oh->win_mtime[0];
23351 + in->win_atime[1] = oh->win_atime[1];
23352 + in->win_ctime[1] = oh->win_ctime[1];
23353 + in->win_mtime[1] = oh->win_mtime[1];
23355 + in->yst_uid = oh->yst_uid;
23356 + in->yst_gid = oh->yst_gid;
23357 + in->yst_atime = oh->yst_atime;
23358 + in->yst_mtime = oh->yst_mtime;
23359 + in->yst_ctime = oh->yst_ctime;
23360 + in->yst_rdev = oh->yst_rdev;
23362 + in->lazyLoaded = 0;
23366 + in->lazyLoaded = 1;
23368 + in->hdrChunk = chunk;
23370 + } else if (!in->valid) {
23371 + /* we need to load this info */
23374 + in->hdrChunk = chunk;
23377 + in->variantType = oh->type;
23379 + in->yst_mode = oh->yst_mode;
23380 +#ifdef CONFIG_YAFFS_WINCE
23381 + in->win_atime[0] = oh->win_atime[0];
23382 + in->win_ctime[0] = oh->win_ctime[0];
23383 + in->win_mtime[0] = oh->win_mtime[0];
23384 + in->win_atime[1] = oh->win_atime[1];
23385 + in->win_ctime[1] = oh->win_ctime[1];
23386 + in->win_mtime[1] = oh->win_mtime[1];
23388 + in->yst_uid = oh->yst_uid;
23389 + in->yst_gid = oh->yst_gid;
23390 + in->yst_atime = oh->yst_atime;
23391 + in->yst_mtime = oh->yst_mtime;
23392 + in->yst_ctime = oh->yst_ctime;
23393 + in->yst_rdev = oh->yst_rdev;
23396 + if (oh->shadowsObject > 0)
23397 + yaffs_HandleShadowedObject(dev,
23404 + yaffs_SetObjectNameFromOH(in, oh);
23406 + yaffs_FindOrCreateObjectByNumber
23407 + (dev, oh->parentObjectId,
23408 + YAFFS_OBJECT_TYPE_DIRECTORY);
23410 + fileSize = oh->fileSize;
23411 + isShrink = oh->isShrink;
23412 + equivalentObjectId = oh->equivalentObjectId;
23415 + in->variantType = tags.extraObjectType;
23417 + yaffs_FindOrCreateObjectByNumber
23418 + (dev, tags.extraParentObjectId,
23419 + YAFFS_OBJECT_TYPE_DIRECTORY);
23420 + fileSize = tags.extraFileLength;
23421 + isShrink = tags.extraIsShrinkHeader;
23422 + equivalentObjectId = tags.extraEquivalentObjectId;
23423 + in->lazyLoaded = 1;
23429 + alloc_failed = 1;
23431 + /* directory stuff...
23432 + * hook up to parent
23435 + if (parent && parent->variantType ==
23436 + YAFFS_OBJECT_TYPE_UNKNOWN) {
23437 + /* Set up as a directory */
23438 + parent->variantType =
23439 + YAFFS_OBJECT_TYPE_DIRECTORY;
23440 + YINIT_LIST_HEAD(&parent->variant.
23441 + directoryVariant.
23443 + } else if (!parent || parent->variantType !=
23444 + YAFFS_OBJECT_TYPE_DIRECTORY) {
23445 + /* Hoosterman, another problem....
23446 + * We're trying to use a non-directory as a directory
23449 + T(YAFFS_TRACE_ERROR,
23451 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
23453 + parent = dev->lostNFoundDir;
23456 + yaffs_AddObjectToDirectory(parent, in);
23458 + itsUnlinked = (parent == dev->deletedDir) ||
23459 + (parent == dev->unlinkedDir);
23462 + /* Mark the block as having a shrinkHeader */
23463 + bi->hasShrinkHeader = 1;
23466 + /* Note re hardlinks.
23467 + * Since we might scan a hardlink before its equivalent object is scanned
23468 + * we put them all in a list.
23469 + * After scanning is complete, we should have all the objects, so we run
23470 + * through this list and fix up all the chains.
23473 + switch (in->variantType) {
23474 + case YAFFS_OBJECT_TYPE_UNKNOWN:
23475 + /* Todo got a problem */
23477 + case YAFFS_OBJECT_TYPE_FILE:
23479 + if (in->variant.fileVariant.
23480 + scannedFileSize < fileSize) {
23481 + /* This covers the case where the file size is greater
23482 + * than where the data is
23483 + * This will happen if the file is resized to be larger
23484 + * than its current data extents.
23486 + in->variant.fileVariant.fileSize = fileSize;
23487 + in->variant.fileVariant.scannedFileSize = fileSize;
23490 + if (in->variant.fileVariant.shrinkSize > fileSize)
23491 + in->variant.fileVariant.shrinkSize = fileSize;
23495 + case YAFFS_OBJECT_TYPE_HARDLINK:
23496 + if (!itsUnlinked) {
23497 + in->variant.hardLinkVariant.equivalentObjectId =
23498 + equivalentObjectId;
23499 + in->hardLinks.next =
23500 + (struct ylist_head *) hardList;
23504 + case YAFFS_OBJECT_TYPE_DIRECTORY:
23507 + case YAFFS_OBJECT_TYPE_SPECIAL:
23510 + case YAFFS_OBJECT_TYPE_SYMLINK:
23512 + in->variant.symLinkVariant.alias =
23513 + yaffs_CloneString(oh->alias);
23514 + if (!in->variant.symLinkVariant.alias)
23515 + alloc_failed = 1;
23524 + } /* End of scanning for each chunk */
23526 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
23527 + /* If we got this far while scanning, then the block is fully allocated. */
23528 + state = YAFFS_BLOCK_STATE_FULL;
23532 + bi->blockState = state;
23534 + /* Now let's see if it was dirty */
23535 + if (bi->pagesInUse == 0 &&
23536 + !bi->hasShrinkHeader &&
23537 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
23538 + yaffs_BlockBecameDirty(dev, blk);
23543 + yaffs_SkipRestOfBlock(dev);
23545 + if (altBlockIndex)
23546 + YFREE_ALT(blockIndex);
23548 + YFREE(blockIndex);
23550 + /* Ok, we've done all the scanning.
23551 + * Fix up the hard link chains.
23552 + * We should now have scanned all the objects, now it's time to add these
23555 + yaffs_HardlinkFixup(dev, hardList);
23558 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
23560 + if (alloc_failed)
23561 + return YAFFS_FAIL;
23563 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
23567 diff -Nrup a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h
23568 --- a/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 02:00:00.000000000 +0200
23569 +++ b/fs/yaffs2/yaffs_yaffs2.h 2010-10-03 18:03:47.552000367 +0300
23572 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
23574 + * Copyright (C) 2002-2010 Aleph One Ltd.
23575 + * for Toby Churchill Ltd and Brightstar Engineering
23577 + * Created by Charles Manning <charles@aleph1.co.uk>
23579 + * This program is free software; you can redistribute it and/or modify
23580 + * it under the terms of the GNU General Public License version 2 as
23581 + * published by the Free Software Foundation.
23584 +#ifndef __YAFFS_YAFFS2_H__
23585 +#define __YAFFS_YAFFS2_H__
23587 +#include "yaffs_guts.h"
23589 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev);
23590 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev);
23591 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi);
23592 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi);
23593 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi);
23594 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev);
23595 +int yaffs2_CheckpointRequired(yaffs_Device *dev);
23596 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev);
23599 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
23600 +int yaffs2_CheckpointSave(yaffs_Device *dev);
23601 +int yaffs2_CheckpointRestore(yaffs_Device *dev);
23603 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
23604 +int yaffs2_ScanBackwards(yaffs_Device *dev);
23607 diff -Nrup a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h
23608 --- a/fs/yaffs2/yportenv.h 2010-10-03 17:48:22.725000364 +0300
23609 +++ b/fs/yaffs2/yportenv.h 2010-10-03 18:03:47.555000363 +0300
23612 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
23614 - * Copyright (C) 2002-2007 Aleph One Ltd.
23615 + * Copyright (C) 2002-2010 Aleph One Ltd.
23616 * for Toby Churchill Ltd and Brightstar Engineering
23618 * Created by Charles Manning <charles@aleph1.co.uk>
23619 @@ -41,12 +41,14 @@
23620 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
23621 #include <linux/config.h>
23624 #include <linux/kernel.h>
23625 #include <linux/mm.h>
23626 #include <linux/sched.h>
23627 #include <linux/string.h>
23628 #include <linux/slab.h>
23629 #include <linux/vmalloc.h>
23630 +#include <linux/xattr.h>
23633 #define YUCHAR unsigned char
23634 @@ -55,11 +57,11 @@
23635 #define yaffs_strcpy(a, b) strcpy(a, b)
23636 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23637 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
23638 -#define yaffs_strlen(s) strlen(s)
23639 +#define yaffs_strnlen(s,m) strnlen(s,m)
23640 #define yaffs_sprintf sprintf
23641 #define yaffs_toupper(a) toupper(a)
23643 -#define Y_INLINE inline
23644 +#define Y_INLINE __inline__
23646 #define YAFFS_LOSTNFOUND_NAME "lost+found"
23647 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23648 @@ -71,11 +73,11 @@
23649 #define YFREE_ALT(x) vfree(x)
23650 #define YMALLOC_DMA(x) YMALLOC(x)
23652 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
23653 #define YYIELD() schedule()
23654 +#define Y_DUMP_STACK() dump_stack()
23656 -#define YAFFS_ROOT_MODE 0666
23657 -#define YAFFS_LOSTNFOUND_MODE 0666
23658 +#define YAFFS_ROOT_MODE 0755
23659 +#define YAFFS_LOSTNFOUND_MODE 0700
23661 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23662 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
23663 @@ -89,15 +91,10 @@
23664 #define yaffs_strcmp(a, b) strcmp(a, b)
23666 #define TENDSTR "\n"
23667 -#define TSTR(x) KERN_WARNING x
23668 +#define TSTR(x) KERN_DEBUG x
23670 #define TOUT(p) printk p
23672 -#define yaffs_trace(mask, fmt, args...) \
23673 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
23674 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
23677 #define compile_time_assertion(assertion) \
23678 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
23680 @@ -116,7 +113,6 @@
23682 #include "string.h"
23684 -#include "devextras.h"
23686 #define YMALLOC(x) malloc(x)
23687 #define YFREE(x) free(x)
23688 @@ -129,7 +125,7 @@
23689 #define yaffs_strcat(a, b) strcat(a, b)
23690 #define yaffs_strcpy(a, b) strcpy(a, b)
23691 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23692 -#define yaffs_strlen(s) strlen(s)
23693 +#define yaffs_strnlen(s,m) strnlen(s,m)
23694 #define yaffs_sprintf sprintf
23695 #define yaffs_toupper(a) toupper(a)
23697 @@ -146,8 +142,8 @@
23698 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23699 /* #define YPRINTF(x) printf x */
23701 -#define YAFFS_ROOT_MODE 0666
23702 -#define YAFFS_LOSTNFOUND_MODE 0666
23703 +#define YAFFS_ROOT_MODE 0755
23704 +#define YAFFS_LOSTNFOUND_MODE 0700
23706 #define yaffs_SumCompare(x, y) ((x) == (y))
23707 #define yaffs_strcmp(a, b) strcmp(a, b)
23708 @@ -158,46 +154,180 @@
23712 -/* see yaffs_fs.c */
23713 -extern unsigned int yaffs_traceMask;
23714 -extern unsigned int yaffs_wr_attempts;
23715 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
23719 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
23721 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
23724 +#define O_RDONLY 00
23728 +#define O_WRONLY 01
23736 +#define O_CREAT 0100
23740 +#define O_EXCL 0200
23744 +#define O_TRUNC 01000
23748 +#define O_APPEND 02000
23752 +#define SEEK_SET 0
23756 +#define SEEK_CUR 1
23760 +#define SEEK_END 2
23800 +#define ENODATA 61
23804 +#define ENOTEMPTY 39
23807 +#ifndef ENAMETOOLONG
23808 +#define ENAMETOOLONG 36
23820 +#define ENOTDIR 20
23831 +#define S_IFMT 0170000
23835 +#define S_IFLNK 0120000
23838 -#define YAFFS_TRACE_OS 0x00000002
23839 -#define YAFFS_TRACE_ALLOCATE 0x00000004
23840 -#define YAFFS_TRACE_SCAN 0x00000008
23841 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
23842 -#define YAFFS_TRACE_ERASE 0x00000020
23843 -#define YAFFS_TRACE_GC 0x00000040
23844 -#define YAFFS_TRACE_WRITE 0x00000080
23845 -#define YAFFS_TRACE_TRACING 0x00000100
23846 -#define YAFFS_TRACE_DELETION 0x00000200
23847 -#define YAFFS_TRACE_BUFFERS 0x00000400
23848 -#define YAFFS_TRACE_NANDACCESS 0x00000800
23849 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
23850 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
23851 -#define YAFFS_TRACE_MTD 0x00004000
23852 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
23854 -#define YAFFS_TRACE_VERIFY 0x00010000
23855 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
23856 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
23857 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
23860 -#define YAFFS_TRACE_ERROR 0x40000000
23861 -#define YAFFS_TRACE_BUG 0x80000000
23862 -#define YAFFS_TRACE_ALWAYS 0xF0000000
23864 +#define S_IFDIR 0040000
23868 +#define S_IFREG 0100000
23872 +#define S_IREAD 0000400
23876 +#define S_IWRITE 0000200
23879 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
23881 +#define S_IEXEC 0000100
23884 +#ifndef XATTR_CREATE
23885 +#define XATTR_CREATE 1
23888 +#ifndef XATTR_REPLACE
23889 +#define XATTR_REPLACE 2
23900 +#include <errno.h>
23901 +#include <sys/stat.h>
23902 +#include <fcntl.h>
23907 +#ifndef Y_DUMP_STACK
23908 +#define Y_DUMP_STACK() do { } while (0)
23912 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
23913 +#define YBUG() do {\
23914 + T(YAFFS_TRACE_BUG,\
23915 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\