1 --- a/fs/yaffs2/devextras.h
2 +++ b/fs/yaffs2/devextras.h
5 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
7 - * Copyright (C) 2002-2007 Aleph One Ltd.
8 + * Copyright (C) 2002-2010 Aleph One Ltd.
9 * for Toby Churchill Ltd and Brightstar Engineering
11 * Created by Charles Manning <charles@aleph1.co.uk>
16 +#include "yportenv.h"
18 #if !(defined __KERNEL__)
20 /* Definition of types */
21 @@ -33,103 +35,6 @@ typedef unsigned __u32;
26 - * This is a simple doubly linked list implementation that matches the
27 - * way the Linux kernel doubly linked list implementation works.
31 - struct ylist_head *next; /* next in chain */
32 - struct ylist_head *prev; /* previous in chain */
36 -/* Initialise a static list */
37 -#define YLIST_HEAD(name) \
38 -struct ylist_head name = { &(name), &(name)}
42 -/* Initialise a list head to an empty list */
43 -#define YINIT_LIST_HEAD(p) \
50 -/* Add an element to a list */
51 -static __inline__ void ylist_add(struct ylist_head *newEntry,
52 - struct ylist_head *list)
54 - struct ylist_head *listNext = list->next;
56 - list->next = newEntry;
57 - newEntry->prev = list;
58 - newEntry->next = listNext;
59 - listNext->prev = newEntry;
63 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
64 - struct ylist_head *list)
66 - struct ylist_head *listPrev = list->prev;
68 - list->prev = newEntry;
69 - newEntry->next = list;
70 - newEntry->prev = listPrev;
71 - listPrev->next = newEntry;
76 -/* Take an element out of its current list, with or without
77 - * reinitialising the links.of the entry*/
78 -static __inline__ void ylist_del(struct ylist_head *entry)
80 - struct ylist_head *listNext = entry->next;
81 - struct ylist_head *listPrev = entry->prev;
83 - listNext->prev = listPrev;
84 - listPrev->next = listNext;
88 -static __inline__ void ylist_del_init(struct ylist_head *entry)
91 - entry->next = entry->prev = entry;
95 -/* Test if the list is empty */
96 -static __inline__ int ylist_empty(struct ylist_head *entry)
98 - return (entry->next == entry);
102 -/* ylist_entry takes a pointer to a list entry and offsets it to that
103 - * we can find a pointer to the object it is embedded in.
107 -#define ylist_entry(entry, type, member) \
108 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
111 -/* ylist_for_each and list_for_each_safe iterate over lists.
112 - * ylist_for_each_safe uses temporary storage to make the list delete safe
115 -#define ylist_for_each(itervar, list) \
116 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
118 -#define ylist_for_each_safe(itervar, saveVar, list) \
119 - for (itervar = (list)->next, saveVar = (list)->next->next; \
120 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
123 #if !(defined __KERNEL__)
125 --- a/fs/yaffs2/Kconfig
126 +++ b/fs/yaffs2/Kconfig
127 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
131 -config YAFFS_DISABLE_LAZY_LOAD
132 - bool "Disable lazy loading"
133 - depends on YAFFS_YAFFS2
134 +config YAFFS_DISABLE_TAGS_ECC
135 + bool "Disable YAFFS from doing ECC on tags by default"
136 + depends on YAFFS_FS && YAFFS_YAFFS2
139 - "Lazy loading" defers loading file details until they are
140 - required. This saves mount time, but makes the first look-up
143 - Lazy loading will only happen if enabled by this option being 'n'
144 - and if the appropriate tags are available, else yaffs2 will
145 - automatically fall back to immediate loading and do the right
148 - Lazy laoding will be required by checkpointing.
150 - Setting this to 'y' will disable lazy loading.
151 + This defaults Yaffs to using its own ECC calculations on tags instead of
152 + just relying on the MTD.
153 + This behavior can also be overridden with tags_ecc_on and
154 + tags_ecc_off mount options.
158 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
159 but makes look-ups faster.
163 +config YAFFS_EMPTY_LOST_AND_FOUND
164 + bool "Empty lost and found on boot"
165 + depends on YAFFS_FS
168 + If this is enabled then the contents of lost and found is
169 + automatically dumped at mount.
173 +config YAFFS_DISABLE_BLOCK_REFRESHING
174 + bool "Disable yaffs2 block refreshing"
175 + depends on YAFFS_FS
178 + If this is set, then block refreshing is disabled.
179 + Block refreshing infrequently refreshes the oldest block in
180 + a yaffs2 file system. This mechanism helps to refresh flash to
181 + mitigate against data loss. This is particularly useful for MLC.
185 +config YAFFS_DISABLE_BACKGROUND
186 + bool "Disable yaffs2 background processing"
187 + depends on YAFFS_FS
190 + If this is set, then background processing is disabled.
191 + Background processing makes many foreground activities faster.
196 + bool "Enable yaffs2 xattr support"
197 + depends on YAFFS_FS
200 + If this is set then yaffs2 will provide xattr support.
204 --- a/fs/yaffs2/Makefile
205 +++ b/fs/yaffs2/Makefile
208 obj-$(CONFIG_YAFFS_FS) += yaffs.o
210 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
211 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
212 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
213 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
214 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
215 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
216 +yaffs-y += yaffs_nameval.o
217 +yaffs-y += yaffs_allocator.o
218 +yaffs-y += yaffs_yaffs1.o
219 +yaffs-y += yaffs_yaffs2.o
220 +yaffs-y += yaffs_bitmap.o
221 +yaffs-y += yaffs_verify.o
223 --- a/fs/yaffs2/moduleconfig.h
224 +++ b/fs/yaffs2/moduleconfig.h
227 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
229 - * Copyright (C) 2002-2007 Aleph One Ltd.
230 + * Copyright (C) 2002-2010 Aleph One Ltd.
231 * for Toby Churchill Ltd and Brightstar Engineering
233 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
235 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
236 /* #define CONFIG_YAFFS_DOES_ECC */
238 +/* Default: Selected */
239 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
240 +#define CONFIG_YAFFS_DOES_TAGS_ECC
242 /* Default: Not selected */
243 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
244 /* CONFIG_YAFFS_DOES_ECC is set */
245 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
247 -/* Default: Selected */
248 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
249 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
250 +/* Default: Not selected */
251 +/* Meaning: Always test whether chunks are erased before writing to them.
252 + Use during mtd debugging and init. */
253 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
255 +/* Default: Not Selected */
256 +/* Meaning: At mount automatically empty all files from lost and found. */
257 +/* This is done to fix an old problem where rmdir was not checking for an */
258 +/* empty directory. This can also be achieved with a mount option. */
259 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
261 /* Default: Selected */
262 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
263 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
266 -/* Meaning: set the count of blocks to reserve for checkpointing */
267 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
268 +/* Default: Unselected */
269 +/* Meaning: Select to disable block refreshing. */
270 +/* Block Refreshing periodically rewrites the oldest block. */
271 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
273 +/* Default: Unselected */
274 +/* Meaning: Select to disable background processing */
275 +/* #define CONFIG_DISABLE_BACKGROUND */
278 +/* Default: Selected */
279 +/* Meaning: Enable XATTR support */
280 +#define CONFIG_YAFFS_XATTR
283 Older-style on-NAND data format has a "pageStatus" byte to record
285 +++ b/fs/yaffs2/yaffs_allocator.c
288 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
290 + * Copyright (C) 2002-2010 Aleph One Ltd.
291 + * for Toby Churchill Ltd and Brightstar Engineering
293 + * Created by Charles Manning <charles@aleph1.co.uk>
295 + * This program is free software; you can redistribute it and/or modify
296 + * it under the terms of the GNU Lesser General Public License version 2.1 as
297 + * published by the Free Software Foundation.
299 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
303 +#include "yaffs_allocator.h"
304 +#include "yaffs_guts.h"
305 +#include "yaffs_trace.h"
306 +#include "yportenv.h"
308 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
310 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
315 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
320 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
322 + return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
325 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
331 +void yaffs_InitialiseRawObjects(yaffs_Device *dev)
336 +void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
341 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
344 + return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
348 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
357 +struct yaffs_TnodeList_struct {
358 + struct yaffs_TnodeList_struct *next;
359 + yaffs_Tnode *tnodes;
362 +typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
364 +struct yaffs_ObjectList_struct {
365 + yaffs_Object *objects;
366 + struct yaffs_ObjectList_struct *next;
369 +typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
372 +struct yaffs_AllocatorStruct {
373 + int nTnodesCreated;
374 + yaffs_Tnode *freeTnodes;
376 + yaffs_TnodeList *allocatedTnodeList;
378 + int nObjectsCreated;
379 + yaffs_Object *freeObjects;
382 + yaffs_ObjectList *allocatedObjectList;
385 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
388 +static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
391 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
393 + yaffs_TnodeList *tmp;
400 + while (allocator->allocatedTnodeList) {
401 + tmp = allocator->allocatedTnodeList->next;
403 + YFREE(allocator->allocatedTnodeList->tnodes);
404 + YFREE(allocator->allocatedTnodeList);
405 + allocator->allocatedTnodeList = tmp;
409 + allocator->freeTnodes = NULL;
410 + allocator->nFreeTnodes = 0;
411 + allocator->nTnodesCreated = 0;
414 +static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
416 + yaffs_Allocator *allocator = dev->allocator;
419 + allocator->allocatedTnodeList = NULL;
420 + allocator->freeTnodes = NULL;
421 + allocator->nFreeTnodes = 0;
422 + allocator->nTnodesCreated = 0;
427 +static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
429 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
431 + yaffs_Tnode *newTnodes;
435 + yaffs_TnodeList *tnl;
446 + /* make these things */
448 + newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
449 + mem = (__u8 *)newTnodes;
452 + T(YAFFS_TRACE_ERROR,
453 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
457 + /* New hookup for wide tnodes */
458 + for (i = 0; i < nTnodes - 1; i++) {
459 + curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
460 + next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
461 + curr->internal[0] = next;
464 + curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
465 + curr->internal[0] = allocator->freeTnodes;
466 + allocator->freeTnodes = (yaffs_Tnode *)mem;
468 + allocator->nFreeTnodes += nTnodes;
469 + allocator->nTnodesCreated += nTnodes;
471 + /* Now add this bunch of tnodes to a list for freeing up.
472 + * NB If we can't add this to the management list it isn't fatal
473 + * but it just means we can't free this bunch of tnodes later.
476 + tnl = YMALLOC(sizeof(yaffs_TnodeList));
478 + T(YAFFS_TRACE_ERROR,
480 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
483 + tnl->tnodes = newTnodes;
484 + tnl->next = allocator->allocatedTnodeList;
485 + allocator->allocatedTnodeList = tnl;
488 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
494 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
496 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
497 + yaffs_Tnode *tn = NULL;
504 + /* If there are none left make more */
505 + if (!allocator->freeTnodes)
506 + yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
508 + if (allocator->freeTnodes) {
509 + tn = allocator->freeTnodes;
510 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
511 + allocator->nFreeTnodes--;
517 +/* FreeTnode frees up a tnode and puts it back on the free list */
518 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
520 + yaffs_Allocator *allocator = dev->allocator;
528 + tn->internal[0] = allocator->freeTnodes;
529 + allocator->freeTnodes = tn;
530 + allocator->nFreeTnodes++;
532 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
537 +static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
539 + yaffs_Allocator *allocator = dev->allocator;
542 + allocator->allocatedObjectList = NULL;
543 + allocator->freeObjects = NULL;
544 + allocator->nFreeObjects = 0;
549 +static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
551 + yaffs_Allocator *allocator = dev->allocator;
552 + yaffs_ObjectList *tmp;
559 + while (allocator->allocatedObjectList) {
560 + tmp = allocator->allocatedObjectList->next;
561 + YFREE(allocator->allocatedObjectList->objects);
562 + YFREE(allocator->allocatedObjectList);
564 + allocator->allocatedObjectList = tmp;
567 + allocator->freeObjects = NULL;
568 + allocator->nFreeObjects = 0;
569 + allocator->nObjectsCreated = 0;
573 +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
575 + yaffs_Allocator *allocator = dev->allocator;
578 + yaffs_Object *newObjects;
579 + yaffs_ObjectList *list;
589 + /* make these things */
590 + newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
591 + list = YMALLOC(sizeof(yaffs_ObjectList));
593 + if (!newObjects || !list) {
602 + T(YAFFS_TRACE_ALLOCATE,
603 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
607 + /* Hook them into the free list */
608 + for (i = 0; i < nObjects - 1; i++) {
609 + newObjects[i].siblings.next =
610 + (struct ylist_head *)(&newObjects[i + 1]);
613 + newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
614 + allocator->freeObjects = newObjects;
615 + allocator->nFreeObjects += nObjects;
616 + allocator->nObjectsCreated += nObjects;
618 + /* Now add this bunch of Objects to a list for freeing up. */
620 + list->objects = newObjects;
621 + list->next = allocator->allocatedObjectList;
622 + allocator->allocatedObjectList = list;
627 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
629 + yaffs_Object *obj = NULL;
630 + yaffs_Allocator *allocator = dev->allocator;
637 + /* If there are none left make more */
638 + if (!allocator->freeObjects)
639 + yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
641 + if (allocator->freeObjects) {
642 + obj = allocator->freeObjects;
643 + allocator->freeObjects =
644 + (yaffs_Object *) (allocator->freeObjects->siblings.next);
645 + allocator->nFreeObjects--;
652 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
655 + yaffs_Allocator *allocator = dev->allocator;
660 + /* Link into the free list. */
661 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
662 + allocator->freeObjects = obj;
663 + allocator->nFreeObjects++;
667 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
669 + if(dev->allocator){
670 + yaffs_DeinitialiseRawTnodes(dev);
671 + yaffs_DeinitialiseRawObjects(dev);
673 + YFREE(dev->allocator);
674 + dev->allocator=NULL;
679 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
681 + yaffs_Allocator *allocator;
683 + if(!dev->allocator){
684 + allocator = YMALLOC(sizeof(yaffs_Allocator));
686 + dev->allocator = allocator;
687 + yaffs_InitialiseRawTnodes(dev);
688 + yaffs_InitialiseRawObjects(dev);
697 +++ b/fs/yaffs2/yaffs_allocator.h
700 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
702 + * Copyright (C) 2002-2010 Aleph One Ltd.
703 + * for Toby Churchill Ltd and Brightstar Engineering
705 + * Created by Charles Manning <charles@aleph1.co.uk>
707 + * This program is free software; you can redistribute it and/or modify
708 + * it under the terms of the GNU Lesser General Public License version 2.1 as
709 + * published by the Free Software Foundation.
711 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
714 +#ifndef __YAFFS_ALLOCATOR_H__
715 +#define __YAFFS_ALLOCATOR_H__
717 +#include "yaffs_guts.h"
719 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
720 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
722 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
723 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
725 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
726 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
730 +++ b/fs/yaffs2/yaffs_bitmap.c
733 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
735 + * Copyright (C) 2002-2010 Aleph One Ltd.
736 + * for Toby Churchill Ltd and Brightstar Engineering
738 + * Created by Charles Manning <charles@aleph1.co.uk>
740 + * This program is free software; you can redistribute it and/or modify
741 + * it under the terms of the GNU General Public License version 2 as
742 + * published by the Free Software Foundation.
745 +#include "yaffs_bitmap.h"
746 +#include "yaffs_trace.h"
748 + * Chunk bitmap manipulations
751 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
753 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
754 + T(YAFFS_TRACE_ERROR,
755 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
759 + return dev->chunkBits +
760 + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
763 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
765 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
766 + chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
767 + T(YAFFS_TRACE_ERROR,
768 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
774 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
776 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
778 + memset(blkBits, 0, dev->chunkBitmapStride);
781 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
783 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
785 + yaffs_VerifyChunkBitId(dev, blk, chunk);
787 + blkBits[chunk / 8] &= ~(1 << (chunk & 7));
790 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
792 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
794 + yaffs_VerifyChunkBitId(dev, blk, chunk);
796 + blkBits[chunk / 8] |= (1 << (chunk & 7));
799 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
801 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
802 + yaffs_VerifyChunkBitId(dev, blk, chunk);
804 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
807 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
809 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
811 + for (i = 0; i < dev->chunkBitmapStride; i++) {
819 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
821 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
824 + for (i = 0; i < dev->chunkBitmapStride; i++) {
838 +++ b/fs/yaffs2/yaffs_bitmap.h
841 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
843 + * Copyright (C) 2002-2010 Aleph One Ltd.
844 + * for Toby Churchill Ltd and Brightstar Engineering
846 + * Created by Charles Manning <charles@aleph1.co.uk>
848 + * This program is free software; you can redistribute it and/or modify
849 + * it under the terms of the GNU General Public License version 2 as
850 + * published by the Free Software Foundation.
854 + * Chunk bitmap manipulations
857 +#ifndef __YAFFS_BITMAP_H__
858 +#define __YAFFS_BITMAP_H__
860 +#include "yaffs_guts.h"
862 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
863 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
864 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
865 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
866 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
867 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
868 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
871 --- a/fs/yaffs2/yaffs_checkptrw.c
872 +++ b/fs/yaffs2/yaffs_checkptrw.c
875 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
877 - * Copyright (C) 2002-2007 Aleph One Ltd.
878 + * Copyright (C) 2002-2010 Aleph One Ltd.
879 * for Toby Churchill Ltd and Brightstar Engineering
881 * Created by Charles Manning <charles@aleph1.co.uk>
883 * published by the Free Software Foundation.
886 -const char *yaffs_checkptrw_c_version =
887 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
890 #include "yaffs_checkptrw.h"
891 #include "yaffs_getblockinfo.h"
893 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
894 +static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev)
896 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
897 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
899 T(YAFFS_TRACE_CHECKPOINT,
900 (TSTR("checkpt blocks available = %d" TENDSTR),
901 @@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs
905 -static int yaffs_CheckpointErase(yaffs_Device *dev)
906 +static int yaffs2_CheckpointErase(yaffs_Device *dev)
910 - if (!dev->eraseBlockInNAND)
911 + if (!dev->param.eraseBlockInNAND)
913 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
914 dev->internalStartBlock, dev->internalEndBlock));
915 @@ -43,12 +39,15 @@ static int yaffs_CheckpointErase(yaffs_D
916 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
917 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
918 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
919 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
921 + dev->nBlockErasures++;
923 + if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
924 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
925 dev->nErasedBlocks++;
926 - dev->nFreeChunks += dev->nChunksPerBlock;
927 + dev->nFreeChunks += dev->param.nChunksPerBlock;
929 - dev->markNANDBlockBad(dev, i);
930 + dev->param.markNANDBlockBad(dev, i);
931 bi->blockState = YAFFS_BLOCK_STATE_DEAD;
934 @@ -60,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_D
938 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
939 +static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev)
942 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
943 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
944 T(YAFFS_TRACE_CHECKPOINT,
945 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
946 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
947 + dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
949 if (dev->checkpointNextBlock >= 0 &&
950 dev->checkpointNextBlock <= dev->internalEndBlock &&
951 @@ -88,7 +87,7 @@ static void yaffs_CheckpointFindNextEras
952 dev->checkpointCurrentBlock = -1;
955 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
956 +static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
959 yaffs_ExtendedTags tags;
960 @@ -98,10 +97,10 @@ static void yaffs_CheckpointFindNextChec
962 if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
963 for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
964 - int chunk = i * dev->nChunksPerBlock;
965 + int chunk = i * dev->param.nChunksPerBlock;
966 int realignedChunk = chunk - dev->chunkOffset;
968 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
969 + dev->param.readChunkWithTagsFromNAND(dev, realignedChunk,
971 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
972 i, tags.objectId, tags.sequenceNumber, tags.eccResult));
973 @@ -124,29 +123,29 @@ static void yaffs_CheckpointFindNextChec
977 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
978 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting)
982 + dev->checkpointOpenForWrite = forWriting;
984 /* Got the functions we need? */
985 - if (!dev->writeChunkWithTagsToNAND ||
986 - !dev->readChunkWithTagsFromNAND ||
987 - !dev->eraseBlockInNAND ||
988 - !dev->markNANDBlockBad)
989 + if (!dev->param.writeChunkWithTagsToNAND ||
990 + !dev->param.readChunkWithTagsFromNAND ||
991 + !dev->param.eraseBlockInNAND ||
992 + !dev->param.markNANDBlockBad)
995 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
996 + if (forWriting && !yaffs2_CheckpointSpaceOk(dev))
999 if (!dev->checkpointBuffer)
1000 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1001 + dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk);
1002 if (!dev->checkpointBuffer)
1006 dev->checkpointPageSequence = 0;
1008 - dev->checkpointOpenForWrite = forWriting;
1010 dev->checkpointByteCount = 0;
1011 dev->checkpointSum = 0;
1012 dev->checkpointXor = 0;
1013 @@ -158,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1015 memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1016 dev->checkpointByteOffset = 0;
1017 - return yaffs_CheckpointErase(dev);
1018 + return yaffs2_CheckpointErase(dev);
1021 /* Set to a value that will kick off a read */
1022 @@ -168,6 +167,9 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1023 dev->blocksInCheckpoint = 0;
1024 dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1025 dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1026 + if(!dev->checkpointBlockList)
1029 for (i = 0; i < dev->checkpointMaxBlocks; i++)
1030 dev->checkpointBlockList[i] = -1;
1032 @@ -175,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1036 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1037 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1040 compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1041 @@ -183,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device
1045 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1046 +static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev)
1050 @@ -191,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(y
1051 yaffs_ExtendedTags tags;
1053 if (dev->checkpointCurrentBlock < 0) {
1054 - yaffs_CheckpointFindNextErasedBlock(dev);
1055 + yaffs2_CheckpointFindNextErasedBlock(dev);
1056 dev->checkpointCurrentChunk = 0;
1059 @@ -211,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(y
1060 dev->blocksInCheckpoint++;
1063 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1064 + chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk;
1067 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1068 @@ -219,12 +221,14 @@ static int yaffs_CheckpointFlushBuffer(y
1070 realignedChunk = chunk - dev->chunkOffset;
1072 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1073 + dev->nPageWrites++;
1075 + dev->param.writeChunkWithTagsToNAND(dev, realignedChunk,
1076 dev->checkpointBuffer, &tags);
1077 dev->checkpointByteOffset = 0;
1078 dev->checkpointPageSequence++;
1079 dev->checkpointCurrentChunk++;
1080 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1081 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) {
1082 dev->checkpointCurrentChunk = 0;
1083 dev->checkpointCurrentBlock = -1;
1085 @@ -234,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(y
1089 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1090 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1094 @@ -263,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *
1096 if (dev->checkpointByteOffset < 0 ||
1097 dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1098 - ok = yaffs_CheckpointFlushBuffer(dev);
1099 + ok = yaffs2_CheckpointFlushBuffer(dev);
1105 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1106 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1110 @@ -294,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1111 dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1113 if (dev->checkpointCurrentBlock < 0) {
1114 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1115 + yaffs2_CheckpointFindNextCheckpointBlock(dev);
1116 dev->checkpointCurrentChunk = 0;
1119 @@ -302,14 +306,16 @@ int yaffs_CheckpointRead(yaffs_Device *d
1122 chunk = dev->checkpointCurrentBlock *
1123 - dev->nChunksPerBlock +
1124 + dev->param.nChunksPerBlock +
1125 dev->checkpointCurrentChunk;
1127 realignedChunk = chunk - dev->chunkOffset;
1129 + dev->nPageReads++;
1131 /* read in the next chunk */
1132 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1133 - dev->readChunkWithTagsFromNAND(dev,
1134 + dev->param.readChunkWithTagsFromNAND(dev,
1136 dev->checkpointBuffer,
1138 @@ -323,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1139 dev->checkpointPageSequence++;
1140 dev->checkpointCurrentChunk++;
1142 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1143 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock)
1144 dev->checkpointCurrentBlock = -1;
1147 @@ -342,17 +348,20 @@ int yaffs_CheckpointRead(yaffs_Device *d
1151 -int yaffs_CheckpointClose(yaffs_Device *dev)
1152 +int yaffs2_CheckpointClose(yaffs_Device *dev)
1155 if (dev->checkpointOpenForWrite) {
1156 if (dev->checkpointByteOffset != 0)
1157 - yaffs_CheckpointFlushBuffer(dev);
1159 + yaffs2_CheckpointFlushBuffer(dev);
1160 + } else if(dev->checkpointBlockList){
1162 for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1163 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1164 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1165 + int blk = dev->checkpointBlockList[i];
1166 + yaffs_BlockInfo *bi = NULL;
1167 + if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
1168 + bi = yaffs_GetBlockInfo(dev, blk);
1169 + if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1170 bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1172 /* Todo this looks odd... */
1173 @@ -362,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *
1174 dev->checkpointBlockList = NULL;
1177 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1178 + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock;
1179 dev->nErasedBlocks -= dev->blocksInCheckpoint;
1182 @@ -378,16 +387,14 @@ int yaffs_CheckpointClose(yaffs_Device *
1186 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1187 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev)
1189 - /* Erase the first checksum block */
1191 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1192 + /* Erase the checkpoint data */
1194 - if (!yaffs_CheckpointSpaceOk(dev))
1196 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1197 + dev->blocksInCheckpoint));
1199 - return yaffs_CheckpointErase(dev);
1200 + return yaffs2_CheckpointErase(dev);
1204 --- a/fs/yaffs2/yaffs_checkptrw.h
1205 +++ b/fs/yaffs2/yaffs_checkptrw.h
1208 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1210 - * Copyright (C) 2002-2007 Aleph One Ltd.
1211 + * Copyright (C) 2002-2010 Aleph One Ltd.
1212 * for Toby Churchill Ltd and Brightstar Engineering
1214 * Created by Charles Manning <charles@aleph1.co.uk>
1217 #include "yaffs_guts.h"
1219 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1220 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting);
1222 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1223 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1225 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1226 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1228 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1229 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1231 -int yaffs_CheckpointClose(yaffs_Device *dev);
1232 +int yaffs2_CheckpointClose(yaffs_Device *dev);
1234 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1235 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev);
1240 --- a/fs/yaffs2/yaffs_ecc.c
1241 +++ b/fs/yaffs2/yaffs_ecc.c
1244 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1246 - * Copyright (C) 2002-2007 Aleph One Ltd.
1247 + * Copyright (C) 2002-2010 Aleph One Ltd.
1248 * for Toby Churchill Ltd and Brightstar Engineering
1250 * Created by Charles Manning <charles@aleph1.co.uk>
1252 * this bytes influence on the line parity.
1255 -const char *yaffs_ecc_c_version =
1256 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1258 #include "yportenv.h"
1260 #include "yaffs_ecc.h"
1261 --- a/fs/yaffs2/yaffs_ecc.h
1262 +++ b/fs/yaffs2/yaffs_ecc.h
1265 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1267 - * Copyright (C) 2002-2007 Aleph One Ltd.
1268 + * Copyright (C) 2002-2010 Aleph One Ltd.
1269 * for Toby Churchill Ltd and Brightstar Engineering
1271 * Created by Charles Manning <charles@aleph1.co.uk>
1272 --- a/fs/yaffs2/yaffs_fs.c
1276 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1278 - * Copyright (C) 2002-2009 Aleph One Ltd.
1279 - * for Toby Churchill Ltd and Brightstar Engineering
1281 - * Created by Charles Manning <charles@aleph1.co.uk>
1282 - * Acknowledgements:
1283 - * Luc van OostenRyck for numerous patches.
1284 - * Nick Bane for numerous patches.
1285 - * Nick Bane for 2.5/2.6 integration.
1286 - * Andras Toth for mknod rdev issue.
1287 - * Michael Fischer for finding the problem with inode inconsistency.
1288 - * Some code bodily lifted from JFFS
1290 - * This program is free software; you can redistribute it and/or modify
1291 - * it under the terms of the GNU General Public License version 2 as
1292 - * published by the Free Software Foundation.
1297 - * This is the file system front-end to YAFFS that hooks it up to
1301 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1303 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1305 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1308 -const char *yaffs_fs_c_version =
1309 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1310 -extern const char *yaffs_guts_c_version;
1312 -#include <linux/version.h>
1313 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1314 -#include <linux/config.h>
1316 -#include <linux/kernel.h>
1317 -#include <linux/module.h>
1318 -#include <linux/slab.h>
1319 -#include <linux/init.h>
1320 -#include <linux/fs.h>
1321 -#include <linux/proc_fs.h>
1322 -#include <linux/smp_lock.h>
1323 -#include <linux/pagemap.h>
1324 -#include <linux/mtd/mtd.h>
1325 -#include <linux/interrupt.h>
1326 -#include <linux/string.h>
1327 -#include <linux/ctype.h>
1329 -#include "asm/div64.h"
1331 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1333 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1334 -#include <linux/statfs.h>
1335 -#define UnlockPage(p) unlock_page(p)
1336 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1338 -/* FIXME: use sb->s_id instead ? */
1339 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1343 -#include <linux/locks.h>
1344 -#define BDEVNAME_SIZE 0
1345 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1347 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1348 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1354 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1355 -#define YPROC_ROOT (&proc_root)
1357 -#define YPROC_ROOT NULL
1360 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1361 -#define WRITE_SIZE_STR "writesize"
1362 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1364 -#define WRITE_SIZE_STR "oobblock"
1365 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1368 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1369 -#define YAFFS_USE_WRITE_BEGIN_END 1
1371 -#define YAFFS_USE_WRITE_BEGIN_END 0
1374 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1375 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1377 - uint64_t result = partition_size;
1378 - do_div(result, block_size);
1379 - return (uint32_t)result;
1382 -#define YCALCBLOCKS(s, b) ((s)/(b))
1385 -#include <linux/uaccess.h>
1387 -#include "yportenv.h"
1388 -#include "yaffs_guts.h"
1390 -#include <linux/mtd/mtd.h>
1391 -#include "yaffs_mtdif.h"
1392 -#include "yaffs_mtdif1.h"
1393 -#include "yaffs_mtdif2.h"
1395 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1396 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1397 -unsigned int yaffs_auto_checkpoint = 1;
1399 -/* Module Parameters */
1400 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1401 -module_param(yaffs_traceMask, uint, 0644);
1402 -module_param(yaffs_wr_attempts, uint, 0644);
1403 -module_param(yaffs_auto_checkpoint, uint, 0644);
1405 -MODULE_PARM(yaffs_traceMask, "i");
1406 -MODULE_PARM(yaffs_wr_attempts, "i");
1407 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1410 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1411 -/* use iget and read_inode */
1412 -#define Y_IGET(sb, inum) iget((sb), (inum))
1413 -static void yaffs_read_inode(struct inode *inode);
1416 -/* Call local equivalent */
1417 -#define YAFFS_USE_OWN_IGET
1418 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1420 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1423 -/*#define T(x) printk x */
1425 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1426 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1428 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1431 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1432 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1434 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1435 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1437 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1440 -static void yaffs_put_super(struct super_block *sb);
1442 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1444 -static ssize_t yaffs_hold_space(struct file *f);
1445 -static void yaffs_release_space(struct file *f);
1447 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1448 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1450 -static int yaffs_file_flush(struct file *file);
1453 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1456 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1458 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1459 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1460 - struct nameidata *n);
1461 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1462 - struct nameidata *n);
1464 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1465 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1467 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1468 - struct dentry *dentry);
1469 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1470 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1471 - const char *symname);
1472 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1474 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1475 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1478 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1481 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1482 - struct inode *new_dir, struct dentry *new_dentry);
1483 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1485 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1486 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1487 -static void yaffs_write_super(struct super_block *sb);
1489 -static int yaffs_sync_fs(struct super_block *sb);
1490 -static int yaffs_write_super(struct super_block *sb);
1493 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1494 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1495 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1496 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1498 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1501 -#ifdef YAFFS_HAS_PUT_INODE
1502 -static void yaffs_put_inode(struct inode *inode);
1505 -static void yaffs_delete_inode(struct inode *);
1506 -static void yaffs_clear_inode(struct inode *);
1508 -static int yaffs_readpage(struct file *file, struct page *page);
1509 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1510 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1512 -static int yaffs_writepage(struct page *page);
1516 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1517 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1518 - loff_t pos, unsigned len, unsigned flags,
1519 - struct page **pagep, void **fsdata);
1520 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1521 - loff_t pos, unsigned len, unsigned copied,
1522 - struct page *pg, void *fsdadata);
1524 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1525 - unsigned offset, unsigned to);
1526 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1531 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1533 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1534 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1536 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1539 -static struct address_space_operations yaffs_file_address_operations = {
1540 - .readpage = yaffs_readpage,
1541 - .writepage = yaffs_writepage,
1542 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1543 - .write_begin = yaffs_write_begin,
1544 - .write_end = yaffs_write_end,
1546 - .prepare_write = yaffs_prepare_write,
1547 - .commit_write = yaffs_commit_write,
1551 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1552 -static const struct file_operations yaffs_file_operations = {
1553 - .read = do_sync_read,
1554 - .write = do_sync_write,
1555 - .aio_read = generic_file_aio_read,
1556 - .aio_write = generic_file_aio_write,
1557 - .mmap = generic_file_mmap,
1558 - .flush = yaffs_file_flush,
1559 - .fsync = yaffs_sync_object,
1560 - .splice_read = generic_file_splice_read,
1561 - .splice_write = generic_file_splice_write,
1562 - .llseek = generic_file_llseek,
1565 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1567 -static const struct file_operations yaffs_file_operations = {
1568 - .read = do_sync_read,
1569 - .write = do_sync_write,
1570 - .aio_read = generic_file_aio_read,
1571 - .aio_write = generic_file_aio_write,
1572 - .mmap = generic_file_mmap,
1573 - .flush = yaffs_file_flush,
1574 - .fsync = yaffs_sync_object,
1575 - .sendfile = generic_file_sendfile,
1580 -static const struct file_operations yaffs_file_operations = {
1581 - .read = generic_file_read,
1582 - .write = generic_file_write,
1583 - .mmap = generic_file_mmap,
1584 - .flush = yaffs_file_flush,
1585 - .fsync = yaffs_sync_object,
1586 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1587 - .sendfile = generic_file_sendfile,
1592 -static const struct inode_operations yaffs_file_inode_operations = {
1593 - .setattr = yaffs_setattr,
1596 -static const struct inode_operations yaffs_symlink_inode_operations = {
1597 - .readlink = yaffs_readlink,
1598 - .follow_link = yaffs_follow_link,
1599 - .setattr = yaffs_setattr,
1602 -static const struct inode_operations yaffs_dir_inode_operations = {
1603 - .create = yaffs_create,
1604 - .lookup = yaffs_lookup,
1605 - .link = yaffs_link,
1606 - .unlink = yaffs_unlink,
1607 - .symlink = yaffs_symlink,
1608 - .mkdir = yaffs_mkdir,
1609 - .rmdir = yaffs_unlink,
1610 - .mknod = yaffs_mknod,
1611 - .rename = yaffs_rename,
1612 - .setattr = yaffs_setattr,
1615 -static const struct file_operations yaffs_dir_operations = {
1616 - .read = generic_read_dir,
1617 - .readdir = yaffs_readdir,
1618 - .fsync = yaffs_sync_object,
1621 -static const struct super_operations yaffs_super_ops = {
1622 - .statfs = yaffs_statfs,
1624 -#ifndef YAFFS_USE_OWN_IGET
1625 - .read_inode = yaffs_read_inode,
1627 -#ifdef YAFFS_HAS_PUT_INODE
1628 - .put_inode = yaffs_put_inode,
1630 - .put_super = yaffs_put_super,
1631 - .delete_inode = yaffs_delete_inode,
1632 - .clear_inode = yaffs_clear_inode,
1633 - .sync_fs = yaffs_sync_fs,
1634 - .write_super = yaffs_write_super,
1637 -static void yaffs_GrossLock(yaffs_Device *dev)
1639 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
1640 - down(&dev->grossLock);
1641 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
1644 -static void yaffs_GrossUnlock(yaffs_Device *dev)
1646 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
1647 - up(&dev->grossLock);
1650 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1653 - unsigned char *alias;
1656 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1658 - yaffs_GrossLock(dev);
1660 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1662 - yaffs_GrossUnlock(dev);
1667 - ret = vfs_readlink(dentry, buffer, buflen, alias);
1672 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1673 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1675 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1678 - unsigned char *alias;
1680 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1682 - yaffs_GrossLock(dev);
1684 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1686 - yaffs_GrossUnlock(dev);
1693 - ret = vfs_follow_link(nd, alias);
1696 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1697 - return ERR_PTR(ret);
1703 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1704 - yaffs_Object *obj);
1707 - * Lookup is used to find objects in the fs
1709 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1711 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1712 - struct nameidata *n)
1714 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
1717 - yaffs_Object *obj;
1718 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
1720 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
1722 - yaffs_GrossLock(dev);
1725 - ("yaffs_lookup for %d:%s\n",
1726 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
1728 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
1729 - dentry->d_name.name);
1731 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
1733 - /* Can't hold gross lock when calling yaffs_get_inode() */
1734 - yaffs_GrossUnlock(dev);
1738 - ("yaffs_lookup found %d\n", obj->objectId));
1740 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1744 - ("yaffs_loookup dentry \n"));
1745 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
1746 - * d_add even if NULL inode */
1748 - /*dget(dentry); // try to solve directory bug */
1749 - d_add(dentry, inode);
1751 - /* return dentry; */
1757 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
1761 -/* added NCB for 2.5/6 compatability - forces add even if inode is
1762 - * NULL which creates dentry hash */
1763 - d_add(dentry, inode);
1769 -#ifdef YAFFS_HAS_PUT_INODE
1771 -/* For now put inode is just for debugging
1772 - * Put inode is called when the inode **structure** is put.
1774 -static void yaffs_put_inode(struct inode *inode)
1777 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
1778 - atomic_read(&inode->i_count)));
1783 -/* clear is called to tell the fs to release any per-inode data it holds */
1784 -static void yaffs_clear_inode(struct inode *inode)
1786 - yaffs_Object *obj;
1787 - yaffs_Device *dev;
1789 - obj = yaffs_InodeToObject(inode);
1792 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1793 - atomic_read(&inode->i_count),
1794 - obj ? "object exists" : "null object"));
1798 - yaffs_GrossLock(dev);
1800 - /* Clear the association between the inode and
1801 - * the yaffs_Object.
1803 - obj->myInode = NULL;
1804 - yaffs_InodeToObjectLV(inode) = NULL;
1806 - /* If the object freeing was deferred, then the real
1807 - * free happens now.
1808 - * This should fix the inode inconsistency problem.
1811 - yaffs_HandleDeferedFree(obj);
1813 - yaffs_GrossUnlock(dev);
1818 -/* delete is called when the link count is zero and the inode
1819 - * is put (ie. nobody wants to know about it anymore, time to
1820 - * delete the file).
1821 - * NB Must call clear_inode()
1823 -static void yaffs_delete_inode(struct inode *inode)
1825 - yaffs_Object *obj = yaffs_InodeToObject(inode);
1826 - yaffs_Device *dev;
1829 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1830 - atomic_read(&inode->i_count),
1831 - obj ? "object exists" : "null object"));
1835 - yaffs_GrossLock(dev);
1836 - yaffs_DeleteObject(obj);
1837 - yaffs_GrossUnlock(dev);
1839 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1840 - truncate_inode_pages(&inode->i_data, 0);
1842 - clear_inode(inode);
1845 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1846 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
1848 -static int yaffs_file_flush(struct file *file)
1851 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1853 - yaffs_Device *dev = obj->myDev;
1856 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
1857 - obj->dirty ? "dirty" : "clean"));
1859 - yaffs_GrossLock(dev);
1861 - yaffs_FlushFile(obj, 1);
1863 - yaffs_GrossUnlock(dev);
1868 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
1870 - /* Lifted from jffs2 */
1872 - yaffs_Object *obj;
1873 - unsigned char *pg_buf;
1876 - yaffs_Device *dev;
1878 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
1879 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
1880 - (unsigned)PAGE_CACHE_SIZE));
1882 - obj = yaffs_DentryToObject(f->f_dentry);
1886 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1887 - BUG_ON(!PageLocked(pg));
1889 - if (!PageLocked(pg))
1893 - pg_buf = kmap(pg);
1894 - /* FIXME: Can kmap fail? */
1896 - yaffs_GrossLock(dev);
1898 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
1899 - pg->index << PAGE_CACHE_SHIFT,
1902 - yaffs_GrossUnlock(dev);
1908 - ClearPageUptodate(pg);
1911 - SetPageUptodate(pg);
1912 - ClearPageError(pg);
1915 - flush_dcache_page(pg);
1918 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
1922 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1924 - int ret = yaffs_readpage_nolock(f, pg);
1929 -static int yaffs_readpage(struct file *f, struct page *pg)
1931 - return yaffs_readpage_unlock(f, pg);
1934 -/* writepage inspired by/stolen from smbfs */
1936 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1937 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1939 -static int yaffs_writepage(struct page *page)
1942 - struct address_space *mapping = page->mapping;
1943 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
1944 - struct inode *inode;
1945 - unsigned long end_index;
1947 - yaffs_Object *obj;
1953 - inode = mapping->host;
1957 - if (offset > inode->i_size) {
1959 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
1960 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
1961 - (unsigned)inode->i_size));
1963 - (" -> don't care!!\n"));
1964 - unlock_page(page);
1968 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1971 - if (page->index < end_index)
1972 - nBytes = PAGE_CACHE_SIZE;
1974 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
1978 - buffer = kmap(page);
1980 - obj = yaffs_InodeToObject(inode);
1981 - yaffs_GrossLock(obj->myDev);
1984 - ("yaffs_writepage at %08x, size %08x\n",
1985 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
1987 - ("writepag0: obj = %05x, ino = %05x\n",
1988 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
1990 - nWritten = yaffs_WriteDataToFile(obj, buffer,
1991 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
1994 - ("writepag1: obj = %05x, ino = %05x\n",
1995 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
1997 - yaffs_GrossUnlock(obj->myDev);
2000 - SetPageUptodate(page);
2004 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2008 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2009 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2010 - loff_t pos, unsigned len, unsigned flags,
2011 - struct page **pagep, void **fsdata)
2013 - struct page *pg = NULL;
2014 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2015 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2016 - uint32_t to = offset + len;
2019 - int space_held = 0;
2021 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2023 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2024 - pg = grab_cache_page_write_begin(mapping, index, flags);
2026 - pg = __grab_cache_page(mapping, index);
2034 - /* Get fs space */
2035 - space_held = yaffs_hold_space(filp);
2037 - if (!space_held) {
2042 - /* Update page if required */
2044 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2045 - ret = yaffs_readpage_nolock(filp, pg);
2050 - /* Happy path return */
2051 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2056 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2058 - yaffs_release_space(filp);
2061 - page_cache_release(pg);
2068 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2069 - unsigned offset, unsigned to)
2071 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2073 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2074 - return yaffs_readpage_nolock(f, pg);
2079 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2080 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2081 - loff_t pos, unsigned len, unsigned copied,
2082 - struct page *pg, void *fsdadata)
2086 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2089 - addr = kva + offset_into_page;
2092 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2094 - (int)pos, copied));
2096 - ret = yaffs_file_write(filp, addr, copied, &pos);
2098 - if (ret != copied) {
2100 - ("yaffs_write_end not same size ret %d copied %d\n",
2103 - ClearPageUptodate(pg);
2105 - SetPageUptodate(pg);
2110 - yaffs_release_space(filp);
2112 - page_cache_release(pg);
2117 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2122 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2123 - int nBytes = to - offset;
2126 - unsigned spos = pos;
2130 - addr = kva + offset;
2132 - saddr = (unsigned) addr;
2135 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2136 - saddr, spos, nBytes));
2138 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2140 - if (nWritten != nBytes) {
2142 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2143 - nWritten, nBytes));
2145 - ClearPageUptodate(pg);
2147 - SetPageUptodate(pg);
2153 - ("yaffs_commit_write returning %d\n",
2154 - nWritten == nBytes ? 0 : nWritten));
2156 - return nWritten == nBytes ? 0 : nWritten;
2161 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2163 - if (inode && obj) {
2166 - /* Check mode against the variant type and attempt to repair if broken. */
2167 - __u32 mode = obj->yst_mode;
2168 - switch (obj->variantType) {
2169 - case YAFFS_OBJECT_TYPE_FILE:
2170 - if (!S_ISREG(mode)) {
2171 - obj->yst_mode &= ~S_IFMT;
2172 - obj->yst_mode |= S_IFREG;
2176 - case YAFFS_OBJECT_TYPE_SYMLINK:
2177 - if (!S_ISLNK(mode)) {
2178 - obj->yst_mode &= ~S_IFMT;
2179 - obj->yst_mode |= S_IFLNK;
2183 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2184 - if (!S_ISDIR(mode)) {
2185 - obj->yst_mode &= ~S_IFMT;
2186 - obj->yst_mode |= S_IFDIR;
2190 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2191 - case YAFFS_OBJECT_TYPE_HARDLINK:
2192 - case YAFFS_OBJECT_TYPE_SPECIAL:
2198 - inode->i_flags |= S_NOATIME;
2200 - inode->i_ino = obj->objectId;
2201 - inode->i_mode = obj->yst_mode;
2202 - inode->i_uid = obj->yst_uid;
2203 - inode->i_gid = obj->yst_gid;
2204 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2205 - inode->i_blksize = inode->i_sb->s_blocksize;
2207 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2209 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2210 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2211 - inode->i_atime.tv_nsec = 0;
2212 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2213 - inode->i_mtime.tv_nsec = 0;
2214 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2215 - inode->i_ctime.tv_nsec = 0;
2217 - inode->i_rdev = obj->yst_rdev;
2218 - inode->i_atime = obj->yst_atime;
2219 - inode->i_mtime = obj->yst_mtime;
2220 - inode->i_ctime = obj->yst_ctime;
2222 - inode->i_size = yaffs_GetObjectFileLength(obj);
2223 - inode->i_blocks = (inode->i_size + 511) >> 9;
2225 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2228 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2229 - inode->i_mode, inode->i_uid, inode->i_gid,
2230 - (int)inode->i_size, atomic_read(&inode->i_count)));
2232 - switch (obj->yst_mode & S_IFMT) {
2233 - default: /* fifo, device or socket */
2234 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2235 - init_special_inode(inode, obj->yst_mode,
2236 - old_decode_dev(obj->yst_rdev));
2238 - init_special_inode(inode, obj->yst_mode,
2239 - (dev_t) (obj->yst_rdev));
2242 - case S_IFREG: /* file */
2243 - inode->i_op = &yaffs_file_inode_operations;
2244 - inode->i_fop = &yaffs_file_operations;
2245 - inode->i_mapping->a_ops =
2246 - &yaffs_file_address_operations;
2248 - case S_IFDIR: /* directory */
2249 - inode->i_op = &yaffs_dir_inode_operations;
2250 - inode->i_fop = &yaffs_dir_operations;
2252 - case S_IFLNK: /* symlink */
2253 - inode->i_op = &yaffs_symlink_inode_operations;
2257 - yaffs_InodeToObjectLV(inode) = obj;
2259 - obj->myInode = inode;
2263 - ("yaffs_FileInode invalid parameters\n"));
2268 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2269 - yaffs_Object *obj)
2271 - struct inode *inode;
2275 - ("yaffs_get_inode for NULL super_block!!\n"));
2282 - ("yaffs_get_inode for NULL object!!\n"));
2288 - ("yaffs_get_inode for object %d\n", obj->objectId));
2290 - inode = Y_IGET(sb, obj->objectId);
2291 - if (IS_ERR(inode))
2294 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2295 - /* iget also increments the inode's i_count */
2296 - /* NB You can't be holding grossLock or deadlock will happen! */
2301 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2304 - yaffs_Object *obj;
2305 - int nWritten, ipos;
2306 - struct inode *inode;
2307 - yaffs_Device *dev;
2309 - obj = yaffs_DentryToObject(f->f_dentry);
2313 - yaffs_GrossLock(dev);
2315 - inode = f->f_dentry->d_inode;
2317 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2318 - ipos = inode->i_size;
2324 - ("yaffs_file_write: hey obj is null!\n"));
2327 - ("yaffs_file_write about to write writing %zu bytes"
2328 - "to object %d at %d\n",
2329 - n, obj->objectId, ipos));
2331 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2334 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2335 - n, nWritten, ipos));
2337 - if (nWritten > 0) {
2340 - if (ipos > inode->i_size) {
2341 - inode->i_size = ipos;
2342 - inode->i_blocks = (ipos + 511) >> 9;
2345 - ("yaffs_file_write size updated to %d bytes, "
2347 - ipos, (int)(inode->i_blocks)));
2351 - yaffs_GrossUnlock(dev);
2352 - return nWritten == 0 ? -ENOSPC : nWritten;
2355 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2356 -/* For now we just assume few parallel writes and check against a small number. */
2357 -/* Todo: need to do this with a counter to handle parallel reads better */
2359 -static ssize_t yaffs_hold_space(struct file *f)
2361 - yaffs_Object *obj;
2362 - yaffs_Device *dev;
2367 - obj = yaffs_DentryToObject(f->f_dentry);
2371 - yaffs_GrossLock(dev);
2373 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2375 - yaffs_GrossUnlock(dev);
2377 - return (nFreeChunks > 20) ? 1 : 0;
2380 -static void yaffs_release_space(struct file *f)
2382 - yaffs_Object *obj;
2383 - yaffs_Device *dev;
2386 - obj = yaffs_DentryToObject(f->f_dentry);
2390 - yaffs_GrossLock(dev);
2393 - yaffs_GrossUnlock(dev);
2396 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2398 - yaffs_Object *obj;
2399 - yaffs_Device *dev;
2400 - struct inode *inode = f->f_dentry->d_inode;
2401 - unsigned long offset, curoffs;
2402 - struct ylist_head *i;
2405 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2407 - obj = yaffs_DentryToObject(f->f_dentry);
2410 - yaffs_GrossLock(dev);
2412 - offset = f->f_pos;
2414 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2416 - if (offset == 0) {
2418 - ("yaffs_readdir: entry . ino %d \n",
2419 - (int)inode->i_ino));
2420 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2425 - if (offset == 1) {
2427 - ("yaffs_readdir: entry .. ino %d \n",
2428 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2429 - if (filldir(dirent, "..", 2, offset,
2430 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2438 - /* If the directory has changed since the open or last call to
2439 - readdir, rewind to after the 2 canned entries. */
2441 - if (f->f_version != inode->i_version) {
2443 - f->f_pos = offset;
2444 - f->f_version = inode->i_version;
2447 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2449 - if (curoffs >= offset) {
2450 - l = ylist_entry(i, yaffs_Object, siblings);
2452 - yaffs_GetObjectName(l, name,
2453 - YAFFS_MAX_NAME_LENGTH + 1);
2455 - ("yaffs_readdir: %s inode %d\n", name,
2456 - yaffs_GetObjectInode(l)));
2458 - if (filldir(dirent,
2462 - yaffs_GetObjectInode(l),
2463 - yaffs_GetObjectType(l)) < 0)
2473 - yaffs_GrossUnlock(dev);
2479 - * File creation. Allocate an inode, and we're done..
2482 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2485 -#define YCRED(x) (x->cred)
2488 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2489 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2492 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2496 - struct inode *inode;
2498 - yaffs_Object *obj = NULL;
2499 - yaffs_Device *dev;
2501 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2503 - int error = -ENOSPC;
2504 - uid_t uid = YCRED(current)->fsuid;
2505 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2507 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2512 - ("yaffs_mknod: parent object %d type %d\n",
2513 - parent->objectId, parent->variantType));
2516 - ("yaffs_mknod: could not get parent object\n"));
2520 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2521 - "mode %x dev %x\n",
2522 - dentry->d_name.name, mode, rdev));
2524 - dev = parent->myDev;
2526 - yaffs_GrossLock(dev);
2528 - switch (mode & S_IFMT) {
2530 - /* Special (socket, fifo, device...) */
2531 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2532 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2533 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2534 - gid, old_encode_dev(rdev));
2536 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2540 - case S_IFREG: /* file */
2541 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2542 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2545 - case S_IFDIR: /* directory */
2547 - ("yaffs_mknod: making directory\n"));
2548 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2551 - case S_IFLNK: /* symlink */
2552 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2553 - obj = NULL; /* Do we ever get here? */
2557 - /* Can not call yaffs_get_inode() with gross lock held */
2558 - yaffs_GrossUnlock(dev);
2561 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2562 - d_instantiate(dentry, inode);
2564 - ("yaffs_mknod created object %d count = %d\n",
2565 - obj->objectId, atomic_read(&inode->i_count)));
2569 - ("yaffs_mknod failed making object\n"));
2576 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2579 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2580 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2584 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2585 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2586 - struct nameidata *n)
2588 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2591 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
2592 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
2595 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
2599 - yaffs_Device *dev;
2602 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
2603 - dentry->d_name.name));
2605 - dev = yaffs_InodeToObject(dir)->myDev;
2607 - yaffs_GrossLock(dev);
2609 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
2611 - if (retVal == YAFFS_OK) {
2612 - dentry->d_inode->i_nlink--;
2614 - yaffs_GrossUnlock(dev);
2615 - mark_inode_dirty(dentry->d_inode);
2618 - yaffs_GrossUnlock(dev);
2619 - return -ENOTEMPTY;
2623 - * Create a link...
2625 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
2626 - struct dentry *dentry)
2628 - struct inode *inode = old_dentry->d_inode;
2629 - yaffs_Object *obj = NULL;
2630 - yaffs_Object *link = NULL;
2631 - yaffs_Device *dev;
2633 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
2635 - obj = yaffs_InodeToObject(inode);
2638 - yaffs_GrossLock(dev);
2640 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
2641 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
2645 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2646 - d_instantiate(dentry, old_dentry->d_inode);
2647 - atomic_inc(&old_dentry->d_inode->i_count);
2649 - ("yaffs_link link count %d i_count %d\n",
2650 - old_dentry->d_inode->i_nlink,
2651 - atomic_read(&old_dentry->d_inode->i_count)));
2654 - yaffs_GrossUnlock(dev);
2662 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
2663 - const char *symname)
2665 - yaffs_Object *obj;
2666 - yaffs_Device *dev;
2667 - uid_t uid = YCRED(current)->fsuid;
2668 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2670 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
2672 - dev = yaffs_InodeToObject(dir)->myDev;
2673 - yaffs_GrossLock(dev);
2674 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
2675 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
2676 - yaffs_GrossUnlock(dev);
2679 - struct inode *inode;
2681 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2682 - d_instantiate(dentry, inode);
2683 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
2686 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
2692 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
2696 - yaffs_Object *obj;
2697 - yaffs_Device *dev;
2699 - obj = yaffs_DentryToObject(dentry);
2703 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
2704 - yaffs_GrossLock(dev);
2705 - yaffs_FlushFile(obj, 1);
2706 - yaffs_GrossUnlock(dev);
2711 - * The VFS layer already does all the dentry stuff for rename.
2713 - * NB: POSIX says you can rename an object over an old object of the same name
2715 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
2716 - struct inode *new_dir, struct dentry *new_dentry)
2718 - yaffs_Device *dev;
2719 - int retVal = YAFFS_FAIL;
2720 - yaffs_Object *target;
2722 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
2723 - dev = yaffs_InodeToObject(old_dir)->myDev;
2725 - yaffs_GrossLock(dev);
2727 - /* Check if the target is an existing directory that is not empty. */
2728 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
2729 - new_dentry->d_name.name);
2733 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
2734 - !ylist_empty(&target->variant.directoryVariant.children)) {
2736 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
2738 - retVal = YAFFS_FAIL;
2740 - /* Now does unlinking internally using shadowing mechanism */
2741 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
2743 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
2744 - old_dentry->d_name.name,
2745 - yaffs_InodeToObject(new_dir),
2746 - new_dentry->d_name.name);
2748 - yaffs_GrossUnlock(dev);
2750 - if (retVal == YAFFS_OK) {
2752 - new_dentry->d_inode->i_nlink--;
2753 - mark_inode_dirty(new_dentry->d_inode);
2758 - return -ENOTEMPTY;
2762 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
2764 - struct inode *inode = dentry->d_inode;
2766 - yaffs_Device *dev;
2769 - ("yaffs_setattr of object %d\n",
2770 - yaffs_InodeToObject(inode)->objectId));
2772 - error = inode_change_ok(inode, attr);
2774 - dev = yaffs_InodeToObject(inode)->myDev;
2775 - yaffs_GrossLock(dev);
2776 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
2782 - yaffs_GrossUnlock(dev);
2784 - error = inode_setattr(inode, attr);
2789 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2790 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
2792 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2793 - struct super_block *sb = dentry->d_sb;
2794 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2795 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
2797 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2799 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
2801 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2804 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
2806 - yaffs_GrossLock(dev);
2808 - buf->f_type = YAFFS_MAGIC;
2809 - buf->f_bsize = sb->s_blocksize;
2810 - buf->f_namelen = 255;
2812 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
2813 - /* Do this if chunk size is not a power of 2 */
2815 - uint64_t bytesInDev;
2816 - uint64_t bytesFree;
2818 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
2819 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
2821 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
2822 - buf->f_blocks = bytesInDev;
2824 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
2825 - ((uint64_t)(dev->nDataBytesPerChunk));
2827 - do_div(bytesFree, sb->s_blocksize);
2829 - buf->f_bfree = bytesFree;
2831 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
2834 - (dev->endBlock - dev->startBlock + 1) *
2835 - dev->nChunksPerBlock /
2836 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2838 - yaffs_GetNumberOfFreeChunks(dev) /
2839 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2842 - (dev->endBlock - dev->startBlock + 1) *
2843 - dev->nChunksPerBlock *
2844 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2847 - yaffs_GetNumberOfFreeChunks(dev) *
2848 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2853 - buf->f_bavail = buf->f_bfree;
2855 - yaffs_GrossUnlock(dev);
2860 -static int yaffs_do_sync_fs(struct super_block *sb)
2863 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2864 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
2867 - yaffs_GrossLock(dev);
2870 - yaffs_FlushEntireDeviceCache(dev);
2871 - yaffs_CheckpointSave(dev);
2874 - yaffs_GrossUnlock(dev);
2882 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2883 -static void yaffs_write_super(struct super_block *sb)
2885 -static int yaffs_write_super(struct super_block *sb)
2889 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
2890 - if (yaffs_auto_checkpoint >= 2)
2891 - yaffs_do_sync_fs(sb);
2892 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
2898 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2899 -static int yaffs_sync_fs(struct super_block *sb, int wait)
2901 -static int yaffs_sync_fs(struct super_block *sb)
2904 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
2906 - if (yaffs_auto_checkpoint >= 1)
2907 - yaffs_do_sync_fs(sb);
2912 -#ifdef YAFFS_USE_OWN_IGET
2914 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
2916 - struct inode *inode;
2917 - yaffs_Object *obj;
2918 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2921 - ("yaffs_iget for %lu\n", ino));
2923 - inode = iget_locked(sb, ino);
2925 - return ERR_PTR(-ENOMEM);
2926 - if (!(inode->i_state & I_NEW))
2929 - /* NB This is called as a side effect of other functions, but
2930 - * we had to release the lock to prevent deadlocks, so
2931 - * need to lock again.
2934 - yaffs_GrossLock(dev);
2936 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2938 - yaffs_FillInodeFromObject(inode, obj);
2940 - yaffs_GrossUnlock(dev);
2942 - unlock_new_inode(inode);
2948 -static void yaffs_read_inode(struct inode *inode)
2950 - /* NB This is called as a side effect of other functions, but
2951 - * we had to release the lock to prevent deadlocks, so
2952 - * need to lock again.
2955 - yaffs_Object *obj;
2956 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
2959 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
2961 - yaffs_GrossLock(dev);
2963 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2965 - yaffs_FillInodeFromObject(inode, obj);
2967 - yaffs_GrossUnlock(dev);
2972 -static YLIST_HEAD(yaffs_dev_list);
2974 -#if 0 /* not used */
2975 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
2977 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2979 - if (*flags & MS_RDONLY) {
2980 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
2983 - ("yaffs_remount_fs: %s: RO\n", dev->name));
2985 - yaffs_GrossLock(dev);
2987 - yaffs_FlushEntireDeviceCache(dev);
2989 - yaffs_CheckpointSave(dev);
2994 - yaffs_GrossUnlock(dev);
2997 - ("yaffs_remount_fs: %s: RW\n", dev->name));
3004 -static void yaffs_put_super(struct super_block *sb)
3006 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3008 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3010 - yaffs_GrossLock(dev);
3012 - yaffs_FlushEntireDeviceCache(dev);
3014 - yaffs_CheckpointSave(dev);
3016 - if (dev->putSuperFunc)
3017 - dev->putSuperFunc(sb);
3019 - yaffs_Deinitialise(dev);
3021 - yaffs_GrossUnlock(dev);
3023 - /* we assume this is protected by lock_kernel() in mount/umount */
3024 - ylist_del(&dev->devList);
3026 - if (dev->spareBuffer) {
3027 - YFREE(dev->spareBuffer);
3028 - dev->spareBuffer = NULL;
3035 -static void yaffs_MTDPutSuper(struct super_block *sb)
3037 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3042 - put_mtd_device(mtd);
3046 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3048 - struct super_block *sb = (struct super_block *)vsb;
3050 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3057 - int skip_checkpoint_read;
3058 - int skip_checkpoint_write;
3062 -#define MAX_OPT_LEN 20
3063 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3065 - char cur_opt[MAX_OPT_LEN + 1];
3069 - /* Parse through the options which is a comma seperated list */
3071 - while (options_str && *options_str && !error) {
3072 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3075 - while (*options_str && *options_str != ',') {
3076 - if (p < MAX_OPT_LEN) {
3077 - cur_opt[p] = *options_str;
3083 - if (!strcmp(cur_opt, "inband-tags"))
3084 - options->inband_tags = 1;
3085 - else if (!strcmp(cur_opt, "no-cache"))
3086 - options->no_cache = 1;
3087 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3088 - options->skip_checkpoint_read = 1;
3089 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3090 - options->skip_checkpoint_write = 1;
3091 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3092 - options->skip_checkpoint_read = 1;
3093 - options->skip_checkpoint_write = 1;
3095 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3104 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3105 - struct super_block *sb,
3106 - void *data, int silent)
3109 - struct inode *inode = NULL;
3110 - struct dentry *root;
3111 - yaffs_Device *dev = 0;
3112 - char devname_buf[BDEVNAME_SIZE + 1];
3113 - struct mtd_info *mtd;
3115 - char *data_str = (char *)data;
3117 - yaffs_options options;
3119 - sb->s_magic = YAFFS_MAGIC;
3120 - sb->s_op = &yaffs_super_ops;
3121 - sb->s_flags |= MS_NOATIME;
3124 - printk(KERN_INFO "yaffs: sb is NULL\n");
3125 - else if (!sb->s_dev)
3126 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3127 - else if (!yaffs_devname(sb, devname_buf))
3128 - printk(KERN_INFO "yaffs: devname is NULL\n");
3130 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3132 - yaffs_devname(sb, devname_buf));
3137 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3139 - memset(&options, 0, sizeof(options));
3141 - if (yaffs_parse_options(&options, data_str)) {
3142 - /* Option parsing failed */
3147 - sb->s_blocksize = PAGE_CACHE_SIZE;
3148 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3149 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3151 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3153 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3155 - ("yaffs: Write verification disabled. All guarantees "
3156 - "null and void\n"));
3159 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3161 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3162 - yaffs_devname(sb, devname_buf)));
3164 - /* Check it's an mtd device..... */
3165 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3166 - return NULL; /* This isn't an mtd device */
3168 - /* Get the device */
3169 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3171 - T(YAFFS_TRACE_ALWAYS,
3172 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3173 - MINOR(sb->s_dev)));
3176 - /* Check it's NAND */
3177 - if (mtd->type != MTD_NANDFLASH) {
3178 - T(YAFFS_TRACE_ALWAYS,
3179 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3183 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3184 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3185 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3186 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3187 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3188 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3189 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3190 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3191 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3192 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3193 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3194 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3196 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3199 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3201 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3202 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3206 - /* Added NCB 26/5/2006 for completeness */
3207 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3208 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3214 - if (yaffsVersion == 2) {
3215 - /* Check for version 2 style functions */
3216 - if (!mtd->erase ||
3217 - !mtd->block_isbad ||
3218 - !mtd->block_markbad ||
3221 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3222 - !mtd->read_oob || !mtd->write_oob) {
3224 - !mtd->write_ecc ||
3225 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3227 - T(YAFFS_TRACE_ALWAYS,
3228 - ("yaffs: MTD device does not support required "
3233 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3234 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3235 - !options.inband_tags) {
3236 - T(YAFFS_TRACE_ALWAYS,
3237 - ("yaffs: MTD device does not have the "
3238 - "right page sizes\n"));
3242 - /* Check for V1 style functions */
3243 - if (!mtd->erase ||
3246 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3247 - !mtd->read_oob || !mtd->write_oob) {
3249 - !mtd->write_ecc ||
3250 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3252 - T(YAFFS_TRACE_ALWAYS,
3253 - ("yaffs: MTD device does not support required "
3258 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3259 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3260 - T(YAFFS_TRACE_ALWAYS,
3261 - ("yaffs: MTD device does not support have the "
3262 - "right page sizes\n"));
3267 - /* OK, so if we got here, we have an MTD that's NAND and looks
3268 - * like it has the right capabilities
3269 - * Set the yaffs_Device up for mtd
3272 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3273 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3275 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3278 - /* Deep shit could not allocate device structure */
3279 - T(YAFFS_TRACE_ALWAYS,
3280 - ("yaffs_read_super: Failed trying to allocate "
3281 - "yaffs_Device. \n"));
3285 - memset(dev, 0, sizeof(yaffs_Device));
3286 - dev->genericDevice = mtd;
3287 - dev->name = mtd->name;
3289 - /* Set up the memory size parameters.... */
3291 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3293 - dev->startBlock = 0;
3294 - dev->endBlock = nBlocks - 1;
3295 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3296 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3297 - dev->nReservedBlocks = 5;
3298 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3299 - dev->inbandTags = options.inband_tags;
3301 - /* ... and the functions. */
3302 - if (yaffsVersion == 2) {
3303 - dev->writeChunkWithTagsToNAND =
3304 - nandmtd2_WriteChunkWithTagsToNAND;
3305 - dev->readChunkWithTagsFromNAND =
3306 - nandmtd2_ReadChunkWithTagsFromNAND;
3307 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3308 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3309 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3310 - dev->isYaffs2 = 1;
3311 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3312 - dev->totalBytesPerChunk = mtd->writesize;
3313 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3315 - dev->totalBytesPerChunk = mtd->oobblock;
3316 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3318 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3320 - dev->startBlock = 0;
3321 - dev->endBlock = nBlocks - 1;
3323 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3324 - /* use the MTD interface in yaffs_mtdif1.c */
3325 - dev->writeChunkWithTagsToNAND =
3326 - nandmtd1_WriteChunkWithTagsToNAND;
3327 - dev->readChunkWithTagsFromNAND =
3328 - nandmtd1_ReadChunkWithTagsFromNAND;
3329 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3330 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3332 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3333 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3335 - dev->isYaffs2 = 0;
3337 - /* ... and common functions */
3338 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3339 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3341 - dev->putSuperFunc = yaffs_MTDPutSuper;
3343 - dev->superBlock = (void *)sb;
3344 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3347 -#ifndef CONFIG_YAFFS_DOES_ECC
3348 - dev->useNANDECC = 1;
3351 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3352 - dev->wideTnodesDisabled = 1;
3355 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3356 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3358 - /* we assume this is protected by lock_kernel() in mount/umount */
3359 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3361 - init_MUTEX(&dev->grossLock);
3363 - yaffs_GrossLock(dev);
3365 - err = yaffs_GutsInitialise(dev);
3368 - ("yaffs_read_super: guts initialised %s\n",
3369 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3371 - /* Release lock before yaffs_get_inode() */
3372 - yaffs_GrossUnlock(dev);
3374 - /* Create root inode */
3375 - if (err == YAFFS_OK)
3376 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3382 - inode->i_op = &yaffs_dir_inode_operations;
3383 - inode->i_fop = &yaffs_dir_operations;
3385 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3387 - root = d_alloc_root(inode);
3389 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3395 - sb->s_root = root;
3396 - sb->s_dirt = !dev->isCheckpointed;
3397 - T(YAFFS_TRACE_ALWAYS,
3398 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3400 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3405 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3406 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3409 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3412 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3413 -static int yaffs_read_super(struct file_system_type *fs,
3414 - int flags, const char *dev_name,
3415 - void *data, struct vfsmount *mnt)
3418 - return get_sb_bdev(fs, flags, dev_name, data,
3419 - yaffs_internal_read_super_mtd, mnt);
3422 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3423 - int flags, const char *dev_name,
3427 - return get_sb_bdev(fs, flags, dev_name, data,
3428 - yaffs_internal_read_super_mtd);
3432 -static struct file_system_type yaffs_fs_type = {
3433 - .owner = THIS_MODULE,
3435 - .get_sb = yaffs_read_super,
3436 - .kill_sb = kill_block_super,
3437 - .fs_flags = FS_REQUIRES_DEV,
3440 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3443 - return yaffs_internal_read_super(1, sb, data, silent);
3446 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3451 -#ifdef CONFIG_YAFFS_YAFFS2
3453 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3454 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3457 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3460 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3461 -static int yaffs2_read_super(struct file_system_type *fs,
3462 - int flags, const char *dev_name, void *data,
3463 - struct vfsmount *mnt)
3465 - return get_sb_bdev(fs, flags, dev_name, data,
3466 - yaffs2_internal_read_super_mtd, mnt);
3469 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3470 - int flags, const char *dev_name,
3474 - return get_sb_bdev(fs, flags, dev_name, data,
3475 - yaffs2_internal_read_super_mtd);
3479 -static struct file_system_type yaffs2_fs_type = {
3480 - .owner = THIS_MODULE,
3482 - .get_sb = yaffs2_read_super,
3483 - .kill_sb = kill_block_super,
3484 - .fs_flags = FS_REQUIRES_DEV,
3487 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3488 - void *data, int silent)
3490 - return yaffs_internal_read_super(2, sb, data, silent);
3493 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3497 -#endif /* CONFIG_YAFFS_YAFFS2 */
3499 -static struct proc_dir_entry *my_proc_entry;
3501 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3503 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3504 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3505 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3506 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3507 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3508 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3509 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3510 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3511 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3512 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3513 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3514 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3515 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3516 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3517 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3518 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3519 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3520 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3521 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3522 - buf += sprintf(buf, "passiveGCs......... %d\n",
3523 - dev->passiveGarbageCollections);
3524 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3525 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3526 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3527 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3528 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3529 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3530 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3531 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3532 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3533 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3535 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3536 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3537 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3538 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3543 -static int yaffs_proc_read(char *page,
3545 - off_t offset, int count, int *eof, void *data)
3547 - struct ylist_head *item;
3549 - int step = offset;
3552 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3553 - * We use 'offset' (*ppos) to indicate where we are in devList.
3554 - * This also assumes the user has posted a read buffer large
3555 - * enough to hold the complete output; but that's life in /proc.
3558 - *(int *)start = 1;
3560 - /* Print header first */
3562 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3563 - "\n%s\n%s\n", yaffs_fs_c_version,
3564 - yaffs_guts_c_version);
3567 - /* hold lock_kernel while traversing yaffs_dev_list */
3570 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3571 - ylist_for_each(item, &yaffs_dev_list) {
3572 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3577 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3578 - buf = yaffs_dump_dev(buf, dev);
3583 - return buf - page < count ? buf - page : count;
3587 - * Set the verbosity of the warnings and error messages.
3589 - * Note that the names can only be a..z or _ with the current code.
3594 - unsigned mask_bitfield;
3596 - {"allocate", YAFFS_TRACE_ALLOCATE},
3597 - {"always", YAFFS_TRACE_ALWAYS},
3598 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3599 - {"buffers", YAFFS_TRACE_BUFFERS},
3600 - {"bug", YAFFS_TRACE_BUG},
3601 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
3602 - {"deletion", YAFFS_TRACE_DELETION},
3603 - {"erase", YAFFS_TRACE_ERASE},
3604 - {"error", YAFFS_TRACE_ERROR},
3605 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
3606 - {"gc", YAFFS_TRACE_GC},
3607 - {"mtd", YAFFS_TRACE_MTD},
3608 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
3609 - {"os", YAFFS_TRACE_OS},
3610 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
3611 - {"scan", YAFFS_TRACE_SCAN},
3612 - {"tracing", YAFFS_TRACE_TRACING},
3614 - {"verify", YAFFS_TRACE_VERIFY},
3615 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
3616 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
3617 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
3619 - {"write", YAFFS_TRACE_WRITE},
3620 - {"all", 0xffffffff},
3625 -#define MAX_MASK_NAME_LENGTH 40
3626 -static int yaffs_proc_write(struct file *file, const char *buf,
3627 - unsigned long count, void *data)
3629 - unsigned rg = 0, mask_bitfield;
3633 - char substring[MAX_MASK_NAME_LENGTH + 1];
3639 - rg = yaffs_traceMask;
3641 - while (!done && (pos < count)) {
3643 - while ((pos < count) && isspace(buf[pos]))
3646 - switch (buf[pos]) {
3660 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
3662 - if (end > buf + pos) {
3663 - mask_name = "numeral";
3664 - len = end - (buf + pos);
3668 - for (x = buf + pos, i = 0;
3669 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
3670 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
3671 - substring[i] = *x;
3672 - substring[i] = '\0';
3674 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3675 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
3676 - mask_name = mask_flags[i].mask_name;
3677 - mask_bitfield = mask_flags[i].mask_bitfield;
3684 - if (mask_name != NULL) {
3688 - rg &= ~mask_bitfield;
3691 - rg |= mask_bitfield;
3694 - rg = mask_bitfield;
3697 - rg |= mask_bitfield;
3703 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
3705 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
3707 - if (rg & YAFFS_TRACE_ALWAYS) {
3708 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3710 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
3711 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
3718 -/* Stuff to handle installation of file systems */
3719 -struct file_system_to_install {
3720 - struct file_system_type *fst;
3724 -static struct file_system_to_install fs_to_install[] = {
3725 - {&yaffs_fs_type, 0},
3726 - {&yaffs2_fs_type, 0},
3730 -static int __init init_yaffs_fs(void)
3733 - struct file_system_to_install *fsinst;
3735 - T(YAFFS_TRACE_ALWAYS,
3736 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
3738 - /* Install the proc_fs entry */
3739 - my_proc_entry = create_proc_entry("yaffs",
3740 - S_IRUGO | S_IFREG,
3743 - if (my_proc_entry) {
3744 - my_proc_entry->write_proc = yaffs_proc_write;
3745 - my_proc_entry->read_proc = yaffs_proc_read;
3746 - my_proc_entry->data = NULL;
3750 - /* Now add the file system entries */
3752 - fsinst = fs_to_install;
3754 - while (fsinst->fst && !error) {
3755 - error = register_filesystem(fsinst->fst);
3757 - fsinst->installed = 1;
3761 - /* Any errors? uninstall */
3763 - fsinst = fs_to_install;
3765 - while (fsinst->fst) {
3766 - if (fsinst->installed) {
3767 - unregister_filesystem(fsinst->fst);
3768 - fsinst->installed = 0;
3777 -static void __exit exit_yaffs_fs(void)
3780 - struct file_system_to_install *fsinst;
3782 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
3783 - " removing. \n"));
3785 - remove_proc_entry("yaffs", YPROC_ROOT);
3787 - fsinst = fs_to_install;
3789 - while (fsinst->fst) {
3790 - if (fsinst->installed) {
3791 - unregister_filesystem(fsinst->fst);
3792 - fsinst->installed = 0;
3798 -module_init(init_yaffs_fs)
3799 -module_exit(exit_yaffs_fs)
3801 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
3802 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
3803 -MODULE_LICENSE("GPL");
3804 --- a/fs/yaffs2/yaffs_getblockinfo.h
3805 +++ b/fs/yaffs2/yaffs_getblockinfo.h
3808 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3810 - * Copyright (C) 2002-2007 Aleph One Ltd.
3811 + * Copyright (C) 2002-2010 Aleph One Ltd.
3812 * for Toby Churchill Ltd and Brightstar Engineering
3814 * Created by Charles Manning <charles@aleph1.co.uk>
3816 #define __YAFFS_GETBLOCKINFO_H__
3818 #include "yaffs_guts.h"
3819 +#include "yaffs_trace.h"
3821 /* Function to manipulate block info */
3822 static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
3823 --- a/fs/yaffs2/yaffs_guts.c
3824 +++ b/fs/yaffs2/yaffs_guts.c
3827 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3829 - * Copyright (C) 2002-2007 Aleph One Ltd.
3830 + * Copyright (C) 2002-2010 Aleph One Ltd.
3831 * for Toby Churchill Ltd and Brightstar Engineering
3833 * Created by Charles Manning <charles@aleph1.co.uk>
3835 * it under the terms of the GNU General Public License version 2 as
3836 * published by the Free Software Foundation.
3839 -const char *yaffs_guts_c_version =
3840 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
3842 #include "yportenv.h"
3843 +#include "yaffs_trace.h"
3845 #include "yaffsinterface.h"
3846 #include "yaffs_guts.h"
3847 @@ -22,22 +19,28 @@ const char *yaffs_guts_c_version =
3848 #include "yaffs_getblockinfo.h"
3850 #include "yaffs_tagscompat.h"
3851 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
3852 -#include "yaffs_qsort.h"
3855 #include "yaffs_nand.h"
3857 -#include "yaffs_checkptrw.h"
3858 +#include "yaffs_yaffs1.h"
3859 +#include "yaffs_yaffs2.h"
3860 +#include "yaffs_bitmap.h"
3861 +#include "yaffs_verify.h"
3863 #include "yaffs_nand.h"
3864 #include "yaffs_packedtags2.h"
3866 +#include "yaffs_nameval.h"
3867 +#include "yaffs_allocator.h"
3869 -#define YAFFS_PASSIVE_GC_CHUNKS 2
3870 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
3871 +#define YAFFS_GC_GOOD_ENOUGH 2
3872 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
3874 #include "yaffs_ecc.h"
3878 /* Robustification (if it ever comes about...) */
3879 static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
3880 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
3881 @@ -49,33 +52,26 @@ static void yaffs_HandleUpdateChunk(yaff
3882 const yaffs_ExtendedTags *tags);
3884 /* Other local prototypes */
3885 +static void yaffs_UpdateParent(yaffs_Object *obj);
3886 static int yaffs_UnlinkObject(yaffs_Object *obj);
3887 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
3889 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
3891 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
3893 yaffs_ExtendedTags *tags,
3895 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
3896 - int chunkInNAND, int inScan);
3899 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
3900 yaffs_ObjectType type);
3901 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
3902 - yaffs_Object *obj);
3903 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
3904 - int force, int isShrink, int shadows);
3907 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
3909 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
3910 static int yaffs_CheckStructures(void);
3911 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
3912 - int chunkOffset, int *limit);
3913 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
3915 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
3918 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
3921 @@ -87,30 +83,22 @@ static int yaffs_TagsMatch(const yaffs_E
3922 static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
3923 yaffs_BlockInfo **blockUsedPtr);
3925 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
3927 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
3929 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
3930 -#ifdef YAFFS_PARANOID
3931 -static int yaffs_CheckFileSanity(yaffs_Object *in);
3933 -#define yaffs_CheckFileSanity(in)
3936 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
3937 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
3939 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
3941 static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
3942 yaffs_ExtendedTags *tags);
3944 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
3946 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
3947 - yaffs_FileStructure *fStruct,
3949 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
3952 + yaffs_ExtendedTags *tags);
3955 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
3956 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
3959 /* Function to calculate chunk and offset */
3960 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
3962 static __u32 Shifts(__u32 x)
3969 @@ -203,7 +191,7 @@ static int yaffs_InitialiseTempBuffers(y
3970 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
3971 dev->tempBuffer[i].line = 0; /* not in use */
3972 dev->tempBuffer[i].buffer = buf =
3973 - YMALLOC_DMA(dev->totalBytesPerChunk);
3974 + YMALLOC_DMA(dev->param.totalBytesPerChunk);
3977 return buf ? YAFFS_OK : YAFFS_FAIL;
3978 @@ -286,7 +274,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
3982 - for (i = 0; i < dev->nShortOpCaches; i++) {
3983 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
3984 if (dev->srCache[i].data == buffer)
3987 @@ -299,6374 +287,4183 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
3994 - * Chunk bitmap manipulations
3995 + * Verification code
3998 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
4000 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4001 - T(YAFFS_TRACE_ERROR,
4002 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4006 - return dev->chunkBits +
4007 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4010 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4012 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4013 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4014 - T(YAFFS_TRACE_ERROR,
4015 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4021 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4023 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4025 - memset(blkBits, 0, dev->chunkBitmapStride);
4028 + * Simple hash function. Needs to have a reasonable spread
4031 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4032 +static Y_INLINE int yaffs_HashFunction(int n)
4034 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4036 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4038 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4040 + return n % YAFFS_NOBJECT_BUCKETS;
4043 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4045 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4047 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4049 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4052 + * Access functions to useful fake objects.
4053 + * Note that root might have a presence in NAND if permissions are set.
4056 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4057 +yaffs_Object *yaffs_Root(yaffs_Device *dev)
4059 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4060 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4062 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4063 + return dev->rootDir;
4066 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4067 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4069 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4071 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4077 + return dev->lostNFoundDir;
4080 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4082 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4085 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4086 - __u8 x = *blkBits;
4099 - * Verification code
4100 + * Erased NAND checking functions
4103 -static int yaffs_SkipVerification(yaffs_Device *dev)
4105 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4108 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4110 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4113 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4114 +int yaffs_CheckFF(__u8 *buffer, int nBytes)
4116 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4117 + /* Horrible, slow implementation */
4118 + while (nBytes--) {
4119 + if (*buffer != 0xFF)
4126 -static const char *blockStateName[] = {
4139 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4140 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4145 + int retval = YAFFS_OK;
4146 + __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4147 + yaffs_ExtendedTags tags;
4150 - if (yaffs_SkipVerification(dev))
4152 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4154 - /* Report illegal runtime states */
4155 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4156 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4157 + if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4158 + retval = YAFFS_FAIL;
4160 - switch (bi->blockState) {
4161 - case YAFFS_BLOCK_STATE_UNKNOWN:
4162 - case YAFFS_BLOCK_STATE_SCANNING:
4163 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4164 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4165 - n, blockStateName[bi->blockState]));
4166 + if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4167 + T(YAFFS_TRACE_NANDACCESS,
4168 + (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
4169 + retval = YAFFS_FAIL;
4172 - /* Check pages in use and soft deletions are legal */
4174 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4176 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4177 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4178 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4179 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4180 - n, bi->pagesInUse, bi->softDeletions));
4182 + yaffs_ReleaseTempBuffer(dev, data, __LINE__);
4184 - /* Check chunk bitmap legal */
4185 - inUse = yaffs_CountChunkBits(dev, n);
4186 - if (inUse != bi->pagesInUse)
4187 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4188 - n, bi->pagesInUse, inUse));
4191 - /* Check that the sequence number is valid.
4192 - * Ten million is legal, but is very unlikely
4194 - if (dev->isYaffs2 &&
4195 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4196 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4197 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4198 - n, bi->sequenceNumber));
4201 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4204 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
4207 + yaffs_ExtendedTags *tags)
4209 - yaffs_VerifyBlock(dev, bi, n);
4210 + int retval = YAFFS_OK;
4211 + yaffs_ExtendedTags tempTags;
4212 + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
4215 + result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
4216 + if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
4217 + tempTags.objectId != tags->objectId ||
4218 + tempTags.chunkId != tags->chunkId ||
4219 + tempTags.byteCount != tags->byteCount)
4220 + retval = YAFFS_FAIL;
4222 - /* After collection the block should be in the erased state */
4223 - /* This will need to change if we do partial gc */
4224 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4226 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4227 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4228 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4229 - n, bi->blockState));
4234 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4235 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
4237 + yaffs_ExtendedTags *tags,
4241 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4242 - int nIllegalBlockStates = 0;
4244 - if (yaffs_SkipVerification(dev))
4247 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4249 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4250 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4251 - yaffs_VerifyBlock(dev, bi, i);
4253 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4254 - nBlocksPerState[bi->blockState]++;
4256 - nIllegalBlockStates++;
4262 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4263 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4264 + yaffs2_InvalidateCheckpoint(dev);
4266 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4267 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4268 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4270 + yaffs_BlockInfo *bi = 0;
4273 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4274 - T(YAFFS_TRACE_VERIFY,
4275 - (TSTR("%s %d blocks"TENDSTR),
4276 - blockStateName[i], nBlocksPerState[i]));
4277 + chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
4283 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4284 - T(YAFFS_TRACE_VERIFY,
4285 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4286 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4287 + /* First check this chunk is erased, if it needs
4288 + * checking. The checking policy (unless forced
4289 + * always on) is as follows:
4291 + * Check the first page we try to write in a block.
4292 + * If the check passes then we don't need to check any
4293 + * more. If the check fails, we check again...
4294 + * If the block has been erased, we don't need to check.
4296 + * However, if the block has been prioritised for gc,
4297 + * then we think there might be something odd about
4298 + * this block and stop using it.
4300 + * Rationale: We should only ever see chunks that have
4301 + * not been erased if there was a partially written
4302 + * chunk due to power loss. This checking policy should
4303 + * catch that case with very few checks and thus save a
4304 + * lot of checks that are most likely not needed.
4306 + * Mods to the above
4307 + * If an erase check fails or the write fails we skip the
4308 + * rest of the block.
4311 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4312 - T(YAFFS_TRACE_VERIFY,
4313 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4314 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4315 + /* let's give it a try */
4318 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4319 - T(YAFFS_TRACE_VERIFY,
4320 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4321 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4322 + if(dev->param.alwaysCheckErased)
4323 + bi->skipErasedCheck = 0;
4325 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4326 + if (!bi->skipErasedCheck) {
4327 + erasedOk = yaffs_CheckChunkErased(dev, chunk);
4328 + if (erasedOk != YAFFS_OK) {
4329 + T(YAFFS_TRACE_ERROR,
4330 + (TSTR("**>> yaffs chunk %d was not erased"
4331 + TENDSTR), chunk));
4334 + /* If not erased, delete this one,
4335 + * skip rest of block and
4336 + * try another chunk */
4337 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4338 + yaffs_SkipRestOfBlock(dev);
4344 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4345 - * case those tests will not be performed.
4347 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4349 - if (obj && yaffs_SkipVerification(obj->myDev))
4351 + writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
4354 - if (!(tags && obj && oh)) {
4355 - T(YAFFS_TRACE_VERIFY,
4356 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4357 - (__u32)tags, (__u32)obj, (__u32)oh));
4360 + if(!bi->skipErasedCheck)
4361 + writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
4363 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4364 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4365 - T(YAFFS_TRACE_VERIFY,
4366 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4367 - tags->objectId, oh->type));
4368 + if (writeOk != YAFFS_OK) {
4369 + /* Clean up aborted write, skip to next block and
4370 + * try another chunk */
4371 + yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
4375 - if (tags->objectId != obj->objectId)
4376 - T(YAFFS_TRACE_VERIFY,
4377 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4378 - tags->objectId, obj->objectId));
4379 + bi->skipErasedCheck = 1;
4381 + /* Copy the data into the robustification buffer */
4382 + yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
4385 - * Check that the object's parent ids match if parentCheck requested.
4387 - * Tests do not apply to the root object.
4389 + } while (writeOk != YAFFS_OK &&
4390 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4392 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4393 - T(YAFFS_TRACE_VERIFY,
4394 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4395 - tags->objectId, oh->parentObjectId));
4399 - if (parentCheck && obj->parent &&
4400 - oh->parentObjectId != obj->parent->objectId &&
4401 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
4402 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
4403 - T(YAFFS_TRACE_VERIFY,
4404 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
4405 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
4406 + if (attempts > 1) {
4407 + T(YAFFS_TRACE_ERROR,
4408 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
4411 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
4412 - T(YAFFS_TRACE_VERIFY,
4413 - (TSTR("Obj %d header name is NULL"TENDSTR),
4415 + dev->nRetriedWrites += (attempts - 1);
4418 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
4419 - T(YAFFS_TRACE_VERIFY,
4420 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
4428 + * Block retiring for handling a broken block.
4431 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
4432 - __u32 level, int chunkOffset)
4433 +static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
4436 - yaffs_Device *dev = obj->myDev;
4438 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4442 + yaffs2_InvalidateCheckpoint(dev);
4444 + yaffs2_ClearOldestDirtySequence(dev,bi);
4446 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
4447 - if (tn->internal[i]) {
4448 - ok = yaffs_VerifyTnodeWorker(obj,
4451 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
4454 - } else if (level == 0) {
4455 + if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
4456 + if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
4457 + T(YAFFS_TRACE_ALWAYS, (TSTR(
4458 + "yaffs: Failed to mark bad and erase block %d"
4459 + TENDSTR), blockInNAND));
4461 yaffs_ExtendedTags tags;
4462 - __u32 objectId = obj->objectId;
4463 + int chunkId = blockInNAND * dev->param.nChunksPerBlock;
4465 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
4466 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4468 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
4469 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4470 + memset(buffer, 0xff, dev->nDataBytesPerChunk);
4471 + yaffs_InitialiseTags(&tags);
4472 + tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
4473 + if (dev->param.writeChunkWithTagsToNAND(dev, chunkId -
4474 + dev->chunkOffset, buffer, &tags) != YAFFS_OK)
4475 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
4476 + TCONT("write bad block marker to block %d")
4477 + TENDSTR), blockInNAND));
4479 - if (theChunk > 0) {
4480 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
4481 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4482 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
4483 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4484 - objectId, chunkOffset, theChunk,
4485 - tags.objectId, tags.chunkId));
4490 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4495 + bi->blockState = YAFFS_BLOCK_STATE_DEAD;
4496 + bi->gcPrioritise = 0;
4497 + bi->needsRetiring = 0;
4499 + dev->nRetiredBlocks++;
4503 + * Functions for robustisizing TODO
4507 -static void yaffs_VerifyFile(yaffs_Object *obj)
4508 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4510 + const yaffs_ExtendedTags *tags)
4512 - int requiredTallness;
4513 - int actualTallness;
4517 - yaffs_Device *dev;
4518 - yaffs_ExtendedTags tags;
4522 + chunkInNAND=chunkInNAND;
4529 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4530 + const yaffs_ExtendedTags *tags)
4533 + chunkInNAND=chunkInNAND;
4537 - if (yaffs_SkipVerification(obj->myDev))
4539 +void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
4541 + if (!bi->gcPrioritise) {
4542 + bi->gcPrioritise = 1;
4543 + dev->hasPendingPrioritisedGCs = 1;
4544 + bi->chunkErrorStrikes++;
4547 - objectId = obj->objectId;
4548 + if (bi->chunkErrorStrikes > 3) {
4549 + bi->needsRetiring = 1; /* Too many stikes, so retire this */
4550 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
4552 - /* Check file size is consistent with tnode depth */
4553 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
4554 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
4555 - requiredTallness = 0;
4557 - x >>= YAFFS_TNODES_INTERNAL_BITS;
4558 - requiredTallness++;
4563 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4566 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
4567 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4569 - actualTallness = obj->variant.fileVariant.topLevel;
4570 + yaffs_HandleChunkError(dev, bi);
4572 - if (requiredTallness > actualTallness)
4573 - T(YAFFS_TRACE_VERIFY,
4574 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
4575 - obj->objectId, actualTallness, requiredTallness));
4577 + /* Was an actual write failure, so mark the block for retirement */
4578 + bi->needsRetiring = 1;
4579 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4580 + (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
4583 + /* Delete the chunk */
4584 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
4585 + yaffs_SkipRestOfBlock(dev);
4589 - /* Check that the chunks in the tnode tree are all correct.
4590 - * We do this by scanning through the tnode tree and
4591 - * checking the tags for every chunk match.
4593 +/*---------------- Name handling functions ------------*/
4595 - if (yaffs_SkipNANDVerification(dev))
4597 +static __u16 yaffs_CalcNameSum(const YCHAR *name)
4602 - for (i = 1; i <= lastChunk; i++) {
4603 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
4604 + const YUCHAR *bname = (const YUCHAR *) name;
4606 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
4609 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4610 - if (theChunk > 0) {
4611 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
4612 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4613 - if (tags.objectId != objectId || tags.chunkId != i) {
4614 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4615 - objectId, i, theChunk,
4616 - tags.objectId, tags.chunkId));
4619 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4620 + sum += yaffs_toupper(*bname) * i;
4622 + sum += (*bname) * i;
4632 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
4633 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
4635 - if (obj && yaffs_SkipVerification(obj->myDev))
4637 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
4638 + memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
4639 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
4640 + yaffs_strcpy(obj->shortName, name);
4642 + obj->shortName[0] = _Y('\0');
4644 + obj->sum = yaffs_CalcNameSum(name);
4647 - /* Verify sane equivalent object */
4648 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
4650 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
4651 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
4652 + memset(tmpName,0,sizeof(tmpName));
4653 + yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
4654 + yaffs_SetObjectName(obj,tmpName);
4656 + yaffs_SetObjectName(obj,oh->name);
4660 -static void yaffs_VerifySymlink(yaffs_Object *obj)
4661 +/*-------------------- TNODES -------------------
4663 + * List of spare tnodes
4664 + * The list is hooked together using the first pointer
4669 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
4671 - if (obj && yaffs_SkipVerification(obj->myDev))
4673 + yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev);
4675 + memset(tn, 0, dev->tnodeSize);
4679 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4681 - /* Verify symlink string */
4685 -static void yaffs_VerifySpecial(yaffs_Object *obj)
4686 +/* FreeTnode frees up a tnode and puts it back on the free list */
4687 +static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
4689 - if (obj && yaffs_SkipVerification(obj->myDev))
4691 + yaffs_FreeRawTnode(dev,tn);
4693 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4696 -static void yaffs_VerifyObject(yaffs_Object *obj)
4697 +static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev)
4699 - yaffs_Device *dev;
4705 - __u32 chunkInRange;
4706 - __u32 chunkShouldNotBeDeleted;
4711 + yaffs_DeinitialiseRawTnodesAndObjects(dev);
4712 + dev->nObjects = 0;
4716 - if (obj->beingCreated)
4720 +void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
4723 + __u32 *map = (__u32 *)tn;
4729 - if (yaffs_SkipVerification(dev))
4731 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4732 + val >>= dev->chunkGroupBits;
4734 - /* Check sane object header chunk */
4735 + bitInMap = pos * dev->tnodeWidth;
4736 + wordInMap = bitInMap / 32;
4737 + bitInWord = bitInMap & (32 - 1);
4739 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
4740 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
4741 + mask = dev->tnodeMask << bitInWord;
4743 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
4744 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
4745 - chunkValid = chunkInRange &&
4746 - yaffs_CheckChunkBit(dev,
4747 - obj->hdrChunk / dev->nChunksPerBlock,
4748 - obj->hdrChunk % dev->nChunksPerBlock);
4749 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
4750 + map[wordInMap] &= ~mask;
4751 + map[wordInMap] |= (mask & (val << bitInWord));
4754 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
4755 - T(YAFFS_TRACE_VERIFY,
4756 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
4757 - obj->objectId, obj->hdrChunk,
4758 - chunkIdOk ? "" : ",out of range",
4759 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
4760 + if (dev->tnodeWidth > (32 - bitInWord)) {
4761 + bitInWord = (32 - bitInWord);
4763 + mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
4764 + map[wordInMap] &= ~mask;
4765 + map[wordInMap] |= (mask & (val >> bitInWord));
4769 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
4770 - yaffs_ExtendedTags tags;
4771 - yaffs_ObjectHeader *oh;
4772 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4774 - oh = (yaffs_ObjectHeader *)buffer;
4775 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4778 + __u32 *map = (__u32 *)tn;
4784 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
4786 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4788 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
4789 + bitInMap = pos * dev->tnodeWidth;
4790 + wordInMap = bitInMap / 32;
4791 + bitInWord = bitInMap & (32 - 1);
4793 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4795 + val = map[wordInMap] >> bitInWord;
4797 - /* Verify it has a parent */
4798 - if (obj && !obj->fake &&
4799 - (!obj->parent || obj->parent->myDev != dev)) {
4800 - T(YAFFS_TRACE_VERIFY,
4801 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
4802 - obj->objectId, obj->parent));
4803 + if (dev->tnodeWidth > (32 - bitInWord)) {
4804 + bitInWord = (32 - bitInWord);
4806 + val |= (map[wordInMap] << bitInWord);
4809 - /* Verify parent is a directory */
4810 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
4811 - T(YAFFS_TRACE_VERIFY,
4812 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
4813 - obj->objectId, obj->parent->variantType));
4815 + val &= dev->tnodeMask;
4816 + val <<= dev->chunkGroupBits;
4818 - switch (obj->variantType) {
4819 - case YAFFS_OBJECT_TYPE_FILE:
4820 - yaffs_VerifyFile(obj);
4822 - case YAFFS_OBJECT_TYPE_SYMLINK:
4823 - yaffs_VerifySymlink(obj);
4825 - case YAFFS_OBJECT_TYPE_DIRECTORY:
4826 - yaffs_VerifyDirectory(obj);
4828 - case YAFFS_OBJECT_TYPE_HARDLINK:
4829 - yaffs_VerifyHardLink(obj);
4831 - case YAFFS_OBJECT_TYPE_SPECIAL:
4832 - yaffs_VerifySpecial(obj);
4834 - case YAFFS_OBJECT_TYPE_UNKNOWN:
4836 - T(YAFFS_TRACE_VERIFY,
4837 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
4838 - obj->objectId, obj->variantType));
4844 -static void yaffs_VerifyObjects(yaffs_Device *dev)
4845 +/* ------------------- End of individual tnode manipulation -----------------*/
4847 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
4848 + * The look up tree is represented by the top tnode and the number of topLevel
4849 + * in the tree. 0 means only the level 0 tnode is in the tree.
4852 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
4853 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4854 + yaffs_FileStructure *fStruct,
4857 - yaffs_Object *obj;
4859 - struct ylist_head *lh;
4860 + yaffs_Tnode *tn = fStruct->top;
4862 + int requiredTallness;
4863 + int level = fStruct->topLevel;
4865 - if (yaffs_SkipVerification(dev))
4869 - /* Iterate through the objects in each hash entry */
4870 + /* Check sane level and chunk Id */
4871 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
4874 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
4875 - ylist_for_each(lh, &dev->objectBucket[i].list) {
4877 - obj = ylist_entry(lh, yaffs_Object, hashLink);
4878 - yaffs_VerifyObject(obj);
4881 + if (chunkId > YAFFS_MAX_CHUNK_ID)
4884 + /* First check we're tall enough (ie enough topLevel) */
4886 + i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
4887 + requiredTallness = 0;
4889 + i >>= YAFFS_TNODES_INTERNAL_BITS;
4890 + requiredTallness++;
4894 + if (requiredTallness > fStruct->topLevel)
4895 + return NULL; /* Not tall enough, so we can't find it */
4898 - * Simple hash function. Needs to have a reasonable spread
4900 + /* Traverse down to level 0 */
4901 + while (level > 0 && tn) {
4902 + tn = tn->internal[(chunkId >>
4903 + (YAFFS_TNODES_LEVEL0_BITS +
4905 + YAFFS_TNODES_INTERNAL_BITS)) &
4906 + YAFFS_TNODES_INTERNAL_MASK];
4910 -static Y_INLINE int yaffs_HashFunction(int n)
4913 - return n % YAFFS_NOBJECT_BUCKETS;
4918 - * Access functions to useful fake objects.
4919 - * Note that root might have a presence in NAND if permissions are set.
4920 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
4921 + * This happens in two steps:
4922 + * 1. If the tree isn't tall enough, then make it taller.
4923 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
4925 + * Used when modifying the tree.
4927 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
4928 + * be plugged into the ttree.
4931 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
4932 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
4933 + yaffs_FileStructure *fStruct,
4935 + yaffs_Tnode *passedTn)
4937 - return dev->rootDir;
4939 + int requiredTallness;
4944 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4946 - return dev->lostNFoundDir;
4952 - * Erased NAND checking functions
4954 + /* Check sane level and page Id */
4955 + if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
4958 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
4960 - /* Horrible, slow implementation */
4961 - while (nBytes--) {
4962 - if (*buffer != 0xFF)
4969 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4972 - int retval = YAFFS_OK;
4973 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4974 - yaffs_ExtendedTags tags;
4977 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4979 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4980 - retval = YAFFS_FAIL;
4982 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4983 - T(YAFFS_TRACE_NANDACCESS,
4984 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
4985 - retval = YAFFS_FAIL;
4988 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
4994 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
4996 - yaffs_ExtendedTags *tags,
5003 - yaffs_InvalidateCheckpoint(dev);
5006 - yaffs_BlockInfo *bi = 0;
5009 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5015 - /* First check this chunk is erased, if it needs
5016 - * checking. The checking policy (unless forced
5017 - * always on) is as follows:
5019 - * Check the first page we try to write in a block.
5020 - * If the check passes then we don't need to check any
5021 - * more. If the check fails, we check again...
5022 - * If the block has been erased, we don't need to check.
5024 - * However, if the block has been prioritised for gc,
5025 - * then we think there might be something odd about
5026 - * this block and stop using it.
5028 - * Rationale: We should only ever see chunks that have
5029 - * not been erased if there was a partially written
5030 - * chunk due to power loss. This checking policy should
5031 - * catch that case with very few checks and thus save a
5032 - * lot of checks that are most likely not needed.
5034 - if (bi->gcPrioritise) {
5035 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5036 - /* try another chunk */
5040 - /* let's give it a try */
5043 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5044 - bi->skipErasedCheck = 0;
5046 - if (!bi->skipErasedCheck) {
5047 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5048 - if (erasedOk != YAFFS_OK) {
5049 - T(YAFFS_TRACE_ERROR,
5050 - (TSTR("**>> yaffs chunk %d was not erased"
5051 - TENDSTR), chunk));
5053 - /* try another chunk */
5056 - bi->skipErasedCheck = 1;
5059 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5061 - if (writeOk != YAFFS_OK) {
5062 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5063 - /* try another chunk */
5067 - /* Copy the data into the robustification buffer */
5068 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5070 - } while (writeOk != YAFFS_OK &&
5071 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5076 - if (attempts > 1) {
5077 - T(YAFFS_TRACE_ERROR,
5078 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5081 - dev->nRetriedWrites += (attempts - 1);
5088 - * Block retiring for handling a broken block.
5091 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5093 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5095 - yaffs_InvalidateCheckpoint(dev);
5097 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5098 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5099 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5100 - "yaffs: Failed to mark bad and erase block %d"
5101 - TENDSTR), blockInNAND));
5103 - yaffs_ExtendedTags tags;
5104 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5106 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5108 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5109 - yaffs_InitialiseTags(&tags);
5110 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5111 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5112 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5113 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5114 - TCONT("write bad block marker to block %d")
5115 - TENDSTR), blockInNAND));
5117 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5121 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5122 - bi->gcPrioritise = 0;
5123 - bi->needsRetiring = 0;
5125 - dev->nRetiredBlocks++;
5129 - * Functions for robustisizing TODO
5133 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5135 - const yaffs_ExtendedTags *tags)
5139 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5140 - const yaffs_ExtendedTags *tags)
5144 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5146 - if (!bi->gcPrioritise) {
5147 - bi->gcPrioritise = 1;
5148 - dev->hasPendingPrioritisedGCs = 1;
5149 - bi->chunkErrorStrikes++;
5151 - if (bi->chunkErrorStrikes > 3) {
5152 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5153 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5159 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5162 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5163 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5165 - yaffs_HandleChunkError(dev, bi);
5168 - /* Was an actual write failure, so mark the block for retirement */
5169 - bi->needsRetiring = 1;
5170 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5171 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5174 - /* Delete the chunk */
5175 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5179 -/*---------------- Name handling functions ------------*/
5181 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5186 - const YUCHAR *bname = (const YUCHAR *) name;
5188 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5190 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5191 - sum += yaffs_toupper(*bname) * i;
5193 - sum += (*bname) * i;
5202 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
5204 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5205 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5206 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
5207 - yaffs_strcpy(obj->shortName, name);
5209 - obj->shortName[0] = _Y('\0');
5211 - obj->sum = yaffs_CalcNameSum(name);
5214 -/*-------------------- TNODES -------------------
5216 - * List of spare tnodes
5217 - * The list is hooked together using the first pointer
5221 -/* yaffs_CreateTnodes creates a bunch more tnodes and
5222 - * adds them to the tnode free list.
5223 - * Don't use this function directly
5226 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
5230 - yaffs_Tnode *newTnodes;
5232 - yaffs_Tnode *curr;
5233 - yaffs_Tnode *next;
5234 - yaffs_TnodeList *tnl;
5239 - /* Calculate the tnode size in bytes for variable width tnode support.
5240 - * Must be a multiple of 32-bits */
5241 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5243 - if (tnodeSize < sizeof(yaffs_Tnode))
5244 - tnodeSize = sizeof(yaffs_Tnode);
5246 - /* make these things */
5248 - newTnodes = YMALLOC(nTnodes * tnodeSize);
5249 - mem = (__u8 *)newTnodes;
5252 - T(YAFFS_TRACE_ERROR,
5253 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
5254 - return YAFFS_FAIL;
5257 - /* Hook them into the free list */
5259 - for (i = 0; i < nTnodes - 1; i++) {
5260 - newTnodes[i].internal[0] = &newTnodes[i + 1];
5261 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5262 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5266 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
5267 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5268 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5270 - dev->freeTnodes = newTnodes;
5272 - /* New hookup for wide tnodes */
5273 - for (i = 0; i < nTnodes - 1; i++) {
5274 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
5275 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
5276 - curr->internal[0] = next;
5279 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
5280 - curr->internal[0] = dev->freeTnodes;
5281 - dev->freeTnodes = (yaffs_Tnode *)mem;
5286 - dev->nFreeTnodes += nTnodes;
5287 - dev->nTnodesCreated += nTnodes;
5289 - /* Now add this bunch of tnodes to a list for freeing up.
5290 - * NB If we can't add this to the management list it isn't fatal
5291 - * but it just means we can't free this bunch of tnodes later.
5294 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
5296 - T(YAFFS_TRACE_ERROR,
5298 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
5299 - return YAFFS_FAIL;
5301 - tnl->tnodes = newTnodes;
5302 - tnl->next = dev->allocatedTnodeList;
5303 - dev->allocatedTnodeList = tnl;
5306 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
5311 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
5313 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
5315 - yaffs_Tnode *tn = NULL;
5317 - /* If there are none left make more */
5318 - if (!dev->freeTnodes)
5319 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
5321 - if (dev->freeTnodes) {
5322 - tn = dev->freeTnodes;
5323 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5324 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
5325 - /* Hoosterman, this thing looks like it isn't in the list */
5326 - T(YAFFS_TRACE_ALWAYS,
5327 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
5330 - dev->freeTnodes = dev->freeTnodes->internal[0];
5331 - dev->nFreeTnodes--;
5334 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5339 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
5341 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
5342 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5344 - if (tnodeSize < sizeof(yaffs_Tnode))
5345 - tnodeSize = sizeof(yaffs_Tnode);
5348 - memset(tn, 0, tnodeSize);
5353 -/* FreeTnode frees up a tnode and puts it back on the free list */
5354 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
5357 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5358 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
5359 - /* Hoosterman, this thing looks like it is already in the list */
5360 - T(YAFFS_TRACE_ALWAYS,
5361 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
5363 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5365 - tn->internal[0] = dev->freeTnodes;
5366 - dev->freeTnodes = tn;
5367 - dev->nFreeTnodes++;
5369 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5372 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
5374 - /* Free the list of allocated tnodes */
5375 - yaffs_TnodeList *tmp;
5377 - while (dev->allocatedTnodeList) {
5378 - tmp = dev->allocatedTnodeList->next;
5380 - YFREE(dev->allocatedTnodeList->tnodes);
5381 - YFREE(dev->allocatedTnodeList);
5382 - dev->allocatedTnodeList = tmp;
5386 - dev->freeTnodes = NULL;
5387 - dev->nFreeTnodes = 0;
5390 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
5392 - dev->allocatedTnodeList = NULL;
5393 - dev->freeTnodes = NULL;
5394 - dev->nFreeTnodes = 0;
5395 - dev->nTnodesCreated = 0;
5399 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
5402 - __u32 *map = (__u32 *)tn;
5408 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5409 - val >>= dev->chunkGroupBits;
5411 - bitInMap = pos * dev->tnodeWidth;
5412 - wordInMap = bitInMap / 32;
5413 - bitInWord = bitInMap & (32 - 1);
5415 - mask = dev->tnodeMask << bitInWord;
5417 - map[wordInMap] &= ~mask;
5418 - map[wordInMap] |= (mask & (val << bitInWord));
5420 - if (dev->tnodeWidth > (32 - bitInWord)) {
5421 - bitInWord = (32 - bitInWord);
5423 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
5424 - map[wordInMap] &= ~mask;
5425 - map[wordInMap] |= (mask & (val >> bitInWord));
5429 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
5432 - __u32 *map = (__u32 *)tn;
5438 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5440 - bitInMap = pos * dev->tnodeWidth;
5441 - wordInMap = bitInMap / 32;
5442 - bitInWord = bitInMap & (32 - 1);
5444 - val = map[wordInMap] >> bitInWord;
5446 - if (dev->tnodeWidth > (32 - bitInWord)) {
5447 - bitInWord = (32 - bitInWord);
5449 - val |= (map[wordInMap] << bitInWord);
5452 - val &= dev->tnodeMask;
5453 - val <<= dev->chunkGroupBits;
5458 -/* ------------------- End of individual tnode manipulation -----------------*/
5460 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5461 - * The look up tree is represented by the top tnode and the number of topLevel
5462 - * in the tree. 0 means only the level 0 tnode is in the tree.
5465 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5466 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
5467 - yaffs_FileStructure *fStruct,
5470 - yaffs_Tnode *tn = fStruct->top;
5472 - int requiredTallness;
5473 - int level = fStruct->topLevel;
5475 - /* Check sane level and chunk Id */
5476 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5479 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5482 - /* First check we're tall enough (ie enough topLevel) */
5484 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5485 - requiredTallness = 0;
5487 - i >>= YAFFS_TNODES_INTERNAL_BITS;
5488 - requiredTallness++;
5491 - if (requiredTallness > fStruct->topLevel)
5492 - return NULL; /* Not tall enough, so we can't find it */
5494 - /* Traverse down to level 0 */
5495 - while (level > 0 && tn) {
5496 - tn = tn->internal[(chunkId >>
5497 - (YAFFS_TNODES_LEVEL0_BITS +
5499 - YAFFS_TNODES_INTERNAL_BITS)) &
5500 - YAFFS_TNODES_INTERNAL_MASK];
5507 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5508 - * This happens in two steps:
5509 - * 1. If the tree isn't tall enough, then make it taller.
5510 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5512 - * Used when modifying the tree.
5514 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5515 - * be plugged into the ttree.
5518 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
5519 - yaffs_FileStructure *fStruct,
5521 - yaffs_Tnode *passedTn)
5523 - int requiredTallness;
5531 - /* Check sane level and page Id */
5532 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
5535 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5538 - /* First check we're tall enough (ie enough topLevel) */
5540 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5541 - requiredTallness = 0;
5543 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5544 - requiredTallness++;
5548 - if (requiredTallness > fStruct->topLevel) {
5549 - /* Not tall enough, gotta make the tree taller */
5550 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
5552 - tn = yaffs_GetTnode(dev);
5555 - tn->internal[0] = fStruct->top;
5556 - fStruct->top = tn;
5558 - T(YAFFS_TRACE_ERROR,
5559 - (TSTR("yaffs: no more tnodes" TENDSTR)));
5563 - fStruct->topLevel = requiredTallness;
5566 - /* Traverse down to level 0, adding anything we need */
5568 - l = fStruct->topLevel;
5569 - tn = fStruct->top;
5572 - while (l > 0 && tn) {
5574 - (YAFFS_TNODES_LEVEL0_BITS +
5575 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5576 - YAFFS_TNODES_INTERNAL_MASK;
5579 - if ((l > 1) && !tn->internal[x]) {
5580 - /* Add missing non-level-zero tnode */
5581 - tn->internal[x] = yaffs_GetTnode(dev);
5583 - } else if (l == 1) {
5584 - /* Looking from level 1 at level 0 */
5586 - /* If we already have one, then release it.*/
5587 - if (tn->internal[x])
5588 - yaffs_FreeTnode(dev, tn->internal[x]);
5589 - tn->internal[x] = passedTn;
5591 - } else if (!tn->internal[x]) {
5592 - /* Don't have one, none passed in */
5593 - tn->internal[x] = yaffs_GetTnode(dev);
5597 - tn = tn->internal[x];
5601 - /* top is level 0 */
5603 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
5604 - yaffs_FreeTnode(dev, passedTn);
5611 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
5612 - yaffs_ExtendedTags *tags, int objectId,
5617 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
5618 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
5619 - theChunk % dev->nChunksPerBlock)) {
5620 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
5622 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
5633 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
5634 - * chunks and tnodes in the file
5635 - * Returns 1 if the tree was deleted.
5636 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5639 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
5640 - int chunkOffset, int *limit)
5645 - yaffs_ExtendedTags tags;
5647 - yaffs_Device *dev = in->myDev;
5653 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5655 - if (tn->internal[i]) {
5656 - if (limit && (*limit) < 0) {
5660 - yaffs_DeleteWorker(in,
5668 - YAFFS_TNODES_INTERNAL_BITS)
5673 - yaffs_FreeTnode(dev,
5676 - tn->internal[i] = NULL;
5680 - return (allDone) ? 1 : 0;
5681 - } else if (level == 0) {
5684 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5686 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5689 - chunkInInode = (chunkOffset <<
5690 - YAFFS_TNODES_LEVEL0_BITS) + i;
5693 - yaffs_FindChunkInGroup(dev,
5699 - if (foundChunk > 0) {
5700 - yaffs_DeleteChunk(dev,
5703 - in->nDataChunks--;
5705 - *limit = *limit - 1;
5712 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5716 - return (i < 0) ? 1 : 0;
5726 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
5728 - yaffs_BlockInfo *theBlock;
5730 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5732 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
5734 - theBlock->softDeletions++;
5735 - dev->nFreeChunks++;
5739 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5740 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5742 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5745 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
5746 - __u32 level, int chunkOffset)
5751 - yaffs_Device *dev = in->myDev;
5756 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5758 - if (tn->internal[i]) {
5760 - yaffs_SoftDeleteWorker(in,
5766 - YAFFS_TNODES_INTERNAL_BITS)
5769 - yaffs_FreeTnode(dev,
5772 - tn->internal[i] = NULL;
5774 - /* Hoosterman... how could this happen? */
5778 - return (allDone) ? 1 : 0;
5779 - } else if (level == 0) {
5781 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
5782 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5784 - /* Note this does not find the real chunk, only the chunk group.
5785 - * We make an assumption that a chunk group is not larger than
5788 - yaffs_SoftDeleteChunk(dev, theChunk);
5789 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5803 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
5805 - if (obj->deleted &&
5806 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
5807 - if (obj->nDataChunks <= 0) {
5808 - /* Empty file with no duplicate object headers, just delete it immediately */
5809 - yaffs_FreeTnode(obj->myDev,
5810 - obj->variant.fileVariant.top);
5811 - obj->variant.fileVariant.top = NULL;
5812 - T(YAFFS_TRACE_TRACING,
5813 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
5815 - yaffs_DoGenericObjectDeletion(obj);
5817 - yaffs_SoftDeleteWorker(obj,
5818 - obj->variant.fileVariant.top,
5819 - obj->variant.fileVariant.
5821 - obj->softDeleted = 1;
5826 -/* Pruning removes any part of the file structure tree that is beyond the
5827 - * bounds of the file (ie that does not point to chunks).
5829 - * A file should only get pruned when its size is reduced.
5831 - * Before pruning, the chunks must be pulled from the tree and the
5832 - * level 0 tnode entries must be zeroed out.
5833 - * Could also use this for file deletion, but that's probably better handled
5834 - * by a special case.
5837 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
5838 - __u32 level, int del0)
5846 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
5847 - if (tn->internal[i] && level > 0) {
5849 - yaffs_PruneWorker(dev, tn->internal[i],
5851 - (i == 0) ? del0 : 1);
5854 - if (tn->internal[i])
5858 - if (hasData == 0 && del0) {
5859 - /* Free and return NULL */
5861 - yaffs_FreeTnode(dev, tn);
5871 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
5872 - yaffs_FileStructure *fStruct)
5879 - if (fStruct->topLevel > 0) {
5881 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
5883 - /* Now we have a tree with all the non-zero branches NULL but the height
5884 - * is the same as it was.
5885 - * Let's see if we can trim internal tnodes to shorten the tree.
5886 - * We can do this if only the 0th element in the tnode is in use
5887 - * (ie all the non-zero are NULL)
5890 - while (fStruct->topLevel && !done) {
5891 - tn = fStruct->top;
5894 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
5895 - if (tn->internal[i])
5900 - fStruct->top = tn->internal[0];
5901 - fStruct->topLevel--;
5902 - yaffs_FreeTnode(dev, tn);
5912 -/*-------------------- End of File Structure functions.-------------------*/
5914 -/* yaffs_CreateFreeObjects creates a bunch more objects and
5915 - * adds them to the object free list.
5917 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
5920 - yaffs_Object *newObjects;
5921 - yaffs_ObjectList *list;
5926 - /* make these things */
5927 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
5928 - list = YMALLOC(sizeof(yaffs_ObjectList));
5930 - if (!newObjects || !list) {
5932 - YFREE(newObjects);
5935 - T(YAFFS_TRACE_ALLOCATE,
5936 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
5937 - return YAFFS_FAIL;
5940 - /* Hook them into the free list */
5941 - for (i = 0; i < nObjects - 1; i++) {
5942 - newObjects[i].siblings.next =
5943 - (struct ylist_head *)(&newObjects[i + 1]);
5946 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
5947 - dev->freeObjects = newObjects;
5948 - dev->nFreeObjects += nObjects;
5949 - dev->nObjectsCreated += nObjects;
5951 - /* Now add this bunch of Objects to a list for freeing up. */
5953 - list->objects = newObjects;
5954 - list->next = dev->allocatedObjectList;
5955 - dev->allocatedObjectList = list;
5961 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
5962 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
5964 - yaffs_Object *tn = NULL;
5966 -#ifdef VALGRIND_TEST
5967 - tn = YMALLOC(sizeof(yaffs_Object));
5969 - /* If there are none left make more */
5970 - if (!dev->freeObjects)
5971 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
5973 - if (dev->freeObjects) {
5974 - tn = dev->freeObjects;
5975 - dev->freeObjects =
5976 - (yaffs_Object *) (dev->freeObjects->siblings.next);
5977 - dev->nFreeObjects--;
5981 - /* Now sweeten it up... */
5983 - memset(tn, 0, sizeof(yaffs_Object));
5984 - tn->beingCreated = 1;
5988 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
5989 - YINIT_LIST_HEAD(&(tn->hardLinks));
5990 - YINIT_LIST_HEAD(&(tn->hashLink));
5991 - YINIT_LIST_HEAD(&tn->siblings);
5994 - /* Now make the directory sane */
5995 - if (dev->rootDir) {
5996 - tn->parent = dev->rootDir;
5997 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
6000 - /* Add it to the lost and found directory.
6001 - * NB Can't put root or lostNFound in lostNFound so
6002 - * check if lostNFound exists first
6004 - if (dev->lostNFoundDir)
6005 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
6007 - tn->beingCreated = 0;
6010 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6015 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
6019 - yaffs_Object *obj =
6020 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6022 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
6023 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
6024 - obj->unlinkAllowed = 0; /* ... or unlink it */
6026 - obj->unlinked = 0;
6027 - obj->yst_mode = mode;
6029 - obj->hdrChunk = 0; /* Not a valid chunk. */
6036 -static void yaffs_UnhashObject(yaffs_Object *tn)
6039 - yaffs_Device *dev = tn->myDev;
6041 - /* If it is still linked into the bucket list, free from the list */
6042 - if (!ylist_empty(&tn->hashLink)) {
6043 - ylist_del_init(&tn->hashLink);
6044 - bucket = yaffs_HashFunction(tn->objectId);
6045 - dev->objectBucket[bucket].count--;
6049 -/* FreeObject frees up a Object and puts it back on the free list */
6050 -static void yaffs_FreeObject(yaffs_Object *tn)
6052 - yaffs_Device *dev = tn->myDev;
6055 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
6060 - if (!ylist_empty(&tn->siblings))
6065 - if (tn->myInode) {
6066 - /* We're still hooked up to a cached inode.
6067 - * Don't delete now, but mark for later deletion
6069 - tn->deferedFree = 1;
6074 - yaffs_UnhashObject(tn);
6076 -#ifdef VALGRIND_TEST
6079 - /* Link into the free list. */
6080 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
6081 - dev->freeObjects = tn;
6082 - dev->nFreeObjects++;
6084 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6089 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
6091 - if (obj->deferedFree)
6092 - yaffs_FreeObject(obj);
6097 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
6099 - /* Free the list of allocated Objects */
6101 - yaffs_ObjectList *tmp;
6103 - while (dev->allocatedObjectList) {
6104 - tmp = dev->allocatedObjectList->next;
6105 - YFREE(dev->allocatedObjectList->objects);
6106 - YFREE(dev->allocatedObjectList);
6108 - dev->allocatedObjectList = tmp;
6111 - dev->freeObjects = NULL;
6112 - dev->nFreeObjects = 0;
6115 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
6119 - dev->allocatedObjectList = NULL;
6120 - dev->freeObjects = NULL;
6121 - dev->nFreeObjects = 0;
6123 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6124 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
6125 - dev->objectBucket[i].count = 0;
6129 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
6134 - int lowest = 999999;
6136 - /* First let's see if we can find one that's empty. */
6138 - for (i = 0; i < 10 && lowest > 0; i++) {
6140 - x %= YAFFS_NOBJECT_BUCKETS;
6141 - if (dev->objectBucket[x].count < lowest) {
6142 - lowest = dev->objectBucket[x].count;
6148 - /* If we didn't find an empty list, then try
6149 - * looking a bit further for a short one
6152 - for (i = 0; i < 10 && lowest > 3; i++) {
6154 - x %= YAFFS_NOBJECT_BUCKETS;
6155 - if (dev->objectBucket[x].count < lowest) {
6156 - lowest = dev->objectBucket[x].count;
6165 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
6167 - int bucket = yaffs_FindNiceObjectBucket(dev);
6169 - /* Now find an object value that has not already been taken
6170 - * by scanning the list.
6174 - struct ylist_head *i;
6176 - __u32 n = (__u32) bucket;
6178 - /* yaffs_CheckObjectHashSanity(); */
6182 - n += YAFFS_NOBJECT_BUCKETS;
6183 - if (1 || dev->objectBucket[bucket].count > 0) {
6184 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6185 - /* If there is already one in the list */
6186 - if (i && ylist_entry(i, yaffs_Object,
6187 - hashLink)->objectId == n) {
6197 -static void yaffs_HashObject(yaffs_Object *in)
6199 - int bucket = yaffs_HashFunction(in->objectId);
6200 - yaffs_Device *dev = in->myDev;
6202 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
6203 - dev->objectBucket[bucket].count++;
6206 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
6208 - int bucket = yaffs_HashFunction(number);
6209 - struct ylist_head *i;
6212 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6213 - /* Look if it is in the list */
6215 - in = ylist_entry(i, yaffs_Object, hashLink);
6216 - if (in->objectId == number) {
6218 - /* Don't tell the VFS about this one if it is defered free */
6219 - if (in->deferedFree)
6231 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
6232 - yaffs_ObjectType type)
6234 - yaffs_Object *theObject;
6235 - yaffs_Tnode *tn = NULL;
6238 - number = yaffs_CreateNewObjectNumber(dev);
6240 - theObject = yaffs_AllocateEmptyObject(dev);
6244 - if (type == YAFFS_OBJECT_TYPE_FILE) {
6245 - tn = yaffs_GetTnode(dev);
6247 - yaffs_FreeObject(theObject);
6253 - theObject->fake = 0;
6254 - theObject->renameAllowed = 1;
6255 - theObject->unlinkAllowed = 1;
6256 - theObject->objectId = number;
6257 - yaffs_HashObject(theObject);
6258 - theObject->variantType = type;
6259 -#ifdef CONFIG_YAFFS_WINCE
6260 - yfsd_WinFileTimeNow(theObject->win_atime);
6261 - theObject->win_ctime[0] = theObject->win_mtime[0] =
6262 - theObject->win_atime[0];
6263 - theObject->win_ctime[1] = theObject->win_mtime[1] =
6264 - theObject->win_atime[1];
6268 - theObject->yst_atime = theObject->yst_mtime =
6269 - theObject->yst_ctime = Y_CURRENT_TIME;
6272 - case YAFFS_OBJECT_TYPE_FILE:
6273 - theObject->variant.fileVariant.fileSize = 0;
6274 - theObject->variant.fileVariant.scannedFileSize = 0;
6275 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
6276 - theObject->variant.fileVariant.topLevel = 0;
6277 - theObject->variant.fileVariant.top = tn;
6279 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6280 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
6283 - case YAFFS_OBJECT_TYPE_SYMLINK:
6284 - case YAFFS_OBJECT_TYPE_HARDLINK:
6285 - case YAFFS_OBJECT_TYPE_SPECIAL:
6286 - /* No action required */
6288 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6289 - /* todo this should not happen */
6297 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
6299 - yaffs_ObjectType type)
6301 - yaffs_Object *theObject = NULL;
6304 - theObject = yaffs_FindObjectByNumber(dev, number);
6307 - theObject = yaffs_CreateNewObject(dev, number, type);
6314 -static YCHAR *yaffs_CloneString(const YCHAR *str)
6316 - YCHAR *newStr = NULL;
6318 - if (str && *str) {
6319 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
6321 - yaffs_strcpy(newStr, str);
6329 - * Mknod (create) a new object.
6330 - * equivalentObject only has meaning for a hard link;
6331 - * aliasString only has meaning for a sumlink.
6332 - * rdev only has meaning for devices (a subset of special objects)
6335 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
6336 - yaffs_Object *parent,
6337 - const YCHAR *name,
6341 - yaffs_Object *equivalentObject,
6342 - const YCHAR *aliasString, __u32 rdev)
6345 - YCHAR *str = NULL;
6347 - yaffs_Device *dev = parent->myDev;
6349 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
6350 - if (yaffs_FindObjectByName(parent, name))
6353 - in = yaffs_CreateNewObject(dev, -1, type);
6356 - return YAFFS_FAIL;
6358 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
6359 - str = yaffs_CloneString(aliasString);
6361 - yaffs_FreeObject(in);
6371 - in->variantType = type;
6373 - in->yst_mode = mode;
6375 -#ifdef CONFIG_YAFFS_WINCE
6376 - yfsd_WinFileTimeNow(in->win_atime);
6377 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
6378 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
6381 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
6383 - in->yst_rdev = rdev;
6384 - in->yst_uid = uid;
6385 - in->yst_gid = gid;
6387 - in->nDataChunks = 0;
6389 - yaffs_SetObjectName(in, name);
6392 - yaffs_AddObjectToDirectory(parent, in);
6394 - in->myDev = parent->myDev;
6397 - case YAFFS_OBJECT_TYPE_SYMLINK:
6398 - in->variant.symLinkVariant.alias = str;
6400 - case YAFFS_OBJECT_TYPE_HARDLINK:
6401 - in->variant.hardLinkVariant.equivalentObject =
6403 - in->variant.hardLinkVariant.equivalentObjectId =
6404 - equivalentObject->objectId;
6405 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
6407 - case YAFFS_OBJECT_TYPE_FILE:
6408 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6409 - case YAFFS_OBJECT_TYPE_SPECIAL:
6410 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6415 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
6416 - /* Could not create the object header, fail the creation */
6417 - yaffs_DeleteObject(in);
6426 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
6427 - __u32 mode, __u32 uid, __u32 gid)
6429 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
6430 - uid, gid, NULL, NULL, 0);
6433 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
6434 - __u32 mode, __u32 uid, __u32 gid)
6436 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
6437 - mode, uid, gid, NULL, NULL, 0);
6440 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
6441 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
6443 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
6444 - uid, gid, NULL, NULL, rdev);
6447 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
6448 - __u32 mode, __u32 uid, __u32 gid,
6449 - const YCHAR *alias)
6451 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
6452 - uid, gid, NULL, alias, 0);
6455 -/* yaffs_Link returns the object id of the equivalent object.*/
6456 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
6457 - yaffs_Object *equivalentObject)
6459 - /* Get the real object in case we were fed a hard link as an equivalent object */
6460 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
6462 - if (yaffs_MknodObject
6463 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
6464 - equivalentObject, NULL, 0)) {
6465 - return equivalentObject;
6472 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
6473 - const YCHAR *newName, int force, int shadows)
6478 - yaffs_Object *existingTarget;
6480 - if (newDir == NULL)
6481 - newDir = obj->parent; /* use the old directory */
6483 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6484 - T(YAFFS_TRACE_ALWAYS,
6486 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
6491 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
6492 - if (obj->myDev->isYaffs2)
6493 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
6495 - unlinkOp = (newDir == obj->myDev->unlinkedDir
6496 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
6498 - deleteOp = (newDir == obj->myDev->deletedDir);
6500 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6502 - /* If the object is a file going into the unlinked directory,
6503 - * then it is OK to just stuff it in since duplicate names are allowed.
6504 - * else only proceed if the new name does not exist and if we're putting
6505 - * it into a directory.
6511 - !existingTarget) &&
6512 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
6513 - yaffs_SetObjectName(obj, newName);
6516 - yaffs_AddObjectToDirectory(newDir, obj);
6519 - obj->unlinked = 1;
6521 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
6522 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
6526 - return YAFFS_FAIL;
6529 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
6530 - yaffs_Object *newDir, const YCHAR *newName)
6532 - yaffs_Object *obj = NULL;
6533 - yaffs_Object *existingTarget = NULL;
6537 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6539 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6542 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6543 - /* Special case for case insemsitive systems (eg. WinCE).
6544 - * While look-up is case insensitive, the name isn't.
6545 - * Therefore we might want to change x.txt to X.txt
6547 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
6551 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
6552 - /* ENAMETOOLONG */
6553 - return YAFFS_FAIL;
6555 - obj = yaffs_FindObjectByName(oldDir, oldName);
6557 - if (obj && obj->renameAllowed) {
6559 - /* Now do the handling for an existing target, if there is one */
6561 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6562 - if (existingTarget &&
6563 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
6564 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
6565 - /* There is a target that is a non-empty directory, so we fail */
6566 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
6567 - } else if (existingTarget && existingTarget != obj) {
6568 - /* Nuke the target first, using shadowing,
6569 - * but only if it isn't the same object
6571 - yaffs_ChangeObjectName(obj, newDir, newName, force,
6572 - existingTarget->objectId);
6573 - yaffs_UnlinkObject(existingTarget);
6576 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
6578 - return YAFFS_FAIL;
6581 -/*------------------------- Block Management and Page Allocation ----------------*/
6583 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
6585 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6587 - dev->blockInfo = NULL;
6588 - dev->chunkBits = NULL;
6590 - dev->allocationBlock = -1; /* force it to get a new one */
6592 - /* If the first allocation strategy fails, thry the alternate one */
6593 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
6594 - if (!dev->blockInfo) {
6595 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
6596 - dev->blockInfoAlt = 1;
6598 - dev->blockInfoAlt = 0;
6600 - if (dev->blockInfo) {
6601 - /* Set up dynamic blockinfo stuff. */
6602 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
6603 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
6604 - if (!dev->chunkBits) {
6605 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
6606 - dev->chunkBitsAlt = 1;
6608 - dev->chunkBitsAlt = 0;
6611 - if (dev->blockInfo && dev->chunkBits) {
6612 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
6613 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
6617 - return YAFFS_FAIL;
6620 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
6622 - if (dev->blockInfoAlt && dev->blockInfo)
6623 - YFREE_ALT(dev->blockInfo);
6624 - else if (dev->blockInfo)
6625 - YFREE(dev->blockInfo);
6627 - dev->blockInfoAlt = 0;
6629 - dev->blockInfo = NULL;
6631 - if (dev->chunkBitsAlt && dev->chunkBits)
6632 - YFREE_ALT(dev->chunkBits);
6633 - else if (dev->chunkBits)
6634 - YFREE(dev->chunkBits);
6635 - dev->chunkBitsAlt = 0;
6636 - dev->chunkBits = NULL;
6639 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
6640 - yaffs_BlockInfo *bi)
6644 - yaffs_BlockInfo *b;
6646 - if (!dev->isYaffs2)
6647 - return 1; /* disqualification only applies to yaffs2. */
6649 - if (!bi->hasShrinkHeader)
6650 - return 1; /* can gc */
6652 - /* Find the oldest dirty sequence number if we don't know it and save it
6653 - * so we don't have to keep recomputing it.
6655 - if (!dev->oldestDirtySequence) {
6656 - seq = dev->sequenceNumber;
6658 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
6660 - b = yaffs_GetBlockInfo(dev, i);
6661 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
6662 - (b->pagesInUse - b->softDeletions) <
6663 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
6664 - seq = b->sequenceNumber;
6667 - dev->oldestDirtySequence = seq;
6670 - /* Can't do gc of this block if there are any blocks older than this one that have
6671 - * discarded pages.
6673 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
6676 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
6677 - * for garbage collection.
6680 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
6683 - int b = dev->currentDirtyChecker;
6687 - int dirtiest = -1;
6688 - int pagesInUse = 0;
6689 - int prioritised = 0;
6690 - yaffs_BlockInfo *bi;
6691 - int pendingPrioritisedExist = 0;
6693 - /* First let's see if we need to grab a prioritised block */
6694 - if (dev->hasPendingPrioritisedGCs) {
6695 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
6697 - bi = yaffs_GetBlockInfo(dev, i);
6698 - /* yaffs_VerifyBlock(dev,bi,i); */
6700 - if (bi->gcPrioritise) {
6701 - pendingPrioritisedExist = 1;
6702 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6703 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6704 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6707 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
6712 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
6713 - dev->hasPendingPrioritisedGCs = 0;
6716 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
6718 - * else (we're doing a leasurely gc), then we only bother to do this if the
6719 - * block has only a few pages in use.
6722 - dev->nonAggressiveSkip--;
6724 - if (!aggressive && (dev->nonAggressiveSkip > 0))
6729 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
6733 - dev->internalEndBlock - dev->internalStartBlock + 1;
6736 - dev->internalEndBlock - dev->internalStartBlock + 1;
6737 - iterations = iterations / 16;
6738 - if (iterations > 200)
6742 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
6744 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
6745 - b = dev->internalStartBlock;
6747 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
6748 - T(YAFFS_TRACE_ERROR,
6749 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
6753 - bi = yaffs_GetBlockInfo(dev, b);
6755 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6756 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
6757 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6759 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6763 - dev->currentDirtyChecker = b;
6765 - if (dirtiest > 0) {
6767 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
6768 - dev->nChunksPerBlock - pagesInUse, prioritised));
6771 - dev->oldestDirtySequence = 0;
6774 - dev->nonAggressiveSkip = 4;
6779 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
6781 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
6785 - /* If the block is still healthy erase it and mark as clean.
6786 - * If the block has had a data failure, then retire it.
6789 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
6790 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
6791 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
6793 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
6795 - if (!bi->needsRetiring) {
6796 - yaffs_InvalidateCheckpoint(dev);
6797 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
6799 - dev->nErasureFailures++;
6800 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6801 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
6806 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
6808 - for (i = 0; i < dev->nChunksPerBlock; i++) {
6809 - if (!yaffs_CheckChunkErased
6810 - (dev, blockNo * dev->nChunksPerBlock + i)) {
6811 - T(YAFFS_TRACE_ERROR,
6813 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
6814 - TENDSTR), blockNo, i));
6820 - /* Clean it up... */
6821 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
6822 - dev->nErasedBlocks++;
6823 - bi->pagesInUse = 0;
6824 - bi->softDeletions = 0;
6825 - bi->hasShrinkHeader = 0;
6826 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
6827 - bi->gcPrioritise = 0;
6828 - yaffs_ClearChunkBits(dev, blockNo);
6830 - T(YAFFS_TRACE_ERASE,
6831 - (TSTR("Erased block %d" TENDSTR), blockNo));
6833 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
6835 - yaffs_RetireBlock(dev, blockNo);
6836 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6837 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
6841 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
6845 - yaffs_BlockInfo *bi;
6847 - if (dev->nErasedBlocks < 1) {
6848 - /* Hoosterman we've got a problem.
6849 - * Can't get space to gc
6851 - T(YAFFS_TRACE_ERROR,
6852 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
6857 - /* Find an empty block. */
6859 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
6860 - dev->allocationBlockFinder++;
6861 - if (dev->allocationBlockFinder < dev->internalStartBlock
6862 - || dev->allocationBlockFinder > dev->internalEndBlock) {
6863 - dev->allocationBlockFinder = dev->internalStartBlock;
6866 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
6868 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
6869 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
6870 - dev->sequenceNumber++;
6871 - bi->sequenceNumber = dev->sequenceNumber;
6872 - dev->nErasedBlocks--;
6873 - T(YAFFS_TRACE_ALLOCATE,
6874 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
6875 - dev->allocationBlockFinder, dev->sequenceNumber,
6876 - dev->nErasedBlocks));
6877 - return dev->allocationBlockFinder;
6881 - T(YAFFS_TRACE_ALWAYS,
6883 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
6884 - TENDSTR), dev->nErasedBlocks));
6891 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
6893 - if (!dev->nCheckpointBlocksRequired &&
6895 - /* Not a valid value so recalculate */
6898 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
6901 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6903 - if (tnodeSize < sizeof(yaffs_Tnode))
6904 - tnodeSize = sizeof(yaffs_Tnode);
6906 - nBytes += sizeof(yaffs_CheckpointValidity);
6907 - nBytes += sizeof(yaffs_CheckpointDevice);
6908 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
6909 - nBytes += devBlocks * dev->chunkBitmapStride;
6910 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
6911 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
6912 - nBytes += sizeof(yaffs_CheckpointValidity);
6913 - nBytes += sizeof(__u32); /* checksum*/
6915 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
6917 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
6919 - dev->nCheckpointBlocksRequired = nBlocks;
6922 - return dev->nCheckpointBlocksRequired;
6926 - * Check if there's space to allocate...
6927 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
6929 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
6931 - int reservedChunks;
6932 - int reservedBlocks = dev->nReservedBlocks;
6933 - int checkpointBlocks;
6935 - if (dev->isYaffs2) {
6936 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
6937 - dev->blocksInCheckpoint;
6938 - if (checkpointBlocks < 0)
6939 - checkpointBlocks = 0;
6941 - checkpointBlocks = 0;
6944 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
6946 - return (dev->nFreeChunks > reservedChunks);
6949 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
6950 - yaffs_BlockInfo **blockUsedPtr)
6953 - yaffs_BlockInfo *bi;
6955 - if (dev->allocationBlock < 0) {
6956 - /* Get next block to allocate off */
6957 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
6958 - dev->allocationPage = 0;
6961 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
6962 - /* Not enough space to allocate unless we're allowed to use the reserve. */
6966 - if (dev->nErasedBlocks < dev->nReservedBlocks
6967 - && dev->allocationPage == 0) {
6968 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
6971 - /* Next page please.... */
6972 - if (dev->allocationBlock >= 0) {
6973 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
6975 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
6976 - dev->allocationPage;
6978 - yaffs_SetChunkBit(dev, dev->allocationBlock,
6979 - dev->allocationPage);
6981 - dev->allocationPage++;
6983 - dev->nFreeChunks--;
6985 - /* If the block is full set the state to full */
6986 - if (dev->allocationPage >= dev->nChunksPerBlock) {
6987 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
6988 - dev->allocationBlock = -1;
6992 - *blockUsedPtr = bi;
6997 - T(YAFFS_TRACE_ERROR,
6998 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
7003 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
7007 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
7009 - if (dev->allocationBlock > 0)
7010 - n += (dev->nChunksPerBlock - dev->allocationPage);
7016 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
7022 - int retVal = YAFFS_OK;
7025 - int isCheckpointBlock;
7026 - int matchingChunk;
7029 - int chunksBefore = yaffs_GetErasedChunks(dev);
7032 - yaffs_ExtendedTags tags;
7034 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
7036 - yaffs_Object *object;
7038 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
7040 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
7042 - T(YAFFS_TRACE_TRACING,
7043 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
7046 - bi->hasShrinkHeader,
7049 - /*yaffs_VerifyFreeChunks(dev); */
7051 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
7053 - /* Take off the number of soft deleted entries because
7054 - * they're going to get really deleted during GC.
7056 - dev->nFreeChunks -= bi->softDeletions;
7058 - dev->isDoingGC = 1;
7060 - if (isCheckpointBlock ||
7061 - !yaffs_StillSomeChunkBits(dev, block)) {
7062 - T(YAFFS_TRACE_TRACING,
7064 - ("Collecting block %d that has no chunks in use" TENDSTR),
7066 - yaffs_BlockBecameDirty(dev, block);
7069 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
7071 - yaffs_VerifyBlock(dev, bi, block);
7073 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
7074 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
7076 - for (/* init already done */;
7077 - retVal == YAFFS_OK &&
7078 - dev->gcChunk < dev->nChunksPerBlock &&
7079 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
7081 - dev->gcChunk++, oldChunk++) {
7082 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
7084 - /* This page is in use and might need to be copied off */
7090 - yaffs_InitialiseTags(&tags);
7092 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
7096 - yaffs_FindObjectByNumber(dev,
7099 - T(YAFFS_TRACE_GC_DETAIL,
7101 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
7102 - dev->gcChunk, tags.objectId, tags.chunkId,
7105 - if (object && !yaffs_SkipVerification(dev)) {
7106 - if (tags.chunkId == 0)
7107 - matchingChunk = object->hdrChunk;
7108 - else if (object->softDeleted)
7109 - matchingChunk = oldChunk; /* Defeat the test */
7111 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
7113 - if (oldChunk != matchingChunk)
7114 - T(YAFFS_TRACE_ERROR,
7115 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
7116 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
7121 - T(YAFFS_TRACE_ERROR,
7123 - ("page %d in gc has no object: %d %d %d "
7124 - TENDSTR), oldChunk,
7125 - tags.objectId, tags.chunkId, tags.byteCount));
7129 - object->deleted &&
7130 - object->softDeleted &&
7131 - tags.chunkId != 0) {
7132 - /* Data chunk in a soft deleted file, throw it away
7133 - * It's a soft deleted data chunk,
7134 - * No need to copy this, just forget about it and
7135 - * fix up the object.
7138 - object->nDataChunks--;
7140 - if (object->nDataChunks <= 0) {
7141 - /* remeber to clean up the object */
7142 - dev->gcCleanupList[cleanups] =
7148 - /* Todo object && object->deleted && object->nDataChunks == 0 */
7149 - /* Deleted object header with no data chunks.
7150 - * Can be discarded and the file deleted.
7152 - object->hdrChunk = 0;
7153 - yaffs_FreeTnode(object->myDev,
7156 - object->variant.fileVariant.top = NULL;
7157 - yaffs_DoGenericObjectDeletion(object);
7159 - } else if (object) {
7160 - /* It's either a data chunk in a live file or
7161 - * an ObjectHeader, so we're interested in it.
7162 - * NB Need to keep the ObjectHeaders of deleted files
7163 - * until the whole file has been deleted off
7165 - tags.serialNumber++;
7169 - if (tags.chunkId == 0) {
7170 - /* It is an object Id,
7171 - * We need to nuke the shrinkheader flags first
7172 - * We no longer want the shrinkHeader flag since its work is done
7173 - * and if it is left in place it will mess up scanning.
7176 - yaffs_ObjectHeader *oh;
7177 - oh = (yaffs_ObjectHeader *)buffer;
7179 - tags.extraIsShrinkHeader = 0;
7181 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
7185 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
7187 - if (newChunk < 0) {
7188 - retVal = YAFFS_FAIL;
7191 - /* Ok, now fix up the Tnodes etc. */
7193 - if (tags.chunkId == 0) {
7194 - /* It's a header */
7195 - object->hdrChunk = newChunk;
7196 - object->serial = tags.serialNumber;
7198 - /* It's a data chunk */
7199 - yaffs_PutChunkIntoFile
7207 - if (retVal == YAFFS_OK)
7208 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
7213 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
7216 - /* Do any required cleanups */
7217 - for (i = 0; i < cleanups; i++) {
7218 - /* Time to delete the file too */
7220 - yaffs_FindObjectByNumber(dev,
7221 - dev->gcCleanupList[i]);
7223 - yaffs_FreeTnode(dev,
7224 - object->variant.fileVariant.
7226 - object->variant.fileVariant.top = NULL;
7229 - ("yaffs: About to finally delete object %d"
7230 - TENDSTR), object->objectId));
7231 - yaffs_DoGenericObjectDeletion(object);
7232 - object->myDev->nDeletedFiles--;
7239 - yaffs_VerifyCollectedBlock(dev, bi, block);
7240 + if (chunkId > YAFFS_MAX_CHUNK_ID)
7243 - chunksAfter = yaffs_GetErasedChunks(dev);
7244 - if (chunksBefore >= chunksAfter) {
7247 - ("gc did not increase free chunks before %d after %d"
7248 - TENDSTR), chunksBefore, chunksAfter));
7250 + /* First check we're tall enough (ie enough topLevel) */
7252 - /* If the gc completed then clear the current gcBlock so that we find another. */
7253 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
7254 - dev->gcBlock = -1;
7256 + x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
7257 + requiredTallness = 0;
7259 + x >>= YAFFS_TNODES_INTERNAL_BITS;
7260 + requiredTallness++;
7263 - dev->isDoingGC = 0;
7268 -/* New garbage collector
7269 - * If we're very low on erased blocks then we do aggressive garbage collection
7270 - * otherwise we do "leasurely" garbage collection.
7271 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
7272 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
7274 - * The idea is to help clear out space in a more spread-out manner.
7275 - * Dunno if it really does anything useful.
7277 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
7281 - int gcOk = YAFFS_OK;
7283 + if (requiredTallness > fStruct->topLevel) {
7284 + /* Not tall enough, gotta make the tree taller */
7285 + for (i = fStruct->topLevel; i < requiredTallness; i++) {
7287 - int checkpointBlockAdjust;
7288 + tn = yaffs_GetTnode(dev);
7290 - if (dev->isDoingGC) {
7291 - /* Bail out so we don't get recursive gc */
7294 + tn->internal[0] = fStruct->top;
7295 + fStruct->top = tn;
7296 + fStruct->topLevel++;
7298 + T(YAFFS_TRACE_ERROR,
7299 + (TSTR("yaffs: no more tnodes" TENDSTR)));
7305 - /* This loop should pass the first time.
7306 - * We'll only see looping here if the erase of the collected block fails.
7312 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
7313 - if (checkpointBlockAdjust < 0)
7314 - checkpointBlockAdjust = 0;
7315 + /* Traverse down to level 0, adding anything we need */
7317 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
7318 - /* We need a block soon...*/
7321 - /* We're in no hurry */
7324 + l = fStruct->topLevel;
7325 + tn = fStruct->top;
7327 - if (dev->gcBlock <= 0) {
7328 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
7332 + while (l > 0 && tn) {
7334 + (YAFFS_TNODES_LEVEL0_BITS +
7335 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
7336 + YAFFS_TNODES_INTERNAL_MASK;
7338 - block = dev->gcBlock;
7341 - dev->garbageCollections++;
7343 - dev->passiveGarbageCollections++;
7344 + if ((l > 1) && !tn->internal[x]) {
7345 + /* Add missing non-level-zero tnode */
7346 + tn->internal[x] = yaffs_GetTnode(dev);
7347 + if(!tn->internal[x])
7349 + } else if (l == 1) {
7350 + /* Looking from level 1 at level 0 */
7352 + /* If we already have one, then release it.*/
7353 + if (tn->internal[x])
7354 + yaffs_FreeTnode(dev, tn->internal[x]);
7355 + tn->internal[x] = passedTn;
7359 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
7360 - dev->nErasedBlocks, aggressive));
7361 + } else if (!tn->internal[x]) {
7362 + /* Don't have one, none passed in */
7363 + tn->internal[x] = yaffs_GetTnode(dev);
7364 + if(!tn->internal[x])
7369 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
7370 + tn = tn->internal[x];
7374 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
7377 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
7378 - TENDSTR), dev->nErasedBlocks, maxTries, block));
7380 + /* top is level 0 */
7382 + memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
7383 + yaffs_FreeTnode(dev, passedTn);
7385 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
7390 - return aggressive ? gcOk : YAFFS_OK;
7394 -/*------------------------- TAGS --------------------------------*/
7396 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
7397 - int chunkInObject)
7398 +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
7399 + yaffs_ExtendedTags *tags, int objectId,
7402 - return (tags->chunkId == chunkInObject &&
7403 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
7406 + for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
7407 + if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock,
7408 + theChunk % dev->param.nChunksPerBlock)) {
7410 + if(dev->chunkGroupSize == 1)
7413 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
7415 + if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
7427 +/* Experimental code not being used yet. Might speed up file deletion */
7428 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
7429 + * chunks and tnodes in the file.
7430 + * Returns 1 if the tree was deleted.
7431 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
7434 -/*-------------------- Data file manipulation -----------------*/
7436 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
7437 - yaffs_ExtendedTags *tags)
7438 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
7439 + int chunkOffset, int *limit)
7441 - /*Get the Tnode, then get the level 0 offset chunk offset */
7443 - int theChunk = -1;
7444 - yaffs_ExtendedTags localTags;
7450 + yaffs_ExtendedTags tags;
7452 yaffs_Device *dev = in->myDev;
7455 - /* Passed a NULL, so use our own tags space */
7456 - tags = &localTags;
7459 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7463 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7465 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7467 + if (tn->internal[i]) {
7468 + if (limit && (*limit) < 0) {
7472 + yaffs_DeleteWorker(in,
7480 + YAFFS_TNODES_INTERNAL_BITS)
7485 + yaffs_FreeTnode(dev,
7488 + tn->internal[i] = NULL;
7492 + return (allDone) ? 1 : 0;
7493 + } else if (level == 0) {
7497 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7502 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
7504 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7507 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
7508 - yaffs_ExtendedTags *tags)
7510 - /* Get the Tnode, then get the level 0 offset chunk offset */
7512 - int theChunk = -1;
7513 - yaffs_ExtendedTags localTags;
7514 + chunkInInode = (chunkOffset <<
7515 + YAFFS_TNODES_LEVEL0_BITS) + i;
7518 + yaffs_FindChunkInGroup(dev,
7524 + if (foundChunk > 0) {
7525 + yaffs_DeleteChunk(dev,
7528 + in->nDataChunks--;
7530 + *limit = *limit - 1;
7535 - yaffs_Device *dev = in->myDev;
7539 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7543 + return (i < 0) ? 1 : 0;
7548 - /* Passed a NULL, so use our own tags space */
7549 - tags = &localTags;
7552 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7558 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7562 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7564 +static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
7566 + yaffs_BlockInfo *theBlock;
7569 - /* Delete the entry in the filestructure (if found) */
7571 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
7573 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
7576 + blockNo = chunk / dev->param.nChunksPerBlock;
7577 + theBlock = yaffs_GetBlockInfo(dev, blockNo);
7579 + theBlock->softDeletions++;
7580 + dev->nFreeChunks++;
7581 + yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock);
7585 -#ifdef YAFFS_PARANOID
7586 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
7587 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
7589 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
7592 -static int yaffs_CheckFileSanity(yaffs_Object *in)
7593 +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
7594 + __u32 level, int chunkOffset)
7602 - yaffs_Tags localTags;
7603 - yaffs_Tags *tags = &localTags;
7608 + yaffs_Device *dev = in->myDev;
7610 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
7611 - return YAFFS_FAIL;
7615 - objId = in->objectId;
7616 - fSize = in->variant.fileVariant.fileSize;
7618 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
7620 - for (chunk = 1; chunk <= nChunks; chunk++) {
7621 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
7626 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
7628 - if (yaffs_CheckChunkBits
7629 - (dev, theChunk / dev->nChunksPerBlock,
7630 - theChunk % dev->nChunksPerBlock)) {
7632 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
7635 - if (yaffs_TagsMatch
7636 - (tags, in->objectId, chunk, chunkDeleted)) {
7638 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7640 + if (tn->internal[i]) {
7642 + yaffs_SoftDeleteWorker(in,
7648 + YAFFS_TNODES_INTERNAL_BITS)
7651 + yaffs_FreeTnode(dev,
7654 + tn->internal[i] = NULL;
7656 + /* Hoosterman... how could this happen? */
7660 + return (allDone) ? 1 : 0;
7661 + } else if (level == 0) {
7663 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
7664 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7666 + /* Note this does not find the real chunk, only the chunk group.
7667 + * We make an assumption that a chunk group is not larger than
7670 + yaffs_SoftDeleteChunk(dev, theChunk);
7671 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7680 - /* T(("No level 0 found for %d\n", chunk)); */
7685 - return failed ? YAFFS_FAIL : YAFFS_OK;
7691 +static void yaffs_SoftDeleteFile(yaffs_Object *obj)
7693 + if (obj->deleted &&
7694 + obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
7695 + if (obj->nDataChunks <= 0) {
7696 + /* Empty file with no duplicate object headers, just delete it immediately */
7697 + yaffs_FreeTnode(obj->myDev,
7698 + obj->variant.fileVariant.top);
7699 + obj->variant.fileVariant.top = NULL;
7700 + T(YAFFS_TRACE_TRACING,
7701 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
7703 + yaffs_DoGenericObjectDeletion(obj);
7705 + yaffs_SoftDeleteWorker(obj,
7706 + obj->variant.fileVariant.top,
7707 + obj->variant.fileVariant.
7709 + obj->softDeleted = 1;
7714 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
7715 - int chunkInNAND, int inScan)
7716 +/* Pruning removes any part of the file structure tree that is beyond the
7717 + * bounds of the file (ie that does not point to chunks).
7719 + * A file should only get pruned when its size is reduced.
7721 + * Before pruning, the chunks must be pulled from the tree and the
7722 + * level 0 tnode entries must be zeroed out.
7723 + * Could also use this for file deletion, but that's probably better handled
7724 + * by a special case.
7726 + * This function is recursive. For levels > 0 the function is called again on
7727 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
7728 + * If there is no data in a subtree then it is pruned.
7731 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7732 + __u32 level, int del0)
7734 - /* NB inScan is zero unless scanning.
7735 - * For forward scanning, inScan is > 0;
7736 - * for backward scanning inScan is < 0
7742 - yaffs_Device *dev = in->myDev;
7743 - int existingChunk;
7744 - yaffs_ExtendedTags existingTags;
7745 - yaffs_ExtendedTags newTags;
7746 - unsigned existingSerial, newSerial;
7750 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
7751 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
7752 - * If it is not during Scanning then something went wrong!
7755 - T(YAFFS_TRACE_ERROR,
7757 - ("yaffs tragedy:attempt to put data chunk into a non-file"
7762 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7763 + if (tn->internal[i]) {
7765 + yaffs_PruneWorker(dev, tn->internal[i],
7767 + (i == 0) ? del0 : 1);
7770 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
7773 + if (tn->internal[i])
7777 + int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32);
7778 + __u32 *map = (__u32 *)tn;
7780 - tn = yaffs_AddOrFindLevel0Tnode(dev,
7781 - &in->variant.fileVariant,
7785 - return YAFFS_FAIL;
7786 + for(i = 0; !hasData && i < tnodeSize_u32; i++){
7792 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7793 + if (hasData == 0 && del0) {
7794 + /* Free and return NULL */
7796 - if (inScan != 0) {
7797 - /* If we're scanning then we need to test for duplicates
7798 - * NB This does not need to be efficient since it should only ever
7799 - * happen when the power fails during a write, then only one
7800 - * chunk should ever be affected.
7802 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
7803 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
7805 + yaffs_FreeTnode(dev, tn);
7809 - if (existingChunk > 0) {
7810 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
7811 - * thus we have to do a FindChunkInFile to get the real chunk id.
7813 - * We have a duplicate now we need to decide which one to use:
7815 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
7816 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
7817 - * YAFFS1: Get both sets of tags and compare serial numbers.
7822 - /* Only do this for forward scanning */
7823 - yaffs_ReadChunkWithTagsFromNAND(dev,
7828 - /* Do a proper find */
7830 - yaffs_FindChunkInFile(in, chunkInInode,
7835 - if (existingChunk <= 0) {
7836 - /*Hoosterman - how did this happen? */
7837 +static int yaffs_PruneFileStructure(yaffs_Device *dev,
7838 + yaffs_FileStructure *fStruct)
7845 - T(YAFFS_TRACE_ERROR,
7847 - ("yaffs tragedy: existing chunk < 0 in scan"
7849 + if (fStruct->topLevel > 0) {
7851 + yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7854 + /* Now we have a tree with all the non-zero branches NULL but the height
7855 + * is the same as it was.
7856 + * Let's see if we can trim internal tnodes to shorten the tree.
7857 + * We can do this if only the 0th element in the tnode is in use
7858 + * (ie all the non-zero are NULL)
7861 - /* NB The deleted flags should be false, otherwise the chunks will
7862 - * not be loaded during a scan
7864 + while (fStruct->topLevel && !done) {
7865 + tn = fStruct->top;
7868 - newSerial = newTags.serialNumber;
7869 - existingSerial = existingTags.serialNumber;
7871 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7872 + if (tn->internal[i])
7876 - if ((inScan > 0) &&
7877 - (in->myDev->isYaffs2 ||
7878 - existingChunk <= 0 ||
7879 - ((existingSerial + 1) & 3) == newSerial)) {
7880 - /* Forward scanning.
7882 - * Delete the old one and drop through to update the tnode
7884 - yaffs_DeleteChunk(dev, existingChunk, 1,
7887 - /* Backward scanning or we want to use the existing one
7889 - * Delete the new one and return early so that the tnode isn't changed
7891 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
7896 + fStruct->top = tn->internal[0];
7897 + fStruct->topLevel--;
7898 + yaffs_FreeTnode(dev, tn);
7906 - if (existingChunk == 0)
7907 - in->nDataChunks++;
7909 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
7914 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
7917 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
7919 - if (chunkInNAND >= 0)
7920 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
7923 - T(YAFFS_TRACE_NANDACCESS,
7924 - (TSTR("Chunk %d not found zero instead" TENDSTR),
7926 - /* get sane (zero) data if you read a hole */
7927 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
7930 +/*-------------------- End of File Structure functions.-------------------*/
7934 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
7935 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7936 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7940 - yaffs_ExtendedTags tags;
7941 - yaffs_BlockInfo *bi;
7942 + yaffs_Object *obj = yaffs_AllocateRawObject(dev);
7949 - dev->nDeletions++;
7950 - block = chunkId / dev->nChunksPerBlock;
7951 - page = chunkId % dev->nChunksPerBlock;
7952 + /* Now sweeten it up... */
7954 + memset(obj, 0, sizeof(yaffs_Object));
7955 + obj->beingCreated = 1;
7957 - if (!yaffs_CheckChunkBit(dev, block, page))
7958 - T(YAFFS_TRACE_VERIFY,
7959 - (TSTR("Deleting invalid chunk %d"TENDSTR),
7962 + obj->hdrChunk = 0;
7963 + obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7964 + YINIT_LIST_HEAD(&(obj->hardLinks));
7965 + YINIT_LIST_HEAD(&(obj->hashLink));
7966 + YINIT_LIST_HEAD(&obj->siblings);
7968 - bi = yaffs_GetBlockInfo(dev, block);
7970 - T(YAFFS_TRACE_DELETION,
7971 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
7972 + /* Now make the directory sane */
7973 + if (dev->rootDir) {
7974 + obj->parent = dev->rootDir;
7975 + ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children);
7979 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
7980 + /* Add it to the lost and found directory.
7981 + * NB Can't put root or lostNFound in lostNFound so
7982 + * check if lostNFound exists first
7984 + if (dev->lostNFoundDir)
7985 + yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj);
7987 - yaffs_InitialiseTags(&tags);
7988 + obj->beingCreated = 0;
7991 - tags.chunkDeleted = 1;
7992 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7994 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
7995 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
7997 - dev->nUnmarkedDeletions++;
8002 - /* Pull out of the management area.
8003 - * If the whole block became dirty, this will kick off an erasure.
8005 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8006 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8007 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8008 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8009 - dev->nFreeChunks++;
8010 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
8014 - yaffs_ClearChunkBit(dev, block, page);
8015 + yaffs_Object *obj =
8016 + yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
8018 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
8019 + obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
8020 + obj->unlinkAllowed = 0; /* ... or unlink it */
8022 + obj->unlinked = 0;
8023 + obj->yst_mode = mode;
8025 + obj->hdrChunk = 0; /* Not a valid chunk. */
8031 - if (bi->pagesInUse == 0 &&
8032 - !bi->hasShrinkHeader &&
8033 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8034 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8035 - yaffs_BlockBecameDirty(dev, block);
8040 +static void yaffs_UnhashObject(yaffs_Object *obj)
8043 + yaffs_Device *dev = obj->myDev;
8045 + /* If it is still linked into the bucket list, free from the list */
8046 + if (!ylist_empty(&obj->hashLink)) {
8047 + ylist_del_init(&obj->hashLink);
8048 + bucket = yaffs_HashFunction(obj->objectId);
8049 + dev->objectBucket[bucket].count--;
8053 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8054 - const __u8 *buffer, int nBytes,
8056 +/* FreeObject frees up a Object and puts it back on the free list */
8057 +static void yaffs_FreeObject(yaffs_Object *obj)
8059 - /* Find old chunk Need to do this to get serial number
8060 - * Write new one and patch into tree.
8061 - * Invalidate old tags.
8063 + yaffs_Device *dev = obj->myDev;
8066 - yaffs_ExtendedTags prevTags;
8067 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode));
8070 - yaffs_ExtendedTags newTags;
8075 + if (!ylist_empty(&obj->siblings))
8078 - yaffs_Device *dev = in->myDev;
8080 - yaffs_CheckGarbageCollection(dev);
8081 + if (obj->myInode) {
8082 + /* We're still hooked up to a cached inode.
8083 + * Don't delete now, but mark for later deletion
8085 + obj->deferedFree = 1;
8089 + yaffs_UnhashObject(obj);
8091 - /* Get the previous chunk at this location in the file if it exists */
8092 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8093 + yaffs_FreeRawObject(dev,obj);
8095 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
8098 - /* Set up new tags */
8099 - yaffs_InitialiseTags(&newTags);
8101 - newTags.chunkId = chunkInInode;
8102 - newTags.objectId = in->objectId;
8103 - newTags.serialNumber =
8104 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8105 - newTags.byteCount = nBytes;
8106 +void yaffs_HandleDeferedFree(yaffs_Object *obj)
8108 + if (obj->deferedFree)
8109 + yaffs_FreeObject(obj);
8112 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8113 - T(YAFFS_TRACE_ERROR,
8114 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8116 +static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev)
8120 + dev->nObjects = 0;
8123 + yaffs_InitialiseRawTnodesAndObjects(dev);
8125 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
8126 + YINIT_LIST_HEAD(&dev->objectBucket[i].list);
8127 + dev->objectBucket[i].count = 0;
8132 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8134 +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
8138 + int lowest = 999999;
8140 - if (newChunkId >= 0) {
8141 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8143 - if (prevChunkId >= 0)
8144 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8145 + /* Search for the shortest list or one that
8149 + for (i = 0; i < 10 && lowest > 4; i++) {
8150 + dev->bucketFinder++;
8151 + dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS;
8152 + if (dev->objectBucket[dev->bucketFinder].count < lowest) {
8153 + lowest = dev->objectBucket[dev->bucketFinder].count;
8154 + l = dev->bucketFinder;
8157 - yaffs_CheckFileSanity(in);
8159 - return newChunkId;
8164 -/* UpdateObjectHeader updates the header on NAND for an object.
8165 - * If name is not NULL, then that new name is used.
8167 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8168 - int isShrink, int shadows)
8169 +static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
8171 + int bucket = yaffs_FindNiceObjectBucket(dev);
8173 - yaffs_BlockInfo *bi;
8174 + /* Now find an object value that has not already been taken
8175 + * by scanning the list.
8178 - yaffs_Device *dev = in->myDev;
8180 + struct ylist_head *i;
8185 + __u32 n = (__u32) bucket;
8188 - yaffs_ExtendedTags newTags;
8189 - yaffs_ExtendedTags oldTags;
8190 + /* yaffs_CheckObjectHashSanity(); */
8192 - __u8 *buffer = NULL;
8193 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8196 + n += YAFFS_NOBJECT_BUCKETS;
8197 + if (1 || dev->objectBucket[bucket].count > 0) {
8198 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8199 + /* If there is already one in the list */
8200 + if (i && ylist_entry(i, yaffs_Object,
8201 + hashLink)->objectId == n) {
8208 - yaffs_ObjectHeader *oh = NULL;
8212 - yaffs_strcpy(oldName, _Y("silly old name"));
8213 +static void yaffs_HashObject(yaffs_Object *in)
8215 + int bucket = yaffs_HashFunction(in->objectId);
8216 + yaffs_Device *dev = in->myDev;
8218 + ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
8219 + dev->objectBucket[bucket].count++;
8223 - in == dev->rootDir || /* The rootDir should also be saved */
8225 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
8227 + int bucket = yaffs_HashFunction(number);
8228 + struct ylist_head *i;
8231 - yaffs_CheckGarbageCollection(dev);
8232 - yaffs_CheckObjectDetailsLoaded(in);
8233 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8234 + /* Look if it is in the list */
8236 + in = ylist_entry(i, yaffs_Object, hashLink);
8237 + if (in->objectId == number) {
8239 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8240 - oh = (yaffs_ObjectHeader *) buffer;
8241 + /* Don't tell the VFS about this one if it is defered free */
8242 + if (in->deferedFree)
8245 - prevChunkId = in->hdrChunk;
8251 - if (prevChunkId > 0) {
8252 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8253 - buffer, &oldTags);
8257 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8258 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
8259 + yaffs_ObjectType type)
8261 + yaffs_Object *theObject=NULL;
8262 + yaffs_Tnode *tn = NULL;
8265 + number = yaffs_CreateNewObjectNumber(dev);
8267 - memcpy(oldName, oh->name, sizeof(oh->name));
8269 + if (type == YAFFS_OBJECT_TYPE_FILE) {
8270 + tn = yaffs_GetTnode(dev);
8275 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8276 + theObject = yaffs_AllocateEmptyObject(dev);
8279 + yaffs_FreeTnode(dev,tn);
8283 - oh->type = in->variantType;
8284 - oh->yst_mode = in->yst_mode;
8285 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8288 + theObject->fake = 0;
8289 + theObject->renameAllowed = 1;
8290 + theObject->unlinkAllowed = 1;
8291 + theObject->objectId = number;
8292 + yaffs_HashObject(theObject);
8293 + theObject->variantType = type;
8294 #ifdef CONFIG_YAFFS_WINCE
8295 - oh->win_atime[0] = in->win_atime[0];
8296 - oh->win_ctime[0] = in->win_ctime[0];
8297 - oh->win_mtime[0] = in->win_mtime[0];
8298 - oh->win_atime[1] = in->win_atime[1];
8299 - oh->win_ctime[1] = in->win_ctime[1];
8300 - oh->win_mtime[1] = in->win_mtime[1];
8302 - oh->yst_uid = in->yst_uid;
8303 - oh->yst_gid = in->yst_gid;
8304 - oh->yst_atime = in->yst_atime;
8305 - oh->yst_mtime = in->yst_mtime;
8306 - oh->yst_ctime = in->yst_ctime;
8307 - oh->yst_rdev = in->yst_rdev;
8310 - oh->parentObjectId = in->parent->objectId;
8312 - oh->parentObjectId = 0;
8314 - if (name && *name) {
8315 - memset(oh->name, 0, sizeof(oh->name));
8316 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
8317 - } else if (prevChunkId >= 0)
8318 - memcpy(oh->name, oldName, sizeof(oh->name));
8320 - memset(oh->name, 0, sizeof(oh->name));
8321 + yfsd_WinFileTimeNow(theObject->win_atime);
8322 + theObject->win_ctime[0] = theObject->win_mtime[0] =
8323 + theObject->win_atime[0];
8324 + theObject->win_ctime[1] = theObject->win_mtime[1] =
8325 + theObject->win_atime[1];
8327 - oh->isShrink = isShrink;
8330 - switch (in->variantType) {
8331 - case YAFFS_OBJECT_TYPE_UNKNOWN:
8332 - /* Should not happen */
8334 + theObject->yst_atime = theObject->yst_mtime =
8335 + theObject->yst_ctime = Y_CURRENT_TIME;
8338 case YAFFS_OBJECT_TYPE_FILE:
8340 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
8341 - || oh->parentObjectId ==
8342 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
8343 - fileVariant.fileSize;
8345 - case YAFFS_OBJECT_TYPE_HARDLINK:
8346 - oh->equivalentObjectId =
8347 - in->variant.hardLinkVariant.equivalentObjectId;
8349 - case YAFFS_OBJECT_TYPE_SPECIAL:
8351 + theObject->variant.fileVariant.fileSize = 0;
8352 + theObject->variant.fileVariant.scannedFileSize = 0;
8353 + theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
8354 + theObject->variant.fileVariant.topLevel = 0;
8355 + theObject->variant.fileVariant.top = tn;
8357 case YAFFS_OBJECT_TYPE_DIRECTORY:
8359 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8361 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8364 case YAFFS_OBJECT_TYPE_SYMLINK:
8365 - yaffs_strncpy(oh->alias,
8366 - in->variant.symLinkVariant.alias,
8367 - YAFFS_MAX_ALIAS_LENGTH);
8368 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
8369 + case YAFFS_OBJECT_TYPE_HARDLINK:
8370 + case YAFFS_OBJECT_TYPE_SPECIAL:
8371 + /* No action required */
8373 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8374 + /* todo this should not happen */
8380 - yaffs_InitialiseTags(&newTags);
8382 - newTags.chunkId = 0;
8383 - newTags.objectId = in->objectId;
8384 - newTags.serialNumber = in->serial;
8386 - /* Add extra info for file header */
8388 - newTags.extraHeaderInfoAvailable = 1;
8389 - newTags.extraParentObjectId = oh->parentObjectId;
8390 - newTags.extraFileLength = oh->fileSize;
8391 - newTags.extraIsShrinkHeader = oh->isShrink;
8392 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
8393 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
8394 - newTags.extraObjectType = in->variantType;
8396 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
8400 - /* Create new chunk in NAND */
8402 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8403 - (prevChunkId >= 0) ? 1 : 0);
8404 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
8406 + yaffs_ObjectType type)
8408 + yaffs_Object *theObject = NULL;
8410 - if (newChunkId >= 0) {
8412 + theObject = yaffs_FindObjectByNumber(dev, number);
8414 - in->hdrChunk = newChunkId;
8416 + theObject = yaffs_CreateNewObject(dev, number, type);
8418 - if (prevChunkId >= 0) {
8419 - yaffs_DeleteChunk(dev, prevChunkId, 1,
8424 - if (!yaffs_ObjectHasCachedWriteData(in))
8428 - /* If this was a shrink, then mark the block that the chunk lives on */
8430 - bi = yaffs_GetBlockInfo(in->myDev,
8431 - newChunkId / in->myDev->nChunksPerBlock);
8432 - bi->hasShrinkHeader = 1;
8436 +YCHAR *yaffs_CloneString(const YCHAR *str)
8438 + YCHAR *newStr = NULL;
8441 - retVal = newChunkId;
8445 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
8446 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
8448 + yaffs_strncpy(newStr, str,len);
8454 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8459 -/*------------------------ Short Operations Cache ----------------------------------------
8460 - * In many situations where there is no high level buffering (eg WinCE) a lot of
8461 - * reads might be short sequential reads, and a lot of writes may be short
8462 - * sequential writes. eg. scanning/writing a jpeg file.
8463 - * In these cases, a short read/write cache can provide a huge perfomance benefit
8464 - * with dumb-as-a-rock code.
8465 - * In Linux, the page cache provides read buffering aand the short op cache provides write
8468 - * There are a limited number (~10) of cache chunks per device so that we don't
8469 - * need a very intelligent search.
8471 + * Mknod (create) a new object.
8472 + * equivalentObject only has meaning for a hard link;
8473 + * aliasString only has meaning for a symlink.
8474 + * rdev only has meaning for devices (a subset of special objects)
8477 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
8478 +static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
8479 + yaffs_Object *parent,
8480 + const YCHAR *name,
8484 + yaffs_Object *equivalentObject,
8485 + const YCHAR *aliasString, __u32 rdev)
8487 - yaffs_Device *dev = obj->myDev;
8489 - yaffs_ChunkCache *cache;
8490 - int nCaches = obj->myDev->nShortOpCaches;
8492 + YCHAR *str = NULL;
8494 - for (i = 0; i < nCaches; i++) {
8495 - cache = &dev->srCache[i];
8496 - if (cache->object == obj &&
8499 + yaffs_Device *dev = parent->myDev;
8501 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8502 + if (yaffs_FindObjectByName(parent, name))
8505 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8506 + str = yaffs_CloneString(aliasString);
8513 + in = yaffs_CreateNewObject(dev, -1, type);
8521 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
8523 - yaffs_Device *dev = obj->myDev;
8524 - int lowest = -99; /* Stop compiler whining. */
8526 - yaffs_ChunkCache *cache;
8527 - int chunkWritten = 0;
8528 - int nCaches = obj->myDev->nShortOpCaches;
8530 - if (nCaches > 0) {
8534 - /* Find the dirty cache for this object with the lowest chunk id. */
8535 - for (i = 0; i < nCaches; i++) {
8536 - if (dev->srCache[i].object == obj &&
8537 - dev->srCache[i].dirty) {
8539 - || dev->srCache[i].chunkId <
8541 - cache = &dev->srCache[i];
8542 - lowest = cache->chunkId;
8547 - if (cache && !cache->locked) {
8548 - /* Write it out and free it up */
8551 - yaffs_WriteChunkDataToObject(cache->object,
8557 - cache->object = NULL;
8562 + in->variantType = type;
8564 - } while (cache && chunkWritten > 0);
8565 + in->yst_mode = mode;
8568 - /* Hoosterman, disk full while writing cache out. */
8569 - T(YAFFS_TRACE_ERROR,
8570 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
8571 +#ifdef CONFIG_YAFFS_WINCE
8572 + yfsd_WinFileTimeNow(in->win_atime);
8573 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8574 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
8577 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
8579 + in->yst_rdev = rdev;
8580 + in->yst_uid = uid;
8581 + in->yst_gid = gid;
8583 + in->nDataChunks = 0;
8585 + yaffs_SetObjectName(in, name);
8588 + yaffs_AddObjectToDirectory(parent, in);
8590 + in->myDev = parent->myDev;
8593 + case YAFFS_OBJECT_TYPE_SYMLINK:
8594 + in->variant.symLinkVariant.alias = str;
8596 + case YAFFS_OBJECT_TYPE_HARDLINK:
8597 + in->variant.hardLinkVariant.equivalentObject =
8599 + in->variant.hardLinkVariant.equivalentObjectId =
8600 + equivalentObject->objectId;
8601 + ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
8603 + case YAFFS_OBJECT_TYPE_FILE:
8604 + case YAFFS_OBJECT_TYPE_DIRECTORY:
8605 + case YAFFS_OBJECT_TYPE_SPECIAL:
8606 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8611 + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) {
8612 + /* Could not create the object header, fail the creation */
8613 + yaffs_DeleteObject(in);
8617 + yaffs_UpdateParent(parent);
8623 -/*yaffs_FlushEntireDeviceCache(dev)
8628 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
8629 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
8630 + __u32 mode, __u32 uid, __u32 gid)
8632 - yaffs_Object *obj;
8633 - int nCaches = dev->nShortOpCaches;
8636 - /* Find a dirty object in the cache and flush it...
8637 - * until there are no further dirty objects.
8641 - for (i = 0; i < nCaches && !obj; i++) {
8642 - if (dev->srCache[i].object &&
8643 - dev->srCache[i].dirty)
8644 - obj = dev->srCache[i].object;
8648 - yaffs_FlushFilesChunkCache(obj);
8649 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
8650 + uid, gid, NULL, NULL, 0);
8654 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
8655 + __u32 mode, __u32 uid, __u32 gid)
8657 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
8658 + mode, uid, gid, NULL, NULL, 0);
8661 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
8662 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
8664 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
8665 + uid, gid, NULL, NULL, rdev);
8668 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
8669 + __u32 mode, __u32 uid, __u32 gid,
8670 + const YCHAR *alias)
8672 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
8673 + uid, gid, NULL, alias, 0);
8676 -/* Grab us a cache chunk for use.
8677 - * First look for an empty one.
8678 - * Then look for the least recently used non-dirty one.
8679 - * Then look for the least recently used dirty one...., flush and look again.
8681 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
8682 +/* yaffs_Link returns the object id of the equivalent object.*/
8683 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
8684 + yaffs_Object *equivalentObject)
8687 + /* Get the real object in case we were fed a hard link as an equivalent object */
8688 + equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
8690 - if (dev->nShortOpCaches > 0) {
8691 - for (i = 0; i < dev->nShortOpCaches; i++) {
8692 - if (!dev->srCache[i].object)
8693 - return &dev->srCache[i];
8695 + if (yaffs_MknodObject
8696 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
8697 + equivalentObject, NULL, 0)) {
8698 + return equivalentObject;
8706 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
8707 +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
8708 + const YCHAR *newName, int force, int shadows)
8710 - yaffs_ChunkCache *cache;
8711 - yaffs_Object *theObj;
8716 - if (dev->nShortOpCaches > 0) {
8717 - /* Try find a non-dirty one... */
8721 - cache = yaffs_GrabChunkCacheWorker(dev);
8722 + yaffs_Object *existingTarget;
8725 - /* They were all dirty, find the last recently used object and flush
8726 - * its cache, then find again.
8727 - * NB what's here is not very accurate, we actually flush the object
8728 - * the last recently used page.
8730 + if (newDir == NULL)
8731 + newDir = obj->parent; /* use the old directory */
8733 - /* With locking we can't assume we can use entry zero */
8734 + if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
8735 + T(YAFFS_TRACE_ALWAYS,
8737 + ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
8746 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
8747 + if (obj->myDev->param.isYaffs2)
8748 + unlinkOp = (newDir == obj->myDev->unlinkedDir);
8750 + unlinkOp = (newDir == obj->myDev->unlinkedDir
8751 + && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
8753 - for (i = 0; i < dev->nShortOpCaches; i++) {
8754 - if (dev->srCache[i].object &&
8755 - !dev->srCache[i].locked &&
8756 - (dev->srCache[i].lastUse < usage || !cache)) {
8757 - usage = dev->srCache[i].lastUse;
8758 - theObj = dev->srCache[i].object;
8759 - cache = &dev->srCache[i];
8763 + deleteOp = (newDir == obj->myDev->deletedDir);
8765 - if (!cache || cache->dirty) {
8766 - /* Flush and try again */
8767 - yaffs_FlushFilesChunkCache(theObj);
8768 - cache = yaffs_GrabChunkCacheWorker(dev);
8770 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8776 + /* If the object is a file going into the unlinked directory,
8777 + * then it is OK to just stuff it in since duplicate names are allowed.
8778 + * else only proceed if the new name does not exist and if we're putting
8779 + * it into a directory.
8785 + !existingTarget) &&
8786 + newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
8787 + yaffs_SetObjectName(obj, newName);
8791 + yaffs_AddObjectToDirectory(newDir, obj);
8793 -/* Find a cached chunk */
8794 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
8797 - yaffs_Device *dev = obj->myDev;
8799 - if (dev->nShortOpCaches > 0) {
8800 - for (i = 0; i < dev->nShortOpCaches; i++) {
8801 - if (dev->srCache[i].object == obj &&
8802 - dev->srCache[i].chunkId == chunkId) {
8805 + obj->unlinked = 1;
8807 - return &dev->srCache[i];
8810 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
8811 + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0)
8816 + return YAFFS_FAIL;
8819 -/* Mark the chunk for the least recently used algorithym */
8820 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
8822 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
8823 + yaffs_Object *newDir, const YCHAR *newName)
8825 + yaffs_Object *obj = NULL;
8826 + yaffs_Object *existingTarget = NULL;
8829 + yaffs_Device *dev;
8831 - if (dev->nShortOpCaches > 0) {
8832 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
8833 - /* Reset the cache usages */
8835 - for (i = 1; i < dev->nShortOpCaches; i++)
8836 - dev->srCache[i].lastUse = 0;
8838 - dev->srLastUse = 0;
8840 + if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8842 + if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8846 + dev = oldDir->myDev;
8848 - cache->lastUse = dev->srLastUse;
8849 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
8850 + /* Special case for case insemsitive systems (eg. WinCE).
8851 + * While look-up is case insensitive, the name isn't.
8852 + * Therefore we might want to change x.txt to X.txt
8854 + if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
8862 + if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
8863 + /* ENAMETOOLONG */
8864 + return YAFFS_FAIL;
8866 -/* Invalidate a single cache page.
8867 - * Do this when a whole page gets written,
8868 - * ie the short cache for this page is no longer valid.
8870 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
8872 - if (object->myDev->nShortOpCaches > 0) {
8873 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
8874 + obj = yaffs_FindObjectByName(oldDir, oldName);
8877 - cache->object = NULL;
8880 + if (obj && obj->renameAllowed) {
8882 -/* Invalidate all the cache pages associated with this object
8883 - * Do this whenever ther file is deleted or resized.
8885 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
8888 - yaffs_Device *dev = in->myDev;
8889 + /* Now do the handling for an existing target, if there is one */
8891 - if (dev->nShortOpCaches > 0) {
8892 - /* Invalidate it. */
8893 - for (i = 0; i < dev->nShortOpCaches; i++) {
8894 - if (dev->srCache[i].object == in)
8895 - dev->srCache[i].object = NULL;
8896 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8897 + if (existingTarget &&
8898 + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
8899 + !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
8900 + /* There is a target that is a non-empty directory, so we fail */
8901 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
8902 + } else if (existingTarget && existingTarget != obj) {
8903 + /* Nuke the target first, using shadowing,
8904 + * but only if it isn't the same object.
8906 + * Note we must disable gc otherwise it can mess up the shadowing.
8910 + yaffs_ChangeObjectName(obj, newDir, newName, force,
8911 + existingTarget->objectId);
8912 + existingTarget->isShadowed = 1;
8913 + yaffs_UnlinkObject(existingTarget);
8917 + result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
8919 + yaffs_UpdateParent(oldDir);
8920 + if(newDir != oldDir)
8921 + yaffs_UpdateParent(newDir);
8925 + return YAFFS_FAIL;
8928 -/*--------------------- Checkpointing --------------------*/
8930 +/*------------------------- Block Management and Page Allocation ----------------*/
8932 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
8933 +static int yaffs_InitialiseBlocks(yaffs_Device *dev)
8935 - yaffs_CheckpointValidity cp;
8936 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
8938 - memset(&cp, 0, sizeof(cp));
8939 + dev->blockInfo = NULL;
8940 + dev->chunkBits = NULL;
8942 - cp.structType = sizeof(cp);
8943 - cp.magic = YAFFS_MAGIC;
8944 - cp.version = YAFFS_CHECKPOINT_VERSION;
8945 - cp.head = (head) ? 1 : 0;
8946 + dev->allocationBlock = -1; /* force it to get a new one */
8948 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
8951 + /* If the first allocation strategy fails, thry the alternate one */
8952 + dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
8953 + if (!dev->blockInfo) {
8954 + dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
8955 + dev->blockInfoAlt = 1;
8957 + dev->blockInfoAlt = 0;
8959 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
8961 - yaffs_CheckpointValidity cp;
8963 + if (dev->blockInfo) {
8964 + /* Set up dynamic blockinfo stuff. */
8965 + dev->chunkBitmapStride = (dev->param.nChunksPerBlock + 7) / 8; /* round up bytes */
8966 + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
8967 + if (!dev->chunkBits) {
8968 + dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
8969 + dev->chunkBitsAlt = 1;
8971 + dev->chunkBitsAlt = 0;
8974 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
8975 + if (dev->blockInfo && dev->chunkBits) {
8976 + memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
8977 + memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
8982 - ok = (cp.structType == sizeof(cp)) &&
8983 - (cp.magic == YAFFS_MAGIC) &&
8984 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
8985 - (cp.head == ((head) ? 1 : 0));
8986 - return ok ? 1 : 0;
8987 + return YAFFS_FAIL;
8990 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
8991 - yaffs_Device *dev)
8992 +static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
8994 - cp->nErasedBlocks = dev->nErasedBlocks;
8995 - cp->allocationBlock = dev->allocationBlock;
8996 - cp->allocationPage = dev->allocationPage;
8997 - cp->nFreeChunks = dev->nFreeChunks;
8998 + if (dev->blockInfoAlt && dev->blockInfo)
8999 + YFREE_ALT(dev->blockInfo);
9000 + else if (dev->blockInfo)
9001 + YFREE(dev->blockInfo);
9003 + dev->blockInfoAlt = 0;
9005 - cp->nDeletedFiles = dev->nDeletedFiles;
9006 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9007 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9008 - cp->sequenceNumber = dev->sequenceNumber;
9009 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9010 + dev->blockInfo = NULL;
9012 + if (dev->chunkBitsAlt && dev->chunkBits)
9013 + YFREE_ALT(dev->chunkBits);
9014 + else if (dev->chunkBits)
9015 + YFREE(dev->chunkBits);
9016 + dev->chunkBitsAlt = 0;
9017 + dev->chunkBits = NULL;
9020 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9021 - yaffs_CheckpointDevice *cp)
9022 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
9024 - dev->nErasedBlocks = cp->nErasedBlocks;
9025 - dev->allocationBlock = cp->allocationBlock;
9026 - dev->allocationPage = cp->allocationPage;
9027 - dev->nFreeChunks = cp->nFreeChunks;
9028 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
9030 - dev->nDeletedFiles = cp->nDeletedFiles;
9031 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9032 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9033 - dev->sequenceNumber = cp->sequenceNumber;
9034 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9038 + /* If the block is still healthy erase it and mark as clean.
9039 + * If the block has had a data failure, then retire it.
9042 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9044 - yaffs_CheckpointDevice cp;
9046 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9047 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9048 + (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
9049 + blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
9052 + yaffs2_ClearOldestDirtySequence(dev,bi);
9054 - /* Write device runtime values*/
9055 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9056 - cp.structType = sizeof(cp);
9057 + bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
9059 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9060 + /* If this is the block being garbage collected then stop gc'ing this block */
9061 + if(blockNo == dev->gcBlock)
9064 + /* If this block is currently the best candidate for gc then drop as a candidate */
9065 + if(blockNo == dev->gcDirtiest){
9066 + dev->gcDirtiest = 0;
9067 + dev->gcPagesInUse = 0;
9070 - /* Write block info */
9072 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9073 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9074 + if (!bi->needsRetiring) {
9075 + yaffs2_InvalidateCheckpoint(dev);
9076 + erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
9078 + dev->nErasureFailures++;
9079 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9080 + (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
9084 - /* Write chunk bits */
9086 - nBytes = nBlocks * dev->chunkBitmapStride;
9087 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9089 + ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
9091 + for (i = 0; i < dev->param.nChunksPerBlock; i++) {
9092 + if (!yaffs_CheckChunkErased
9093 + (dev, blockNo * dev->param.nChunksPerBlock + i)) {
9094 + T(YAFFS_TRACE_ERROR,
9096 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9097 + TENDSTR), blockNo, i));
9101 - return ok ? 1 : 0;
9104 + /* Clean it up... */
9105 + bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
9106 + bi->sequenceNumber = 0;
9107 + dev->nErasedBlocks++;
9108 + bi->pagesInUse = 0;
9109 + bi->softDeletions = 0;
9110 + bi->hasShrinkHeader = 0;
9111 + bi->skipErasedCheck = 1; /* This is clean, so no need to check */
9112 + bi->gcPrioritise = 0;
9113 + yaffs_ClearChunkBits(dev, blockNo);
9115 + T(YAFFS_TRACE_ERASE,
9116 + (TSTR("Erased block %d" TENDSTR), blockNo));
9118 + dev->nFreeChunks -= dev->param.nChunksPerBlock; /* We lost a block of free space */
9120 + yaffs_RetireBlock(dev, blockNo);
9121 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9122 + (TSTR("**>> Block %d retired" TENDSTR), blockNo));
9126 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9127 +static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
9129 - yaffs_CheckpointDevice cp;
9131 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9136 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9139 + yaffs_BlockInfo *bi;
9141 - if (cp.structType != sizeof(cp))
9143 + if (dev->nErasedBlocks < 1) {
9144 + /* Hoosterman we've got a problem.
9145 + * Can't get space to gc
9147 + T(YAFFS_TRACE_ERROR,
9148 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9153 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9154 + /* Find an empty block. */
9156 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9157 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
9158 + dev->allocationBlockFinder++;
9159 + if (dev->allocationBlockFinder < dev->internalStartBlock
9160 + || dev->allocationBlockFinder > dev->internalEndBlock) {
9161 + dev->allocationBlockFinder = dev->internalStartBlock;
9164 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9165 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
9169 - nBytes = nBlocks * dev->chunkBitmapStride;
9170 + if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
9171 + bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
9172 + dev->sequenceNumber++;
9173 + bi->sequenceNumber = dev->sequenceNumber;
9174 + dev->nErasedBlocks--;
9175 + T(YAFFS_TRACE_ALLOCATE,
9176 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9177 + dev->allocationBlockFinder, dev->sequenceNumber,
9178 + dev->nErasedBlocks));
9179 + return dev->allocationBlockFinder;
9183 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9184 + T(YAFFS_TRACE_ALWAYS,
9186 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9187 + TENDSTR), dev->nErasedBlocks));
9189 - return ok ? 1 : 0;
9193 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9194 - yaffs_Object *obj)
9197 + * Check if there's space to allocate...
9198 + * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
9200 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks)
9202 + int reservedChunks;
9203 + int reservedBlocks = dev->param.nReservedBlocks;
9204 + int checkpointBlocks;
9206 - cp->objectId = obj->objectId;
9207 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9208 - cp->hdrChunk = obj->hdrChunk;
9209 - cp->variantType = obj->variantType;
9210 - cp->deleted = obj->deleted;
9211 - cp->softDeleted = obj->softDeleted;
9212 - cp->unlinked = obj->unlinked;
9213 - cp->fake = obj->fake;
9214 - cp->renameAllowed = obj->renameAllowed;
9215 - cp->unlinkAllowed = obj->unlinkAllowed;
9216 - cp->serial = obj->serial;
9217 - cp->nDataChunks = obj->nDataChunks;
9218 + checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev);
9220 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9221 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9222 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9223 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9224 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
9226 + return (dev->nFreeChunks > (reservedChunks + nChunks));
9229 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9230 +static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
9231 + yaffs_BlockInfo **blockUsedPtr)
9234 + yaffs_BlockInfo *bi;
9236 - yaffs_Object *parent;
9237 + if (dev->allocationBlock < 0) {
9238 + /* Get next block to allocate off */
9239 + dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
9240 + dev->allocationPage = 0;
9243 - if (obj->variantType != cp->variantType) {
9244 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9245 - TCONT("chunk %d does not match existing object type %d")
9246 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9247 - obj->variantType));
9249 + if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) {
9250 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9254 - obj->objectId = cp->objectId;
9255 + if (dev->nErasedBlocks < dev->param.nReservedBlocks
9256 + && dev->allocationPage == 0) {
9257 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9261 - parent = yaffs_FindOrCreateObjectByNumber(
9264 - YAFFS_OBJECT_TYPE_DIRECTORY);
9267 + /* Next page please.... */
9268 + if (dev->allocationBlock >= 0) {
9269 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9272 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9273 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9274 - TCONT(" chunk %d Parent type, %d, not directory")
9276 - cp->objectId, cp->parentId, cp->variantType,
9277 - cp->hdrChunk, parent->variantType));
9280 - yaffs_AddObjectToDirectory(parent, obj);
9282 + retVal = (dev->allocationBlock * dev->param.nChunksPerBlock) +
9283 + dev->allocationPage;
9285 + yaffs_SetChunkBit(dev, dev->allocationBlock,
9286 + dev->allocationPage);
9288 - obj->hdrChunk = cp->hdrChunk;
9289 - obj->variantType = cp->variantType;
9290 - obj->deleted = cp->deleted;
9291 - obj->softDeleted = cp->softDeleted;
9292 - obj->unlinked = cp->unlinked;
9293 - obj->fake = cp->fake;
9294 - obj->renameAllowed = cp->renameAllowed;
9295 - obj->unlinkAllowed = cp->unlinkAllowed;
9296 - obj->serial = cp->serial;
9297 - obj->nDataChunks = cp->nDataChunks;
9298 + dev->allocationPage++;
9300 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9301 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9302 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9303 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9304 + dev->nFreeChunks--;
9306 - if (obj->hdrChunk > 0)
9307 - obj->lazyLoaded = 1;
9310 + /* If the block is full set the state to full */
9311 + if (dev->allocationPage >= dev->param.nChunksPerBlock) {
9312 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9313 + dev->allocationBlock = -1;
9317 + *blockUsedPtr = bi;
9322 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9323 - __u32 level, int chunkOffset)
9326 - yaffs_Device *dev = in->myDev;
9328 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9329 + T(YAFFS_TRACE_ERROR,
9330 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9332 - if (tnodeSize < sizeof(yaffs_Tnode))
9333 - tnodeSize = sizeof(yaffs_Tnode);
9337 +static int yaffs_GetErasedChunks(yaffs_Device *dev)
9343 + n = dev->nErasedBlocks * dev->param.nChunksPerBlock;
9345 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9346 - if (tn->internal[i]) {
9347 - ok = yaffs_CheckpointTnodeWorker(in,
9350 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9353 - } else if (level == 0) {
9354 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9355 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9357 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9360 + if (dev->allocationBlock > 0)
9361 + n += (dev->param.nChunksPerBlock - dev->allocationPage);
9368 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9370 + * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
9371 + * if we don't want to write to it.
9373 +void yaffs_SkipRestOfBlock(yaffs_Device *dev)
9375 - __u32 endMarker = ~0;
9378 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9379 - ok = yaffs_CheckpointTnodeWorker(obj,
9380 - obj->variant.fileVariant.top,
9381 - obj->variant.fileVariant.topLevel,
9384 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
9385 - sizeof(endMarker));
9386 + if(dev->allocationBlock > 0){
9387 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9388 + if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
9389 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9390 + dev->allocationBlock = -1;
9394 - return ok ? 1 : 0;
9397 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
9401 - yaffs_Device *dev = obj->myDev;
9402 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
9405 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9407 - if (tnodeSize < sizeof(yaffs_Tnode))
9408 - tnodeSize = sizeof(yaffs_Tnode);
9409 +static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
9415 + int retVal = YAFFS_OK;
9417 + int isCheckpointBlock;
9418 + int matchingChunk;
9421 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9422 + int chunksBefore = yaffs_GetErasedChunks(dev);
9425 - while (ok && (~baseChunk)) {
9427 - /* Read level 0 tnode */
9428 + yaffs_ExtendedTags tags;
9430 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
9432 - tn = yaffs_GetTnodeRaw(dev);
9434 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
9437 + yaffs_Object *object;
9440 - ok = yaffs_AddOrFindLevel0Tnode(dev,
9444 + isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
9447 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9450 + T(YAFFS_TRACE_TRACING,
9451 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
9454 + bi->hasShrinkHeader,
9457 - T(YAFFS_TRACE_CHECKPOINT, (
9458 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
9459 - nread, baseChunk, ok));
9460 + /*yaffs_VerifyFreeChunks(dev); */
9462 - return ok ? 1 : 0;
9464 + if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
9465 + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
9467 + bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
9469 + dev->gcDisable = 1;
9471 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
9473 - yaffs_Object *obj;
9474 - yaffs_CheckpointObject cp;
9477 - struct ylist_head *lh;
9478 + if (isCheckpointBlock ||
9479 + !yaffs_StillSomeChunkBits(dev, block)) {
9480 + T(YAFFS_TRACE_TRACING,
9482 + ("Collecting block %d that has no chunks in use" TENDSTR),
9484 + yaffs_BlockBecameDirty(dev, block);
9487 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
9489 - /* Iterate through the objects in each hash entry,
9490 - * dumping them to the checkpointing stream.
9492 + yaffs_VerifyBlock(dev, bi, block);
9494 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
9495 - ylist_for_each(lh, &dev->objectBucket[i].list) {
9497 - obj = ylist_entry(lh, yaffs_Object, hashLink);
9498 - if (!obj->deferedFree) {
9499 - yaffs_ObjectToCheckpointObject(&cp, obj);
9500 - cp.structType = sizeof(cp);
9502 - T(YAFFS_TRACE_CHECKPOINT, (
9503 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
9504 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
9505 + maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5;
9506 + oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk;
9508 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9509 + for (/* init already done */;
9510 + retVal == YAFFS_OK &&
9511 + dev->gcChunk < dev->param.nChunksPerBlock &&
9512 + (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
9514 + dev->gcChunk++, oldChunk++) {
9515 + if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
9517 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9518 - ok = yaffs_WriteCheckpointTnodes(obj);
9523 + /* This page is in use and might need to be copied off */
9525 - /* Dump end of list */
9526 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
9527 - cp.structType = sizeof(cp);
9531 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9534 - return ok ? 1 : 0;
9536 + yaffs_InitialiseTags(&tags);
9538 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
9540 - yaffs_Object *obj;
9541 - yaffs_CheckpointObject cp;
9544 - yaffs_Object *hardList = NULL;
9545 + yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
9548 - while (ok && !done) {
9549 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9550 - if (cp.structType != sizeof(cp)) {
9551 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
9552 - cp.structType, sizeof(cp), ok));
9556 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
9557 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
9559 - if (ok && cp.objectId == ~0)
9562 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
9564 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
9567 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9568 - ok = yaffs_ReadCheckpointTnodes(obj);
9569 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
9570 - obj->hardLinks.next =
9571 - (struct ylist_head *) hardList;
9579 + yaffs_FindObjectByNumber(dev,
9583 - yaffs_HardlinkFixup(dev, hardList);
9584 + T(YAFFS_TRACE_GC_DETAIL,
9586 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
9587 + dev->gcChunk, tags.objectId, tags.chunkId,
9590 - return ok ? 1 : 0;
9592 + if (object && !yaffs_SkipVerification(dev)) {
9593 + if (tags.chunkId == 0)
9594 + matchingChunk = object->hdrChunk;
9595 + else if (object->softDeleted)
9596 + matchingChunk = oldChunk; /* Defeat the test */
9598 + matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
9600 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
9602 - __u32 checkpointSum;
9604 + if (oldChunk != matchingChunk)
9605 + T(YAFFS_TRACE_ERROR,
9606 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
9607 + oldChunk, matchingChunk, tags.objectId, tags.chunkId));
9609 - yaffs_GetCheckpointSum(dev, &checkpointSum);
9612 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
9614 + T(YAFFS_TRACE_ERROR,
9616 + ("page %d in gc has no object: %d %d %d "
9617 + TENDSTR), oldChunk,
9618 + tags.objectId, tags.chunkId, tags.byteCount));
9624 + object->deleted &&
9625 + object->softDeleted &&
9626 + tags.chunkId != 0) {
9627 + /* Data chunk in a soft deleted file, throw it away
9628 + * It's a soft deleted data chunk,
9629 + * No need to copy this, just forget about it and
9630 + * fix up the object.
9633 + /* Free chunks already includes softdeleted chunks.
9634 + * How ever this chunk is going to soon be really deleted
9635 + * which will increment free chunks.
9636 + * We have to decrement free chunks so this works out properly.
9638 + dev->nFreeChunks--;
9639 + bi->softDeletions--;
9643 + object->nDataChunks--;
9645 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
9647 - __u32 checkpointSum0;
9648 - __u32 checkpointSum1;
9650 + if (object->nDataChunks <= 0) {
9651 + /* remeber to clean up the object */
9652 + dev->gcCleanupList[dev->nCleanups] =
9658 + /* Todo object && object->deleted && object->nDataChunks == 0 */
9659 + /* Deleted object header with no data chunks.
9660 + * Can be discarded and the file deleted.
9662 + object->hdrChunk = 0;
9663 + yaffs_FreeTnode(object->myDev,
9666 + object->variant.fileVariant.top = NULL;
9667 + yaffs_DoGenericObjectDeletion(object);
9669 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
9670 + } else if (object) {
9671 + /* It's either a data chunk in a live file or
9672 + * an ObjectHeader, so we're interested in it.
9673 + * NB Need to keep the ObjectHeaders of deleted files
9674 + * until the whole file has been deleted off
9676 + tags.serialNumber++;
9678 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
9683 + if (tags.chunkId == 0) {
9684 + /* It is an object Id,
9685 + * We need to nuke the shrinkheader flags first
9686 + * Also need to clean up shadowing.
9687 + * We no longer want the shrinkHeader flag since its work is done
9688 + * and if it is left in place it will mess up scanning.
9691 - if (checkpointSum0 != checkpointSum1)
9693 + yaffs_ObjectHeader *oh;
9694 + oh = (yaffs_ObjectHeader *)buffer;
9699 + tags.extraIsShrinkHeader = 0;
9701 + oh->shadowsObject = 0;
9702 + oh->inbandShadowsObject = 0;
9703 + tags.extraShadows = 0;
9705 + /* Update file size */
9706 + if(object->variantType == YAFFS_OBJECT_TYPE_FILE){
9707 + oh->fileSize = object->variant.fileVariant.fileSize;
9708 + tags.extraFileLength = oh->fileSize;
9711 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
9714 + yaffs_VerifyObjectHeader(object, oh, &tags, 1);
9716 + yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1);
9719 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
9721 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
9722 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
9725 + if (newChunk < 0) {
9726 + retVal = YAFFS_FAIL;
9730 - ok = yaffs_CheckpointOpen(dev, 1);
9731 + /* Ok, now fix up the Tnodes etc. */
9734 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9735 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
9738 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
9739 - ok = yaffs_WriteCheckpointDevice(dev);
9742 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
9743 - ok = yaffs_WriteCheckpointObjects(dev);
9746 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9747 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
9749 + if (tags.chunkId == 0) {
9750 + /* It's a header */
9751 + object->hdrChunk = newChunk;
9752 + object->serial = tags.serialNumber;
9754 + /* It's a data chunk */
9756 + ok = yaffs_PutChunkIntoFile
9765 - ok = yaffs_WriteCheckpointSum(dev);
9766 + if (retVal == YAFFS_OK)
9767 + yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
9769 - if (!yaffs_CheckpointClose(dev))
9775 - dev->isCheckpointed = 1;
9777 - dev->isCheckpointed = 0;
9778 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9780 - return dev->isCheckpointed;
9783 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
9787 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
9788 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
9793 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
9796 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9797 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
9800 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
9801 - ok = yaffs_ReadCheckpointDevice(dev);
9804 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
9805 - ok = yaffs_ReadCheckpointObjects(dev);
9808 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9809 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
9811 + yaffs_VerifyCollectedBlock(dev, bi, block);
9814 - ok = yaffs_ReadCheckpointSum(dev);
9815 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
9818 - if (!yaffs_CheckpointClose(dev))
9822 - dev->isCheckpointed = 1;
9824 - dev->isCheckpointed = 0;
9825 + if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
9827 + * The gc did not complete. Set block state back to FULL
9828 + * because checkpointing does not restore gc.
9830 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9832 + /* The gc completed. */
9833 + /* Do any required cleanups */
9834 + for (i = 0; i < dev->nCleanups; i++) {
9835 + /* Time to delete the file too */
9837 + yaffs_FindObjectByNumber(dev,
9838 + dev->gcCleanupList[i]);
9840 + yaffs_FreeTnode(dev,
9841 + object->variant.fileVariant.
9843 + object->variant.fileVariant.top = NULL;
9846 + ("yaffs: About to finally delete object %d"
9847 + TENDSTR), object->objectId));
9848 + yaffs_DoGenericObjectDeletion(object);
9849 + object->myDev->nDeletedFiles--;
9852 - return ok ? 1 : 0;
9857 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
9859 - if (dev->isCheckpointed ||
9860 - dev->blocksInCheckpoint > 0) {
9861 - dev->isCheckpointed = 0;
9862 - yaffs_CheckpointInvalidateStream(dev);
9863 - if (dev->superBlock && dev->markSuperBlockDirty)
9864 - dev->markSuperBlockDirty(dev->superBlock);
9865 + chunksAfter = yaffs_GetErasedChunks(dev);
9866 + if (chunksBefore >= chunksAfter) {
9869 + ("gc did not increase free chunks before %d after %d"
9870 + TENDSTR), chunksBefore, chunksAfter));
9874 + dev->nCleanups = 0;
9878 + dev->gcDisable = 0;
9880 -int yaffs_CheckpointSave(yaffs_Device *dev)
9883 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9887 - yaffs_VerifyObjects(dev);
9888 - yaffs_VerifyBlocks(dev);
9889 - yaffs_VerifyFreeChunks(dev);
9891 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
9892 + * for garbage collection.
9895 - if (!dev->isCheckpointed) {
9896 - yaffs_InvalidateCheckpoint(dev);
9897 - yaffs_WriteCheckpointData(dev);
9899 +static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
9905 + unsigned selected = 0;
9906 + int prioritised = 0;
9907 + int prioritisedExists = 0;
9908 + yaffs_BlockInfo *bi;
9911 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9912 + /* First let's see if we need to grab a prioritised block */
9913 + if (dev->hasPendingPrioritisedGCs && !aggressive) {
9914 + dev->gcDirtiest = 0;
9915 + bi = dev->blockInfo;
9916 + for (i = dev->internalStartBlock;
9917 + i <= dev->internalEndBlock && !selected;
9920 - return dev->isCheckpointed;
9922 + if (bi->gcPrioritise) {
9923 + prioritisedExists = 1;
9924 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
9925 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
9933 -int yaffs_CheckpointRestore(yaffs_Device *dev)
9936 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9938 + * If there is a prioritised block and none was selected then
9939 + * this happened because there is at least one old dirty block gumming
9940 + * up the works. Let's gc the oldest dirty block.
9943 - retval = yaffs_ReadCheckpointData(dev);
9944 + if(prioritisedExists &&
9946 + dev->oldestDirtyBlock > 0)
9947 + selected = dev->oldestDirtyBlock;
9949 - if (dev->isCheckpointed) {
9950 - yaffs_VerifyObjects(dev);
9951 - yaffs_VerifyBlocks(dev);
9952 - yaffs_VerifyFreeChunks(dev);
9953 + if (!prioritisedExists) /* None found, so we can clear this */
9954 + dev->hasPendingPrioritisedGCs = 0;
9957 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9958 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
9960 + * else (we're doing a leasurely gc), then we only bother to do this if the
9961 + * block has only a few pages in use.
9968 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
9970 + threshold = dev->param.nChunksPerBlock;
9971 + iterations = nBlocks;
9975 -/*--------------------- File read/write ------------------------
9976 - * Read and write have very similar structures.
9977 - * In general the read/write has three parts to it
9978 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
9979 - * Some complete chunks
9980 - * An incomplete chunk to end off with
9982 - * Curve-balls: the first chunk might also be the last chunk.
9985 + maxThreshold = dev->param.nChunksPerBlock/2;
9987 + maxThreshold = dev->param.nChunksPerBlock/8;
9989 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
9992 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
9993 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
10000 - yaffs_ChunkCache *cache;
10001 + threshold = background ?
10002 + (dev->gcNotDone + 2) * 2 : 0;
10003 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10004 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10005 + if(threshold > maxThreshold)
10006 + threshold = maxThreshold;
10008 - yaffs_Device *dev;
10009 + iterations = nBlocks / 16 + 1;
10010 + if (iterations > 100)
10011 + iterations = 100;
10016 + i < iterations &&
10017 + (dev->gcDirtiest < 1 ||
10018 + dev->gcPagesInUse > YAFFS_GC_GOOD_ENOUGH);
10020 + dev->gcBlockFinder++;
10021 + if (dev->gcBlockFinder < dev->internalStartBlock ||
10022 + dev->gcBlockFinder > dev->internalEndBlock)
10023 + dev->gcBlockFinder = dev->internalStartBlock;
10026 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10027 - /* start = offset % dev->nDataBytesPerChunk; */
10028 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10030 + bi = yaffs_GetBlockInfo(dev, dev->gcBlockFinder);
10032 - /* OK now check for the curveball where the start and end are in
10033 - * the same chunk.
10035 - if ((start + n) < dev->nDataBytesPerChunk)
10038 - nToCopy = dev->nDataBytesPerChunk - start;
10039 + pagesUsed = bi->pagesInUse - bi->softDeletions;
10041 - cache = yaffs_FindChunkCache(in, chunk);
10042 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
10043 + pagesUsed < dev->param.nChunksPerBlock &&
10044 + (dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) &&
10045 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
10046 + dev->gcDirtiest = dev->gcBlockFinder;
10047 + dev->gcPagesInUse = pagesUsed;
10051 - /* If the chunk is already in the cache or it is less than a whole chunk
10052 - * or we're using inband tags then use the cache (if there is caching)
10053 - * else bypass the cache.
10055 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10056 - if (dev->nShortOpCaches > 0) {
10057 + if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold)
10058 + selected = dev->gcDirtiest;
10062 + * If nothing has been selected for a while, try selecting the oldest dirty
10063 + * because that's gumming up the works.
10066 - /* If we can't find the data in the cache, then load it up. */
10067 + if(!selected && dev->param.isYaffs2 &&
10068 + dev->gcNotDone >= ( background ? 10 : 20)){
10069 + yaffs2_FindOldestDirtySequence(dev);
10070 + if(dev->oldestDirtyBlock > 0) {
10071 + selected = dev->oldestDirtyBlock;
10072 + dev->gcDirtiest = selected;
10073 + dev->oldestDirtyGCs++;
10074 + bi = yaffs_GetBlockInfo(dev, selected);
10075 + dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions;
10077 + dev->gcNotDone = 0;
10081 - cache = yaffs_GrabChunkCache(in->myDev);
10082 - cache->object = in;
10083 - cache->chunkId = chunk;
10084 - cache->dirty = 0;
10085 - cache->locked = 0;
10086 - yaffs_ReadChunkDataFromObject(in, chunk,
10089 - cache->nBytes = 0;
10092 + T(YAFFS_TRACE_GC,
10093 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10095 + dev->param.nChunksPerBlock - dev->gcPagesInUse,
10098 + dev->nGCBlocks++;
10100 + dev->backgroundGCs++;
10102 + dev->gcDirtiest = 0;
10103 + dev->gcPagesInUse = 0;
10104 + dev->gcNotDone = 0;
10105 + if(dev->refreshSkip > 0)
10106 + dev->refreshSkip--;
10108 + dev->gcNotDone++;
10109 + T(YAFFS_TRACE_GC,
10110 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10111 + dev->gcBlockFinder, dev->gcNotDone,
10113 + dev->gcDirtiest, dev->gcPagesInUse,
10114 + dev->oldestDirtyBlock,
10115 + background ? " bg" : ""));
10118 - yaffs_UseChunkCache(dev, cache, 0);
10122 - cache->locked = 1;
10123 +/* New garbage collector
10124 + * If we're very low on erased blocks then we do aggressive garbage collection
10125 + * otherwise we do "leasurely" garbage collection.
10126 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10127 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10129 + * The idea is to help clear out space in a more spread-out manner.
10130 + * Dunno if it really does anything useful.
10132 +static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
10134 + int aggressive = 0;
10135 + int gcOk = YAFFS_OK;
10136 + int maxTries = 0;
10138 + int erasedChunks;
10139 + int checkpointBlockAdjust;
10141 + if(dev->param.gcControl &&
10142 + (dev->param.gcControl(dev) & 1) == 0)
10145 - memcpy(buffer, &cache->data[start], nToCopy);
10146 + if (dev->gcDisable) {
10147 + /* Bail out so we don't get recursive gc */
10151 - cache->locked = 0;
10153 - /* Read into the local buffer then copy..*/
10154 + /* This loop should pass the first time.
10155 + * We'll only see looping here if the collection does not increase space.
10158 - __u8 *localBuffer =
10159 - yaffs_GetTempBuffer(dev, __LINE__);
10160 - yaffs_ReadChunkDataFromObject(in, chunk,
10165 - memcpy(buffer, &localBuffer[start], nToCopy);
10166 + checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev);
10168 + minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1;
10169 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10171 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10173 + /* If we need a block soon then do aggressive gc.*/
10174 + if (dev->nErasedBlocks < minErased)
10177 + if(!background && erasedChunks > (dev->nFreeChunks / 4))
10180 + if(dev->gcSkip > 20)
10181 + dev->gcSkip = 20;
10182 + if(erasedChunks < dev->nFreeChunks/2 ||
10183 + dev->gcSkip < 1 ||
10195 - /* A full chunk. Read directly into the supplied buffer. */
10196 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10197 + /* If we don't already have a block being gc'd then see if we should start another */
10199 + if (dev->gcBlock < 1 && !aggressive) {
10200 + dev->gcBlock = yaffs2_FindRefreshBlock(dev);
10201 + dev->gcChunk = 0;
10202 + dev->nCleanups=0;
10204 + if (dev->gcBlock < 1) {
10205 + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
10206 + dev->gcChunk = 0;
10207 + dev->nCleanups=0;
10211 - offset += nToCopy;
10212 - buffer += nToCopy;
10213 - nDone += nToCopy;
10214 + if (dev->gcBlock > 0) {
10217 + dev->passiveGCs++;
10220 + T(YAFFS_TRACE_GC,
10222 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10223 + dev->nErasedBlocks, aggressive));
10226 + gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive);
10229 + if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) {
10230 + T(YAFFS_TRACE_GC,
10232 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10233 + TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock));
10235 + } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) &&
10236 + (dev->gcBlock > 0) &&
10239 + return aggressive ? gcOk : YAFFS_OK;
10242 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10243 - int nBytes, int writeThrough)
10245 + * yaffs_BackgroundGarbageCollect()
10246 + * Garbage collects. Intended to be called from a background thread.
10247 + * Returns non-zero if at least half the free chunks are erased.
10249 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency)
10251 + int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10258 - int nToWriteBack;
10259 - int startOfWrite = offset;
10260 - int chunkWritten = 0;
10261 - __u32 nBytesRead;
10262 - __u32 chunkStart;
10263 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10265 - yaffs_Device *dev;
10266 + yaffs_CheckGarbageCollection(dev, 1);
10267 + return erasedChunks > dev->nFreeChunks/2;
10271 +/*------------------------- TAGS --------------------------------*/
10273 - while (n > 0 && chunkWritten >= 0) {
10274 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10275 - /* start = offset % dev->nDataBytesPerChunk; */
10276 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10277 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
10278 + int chunkInObject)
10280 + return (tags->chunkId == chunkInObject &&
10281 + tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
10283 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10284 - start >= dev->nDataBytesPerChunk) {
10285 - T(YAFFS_TRACE_ERROR, (
10286 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10288 - (int)offset, chunk, start));
10293 - /* OK now check for the curveball where the start and end are in
10294 - * the same chunk.
10297 - if ((start + n) < dev->nDataBytesPerChunk) {
10299 +/*-------------------- Data file manipulation -----------------*/
10301 - /* Now folks, to calculate how many bytes to write back....
10302 - * If we're overwriting and not writing to then end of file then
10303 - * we need to write back as much as was there before.
10305 +static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
10306 + yaffs_ExtendedTags *tags)
10308 + /*Get the Tnode, then get the level 0 offset chunk offset */
10310 + int theChunk = -1;
10311 + yaffs_ExtendedTags localTags;
10314 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10315 + yaffs_Device *dev = in->myDev;
10317 - if (chunkStart > in->variant.fileVariant.fileSize)
10318 - nBytesRead = 0; /* Past end of file */
10320 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10322 + /* Passed a NULL, so use our own tags space */
10323 + tags = &localTags;
10326 - if (nBytesRead > dev->nDataBytesPerChunk)
10327 - nBytesRead = dev->nDataBytesPerChunk;
10328 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10332 - (start + n)) ? nBytesRead : (start + n);
10334 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10336 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10339 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10346 - nToCopy = dev->nDataBytesPerChunk - start;
10347 - nToWriteBack = dev->nDataBytesPerChunk;
10349 +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
10350 + yaffs_ExtendedTags *tags)
10352 + /* Get the Tnode, then get the level 0 offset chunk offset */
10354 + int theChunk = -1;
10355 + yaffs_ExtendedTags localTags;
10357 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10358 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10359 - * or we're using inband tags, so we want to use the cache buffers.
10361 - if (dev->nShortOpCaches > 0) {
10362 - yaffs_ChunkCache *cache;
10363 - /* If we can't find the data in the cache, then load the cache */
10364 - cache = yaffs_FindChunkCache(in, chunk);
10365 + yaffs_Device *dev = in->myDev;
10369 - && yaffs_CheckSpaceForAllocation(in->
10371 - cache = yaffs_GrabChunkCache(in->myDev);
10372 - cache->object = in;
10373 - cache->chunkId = chunk;
10374 - cache->dirty = 0;
10375 - cache->locked = 0;
10376 - yaffs_ReadChunkDataFromObject(in, chunk,
10379 - } else if (cache &&
10381 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10382 - /* Drop the cache if it was a read cache item and
10383 - * no space check has been made for it.
10388 + /* Passed a NULL, so use our own tags space */
10389 + tags = &localTags;
10393 - yaffs_UseChunkCache(dev, cache, 1);
10394 - cache->locked = 1;
10395 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10399 - memcpy(&cache->data[start], buffer,
10401 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10404 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10407 - cache->locked = 0;
10408 - cache->nBytes = nToWriteBack;
10409 + /* Delete the entry in the filestructure (if found) */
10410 + if (retVal != -1)
10411 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
10414 - if (writeThrough) {
10416 - yaffs_WriteChunkDataToObject
10419 - cache->data, cache->nBytes,
10421 - cache->dirty = 0;
10427 - chunkWritten = -1; /* fail the write */
10430 - /* An incomplete start or end chunk (or maybe both start and end chunk)
10431 - * Read into the local buffer then copy, then copy over and write back.
10434 - __u8 *localBuffer =
10435 - yaffs_GetTempBuffer(dev, __LINE__);
10436 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
10437 + int chunkInNAND, int inScan)
10439 + /* NB inScan is zero unless scanning.
10440 + * For forward scanning, inScan is > 0;
10441 + * for backward scanning inScan is < 0
10443 + * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
10447 + yaffs_Device *dev = in->myDev;
10448 + int existingChunk;
10449 + yaffs_ExtendedTags existingTags;
10450 + yaffs_ExtendedTags newTags;
10451 + unsigned existingSerial, newSerial;
10453 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
10454 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
10455 + * If it is not during Scanning then something went wrong!
10458 + T(YAFFS_TRACE_ERROR,
10460 + ("yaffs tragedy:attempt to put data chunk into a non-file"
10465 - yaffs_ReadChunkDataFromObject(in, chunk,
10467 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
10471 + tn = yaffs_AddOrFindLevel0Tnode(dev,
10472 + &in->variant.fileVariant,
10476 + return YAFFS_FAIL;
10479 + /* Dummy insert, bail now */
10482 + existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10484 - memcpy(&localBuffer[start], buffer, nToCopy);
10485 + if (inScan != 0) {
10486 + /* If we're scanning then we need to test for duplicates
10487 + * NB This does not need to be efficient since it should only ever
10488 + * happen when the power fails during a write, then only one
10489 + * chunk should ever be affected.
10491 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
10492 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
10496 - yaffs_WriteChunkDataToObject(in, chunk,
10500 + if (existingChunk > 0) {
10501 + /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1
10502 + * thus we have to do a FindChunkInFile to get the real chunk id.
10504 + * We have a duplicate now we need to decide which one to use:
10506 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
10507 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
10508 + * YAFFS1: Get both sets of tags and compare serial numbers.
10511 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10513 + if (inScan > 0) {
10514 + /* Only do this for forward scanning */
10515 + yaffs_ReadChunkWithTagsFromNAND(dev,
10519 + /* Do a proper find */
10521 + yaffs_FindChunkInFile(in, chunkInInode,
10526 - /* A full chunk. Write directly from the supplied buffer. */
10527 + if (existingChunk <= 0) {
10528 + /*Hoosterman - how did this happen? */
10530 + T(YAFFS_TRACE_ERROR,
10532 + ("yaffs tragedy: existing chunk < 0 in scan"
10538 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
10539 - dev->nDataBytesPerChunk,
10541 + /* NB The deleted flags should be false, otherwise the chunks will
10542 + * not be loaded during a scan
10545 - /* Since we've overwritten the cached data, we better invalidate it. */
10546 - yaffs_InvalidateChunkCache(in, chunk);
10548 + if (inScan > 0) {
10549 + newSerial = newTags.serialNumber;
10550 + existingSerial = existingTags.serialNumber;
10553 - if (chunkWritten >= 0) {
10555 - offset += nToCopy;
10556 - buffer += nToCopy;
10557 - nDone += nToCopy;
10558 + if ((inScan > 0) &&
10559 + (existingChunk <= 0 ||
10560 + ((existingSerial + 1) & 3) == newSerial)) {
10561 + /* Forward scanning.
10563 + * Delete the old one and drop through to update the tnode
10565 + yaffs_DeleteChunk(dev, existingChunk, 1,
10568 + /* Backward scanning or we want to use the existing one
10570 + * Delete the new one and return early so that the tnode isn't changed
10572 + yaffs_DeleteChunk(dev, chunkInNAND, 1,
10580 - /* Update file object */
10582 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
10583 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
10584 + if (existingChunk == 0)
10585 + in->nDataChunks++;
10588 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
10594 +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
10597 + int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
10599 -/* ---------------------- File resizing stuff ------------------ */
10600 + if (chunkInNAND >= 0)
10601 + return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
10604 + T(YAFFS_TRACE_NANDACCESS,
10605 + (TSTR("Chunk %d not found zero instead" TENDSTR),
10607 + /* get sane (zero) data if you read a hole */
10608 + memset(buffer, 0, in->myDev->nDataBytesPerChunk);
10612 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
10616 - yaffs_Device *dev = in->myDev;
10617 - int oldFileSize = in->variant.fileVariant.fileSize;
10618 +void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
10622 + yaffs_ExtendedTags tags;
10623 + yaffs_BlockInfo *bi;
10625 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
10626 + if (chunkId <= 0)
10629 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
10630 - dev->nDataBytesPerChunk;
10633 + dev->nDeletions++;
10634 + block = chunkId / dev->param.nChunksPerBlock;
10635 + page = chunkId % dev->param.nChunksPerBlock;
10637 - /* Delete backwards so that we don't end up with holes if
10638 - * power is lost part-way through the operation.
10640 - for (i = lastDel; i >= startDel; i--) {
10641 - /* NB this could be optimised somewhat,
10642 - * eg. could retrieve the tags and write them without
10643 - * using yaffs_DeleteChunk
10646 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
10647 - if (chunkId > 0) {
10649 - (dev->internalStartBlock * dev->nChunksPerBlock)
10651 - ((dev->internalEndBlock +
10652 - 1) * dev->nChunksPerBlock)) {
10653 - T(YAFFS_TRACE_ALWAYS,
10654 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
10657 - in->nDataChunks--;
10658 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
10662 + if (!yaffs_CheckChunkBit(dev, block, page))
10663 + T(YAFFS_TRACE_VERIFY,
10664 + (TSTR("Deleting invalid chunk %d"TENDSTR),
10668 + bi = yaffs_GetBlockInfo(dev, block);
10670 + yaffs2_UpdateOldestDirtySequence(dev, block, bi);
10672 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
10674 + T(YAFFS_TRACE_DELETION,
10675 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
10677 - int oldFileSize = in->variant.fileVariant.fileSize;
10678 - __u32 newSizeOfPartialChunk;
10679 - int newFullChunks;
10680 + if (!dev->param.isYaffs2 && markNAND &&
10681 + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
10683 - yaffs_Device *dev = in->myDev;
10684 + yaffs_InitialiseTags(&tags);
10686 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
10687 + tags.chunkDeleted = 1;
10689 - yaffs_FlushFilesChunkCache(in);
10690 - yaffs_InvalidateWholeChunkCache(in);
10691 + yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
10692 + yaffs_HandleUpdateChunk(dev, chunkId, &tags);
10694 + dev->nUnmarkedDeletions++;
10697 - yaffs_CheckGarbageCollection(dev);
10698 + /* Pull out of the management area.
10699 + * If the whole block became dirty, this will kick off an erasure.
10701 + if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
10702 + bi->blockState == YAFFS_BLOCK_STATE_FULL ||
10703 + bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
10704 + bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
10705 + dev->nFreeChunks++;
10707 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
10708 - return YAFFS_FAIL;
10709 + yaffs_ClearChunkBit(dev, block, page);
10711 - if (newSize == oldFileSize)
10713 + bi->pagesInUse--;
10715 - if (newSize < oldFileSize) {
10716 + if (bi->pagesInUse == 0 &&
10717 + !bi->hasShrinkHeader &&
10718 + bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
10719 + bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
10720 + yaffs_BlockBecameDirty(dev, block);
10723 - yaffs_PruneResizedChunks(in, newSize);
10726 - if (newSizeOfPartialChunk != 0) {
10727 - int lastChunk = 1 + newFullChunks;
10730 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
10731 +static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
10732 + const __u8 *buffer, int nBytes,
10735 + /* Find old chunk Need to do this to get serial number
10736 + * Write new one and patch into tree.
10737 + * Invalidate old tags.
10740 - /* Got to read and rewrite the last chunk with its new size and zero pad */
10741 - yaffs_ReadChunkDataFromObject(in, lastChunk,
10744 + yaffs_ExtendedTags prevTags;
10746 - memset(localBuffer + newSizeOfPartialChunk, 0,
10747 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
10749 + yaffs_ExtendedTags newTags;
10751 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
10752 - newSizeOfPartialChunk, 1);
10753 + yaffs_Device *dev = in->myDev;
10755 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
10757 + yaffs_CheckGarbageCollection(dev,0);
10759 - in->variant.fileVariant.fileSize = newSize;
10760 + /* Get the previous chunk at this location in the file if it exists.
10761 + * If it does not exist then put a zero into the tree. This creates
10762 + * the tnode now, rather than later when it is harder to clean up.
10764 + prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
10765 + if(prevChunkId < 1 &&
10766 + !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0))
10769 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
10771 - /* newsSize > oldFileSize */
10772 - in->variant.fileVariant.fileSize = newSize;
10774 + /* Set up new tags */
10775 + yaffs_InitialiseTags(&newTags);
10777 + newTags.chunkId = chunkInInode;
10778 + newTags.objectId = in->objectId;
10779 + newTags.serialNumber =
10780 + (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
10781 + newTags.byteCount = nBytes;
10783 - /* Write a new object header.
10784 - * show we've shrunk the file, if need be
10785 - * Do this only if the file is not in the deleted directories.
10787 - if (in->parent &&
10788 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
10789 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
10790 - yaffs_UpdateObjectHeader(in, NULL, 0,
10791 - (newSize < oldFileSize) ? 1 : 0, 0);
10792 + if (nBytes < 1 || nBytes > dev->param.totalBytesPerChunk) {
10793 + T(YAFFS_TRACE_ERROR,
10794 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
10800 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
10805 + if (newChunkId > 0) {
10806 + yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
10808 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
10810 - obj = yaffs_GetEquivalentObject(obj);
10811 + if (prevChunkId > 0)
10812 + yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
10814 - switch (obj->variantType) {
10815 - case YAFFS_OBJECT_TYPE_FILE:
10816 - return obj->variant.fileVariant.fileSize;
10817 - case YAFFS_OBJECT_TYPE_SYMLINK:
10818 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
10821 + yaffs_VerifyFileSanity(in);
10823 + return newChunkId;
10827 +/* UpdateObjectHeader updates the header on NAND for an object.
10828 + * If name is not NULL, then that new name is used.
10830 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
10831 + int isShrink, int shadows, yaffs_XAttrMod *xmod)
10834 + yaffs_BlockInfo *bi;
10836 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
10840 - yaffs_FlushFilesChunkCache(in);
10841 - if (updateTime) {
10842 -#ifdef CONFIG_YAFFS_WINCE
10843 - yfsd_WinFileTimeNow(in->win_mtime);
10845 + yaffs_Device *dev = in->myDev;
10847 - in->yst_mtime = Y_CURRENT_TIME;
10855 + yaffs_ExtendedTags newTags;
10856 + yaffs_ExtendedTags oldTags;
10857 + const YCHAR *alias = NULL;
10859 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
10860 - 0) ? YAFFS_OK : YAFFS_FAIL;
10862 - retVal = YAFFS_OK;
10864 + __u8 *buffer = NULL;
10865 + YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
10868 + yaffs_ObjectHeader *oh = NULL;
10871 + yaffs_strcpy(oldName, _Y("silly old name"));
10873 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
10876 - /* First off, invalidate the file's data in the cache, without flushing. */
10877 - yaffs_InvalidateWholeChunkCache(in);
10879 + in == dev->rootDir || /* The rootDir should also be saved */
10882 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
10883 - /* Move to the unlinked directory so we have a record that it was deleted. */
10884 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
10885 + yaffs_CheckGarbageCollection(dev,0);
10886 + yaffs_CheckObjectDetailsLoaded(in);
10889 + buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
10890 + oh = (yaffs_ObjectHeader *) buffer;
10892 - yaffs_RemoveObjectFromDirectory(in);
10893 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
10894 - in->hdrChunk = 0;
10895 + prevChunkId = in->hdrChunk;
10897 - yaffs_FreeObject(in);
10899 + if (prevChunkId > 0) {
10900 + result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
10901 + buffer, &oldTags);
10904 + yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
10906 -/* yaffs_DeleteFile deletes the whole file data
10907 - * and the inode associated with the file.
10908 - * It does not delete the links associated with the file.
10910 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
10912 + memcpy(oldName, oh->name, sizeof(oh->name));
10913 + memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader));
10915 + memset(buffer, 0xFF, dev->nDataBytesPerChunk);
10918 - int immediateDeletion = 0;
10919 + oh->type = in->variantType;
10920 + oh->yst_mode = in->yst_mode;
10921 + oh->shadowsObject = oh->inbandShadowsObject = shadows;
10924 - if (!in->myInode)
10925 - immediateDeletion = 1;
10926 +#ifdef CONFIG_YAFFS_WINCE
10927 + oh->win_atime[0] = in->win_atime[0];
10928 + oh->win_ctime[0] = in->win_ctime[0];
10929 + oh->win_mtime[0] = in->win_mtime[0];
10930 + oh->win_atime[1] = in->win_atime[1];
10931 + oh->win_ctime[1] = in->win_ctime[1];
10932 + oh->win_mtime[1] = in->win_mtime[1];
10934 - if (in->inUse <= 0)
10935 - immediateDeletion = 1;
10936 + oh->yst_uid = in->yst_uid;
10937 + oh->yst_gid = in->yst_gid;
10938 + oh->yst_atime = in->yst_atime;
10939 + oh->yst_mtime = in->yst_mtime;
10940 + oh->yst_ctime = in->yst_ctime;
10941 + oh->yst_rdev = in->yst_rdev;
10944 + oh->parentObjectId = in->parent->objectId;
10946 + oh->parentObjectId = 0;
10948 - if (immediateDeletion) {
10950 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
10951 - _Y("deleted"), 0, 0);
10952 - T(YAFFS_TRACE_TRACING,
10953 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
10956 - in->myDev->nDeletedFiles++;
10957 - if (1 || in->myDev->isYaffs2)
10958 - yaffs_ResizeFile(in, 0);
10959 - yaffs_SoftDeleteFile(in);
10962 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
10963 - _Y("unlinked"), 0, 0);
10965 + if (name && *name) {
10966 + memset(oh->name, 0, sizeof(oh->name));
10967 + yaffs_LoadObjectHeaderFromName(dev,oh->name,name);
10968 + } else if (prevChunkId > 0)
10969 + memcpy(oh->name, oldName, sizeof(oh->name));
10971 + memset(oh->name, 0, sizeof(oh->name));
10973 + oh->isShrink = isShrink;
10977 + switch (in->variantType) {
10978 + case YAFFS_OBJECT_TYPE_UNKNOWN:
10979 + /* Should not happen */
10981 + case YAFFS_OBJECT_TYPE_FILE:
10983 + (oh->parentObjectId == YAFFS_OBJECTID_DELETED
10984 + || oh->parentObjectId ==
10985 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
10986 + fileVariant.fileSize;
10988 + case YAFFS_OBJECT_TYPE_HARDLINK:
10989 + oh->equivalentObjectId =
10990 + in->variant.hardLinkVariant.equivalentObjectId;
10992 + case YAFFS_OBJECT_TYPE_SPECIAL:
10995 + case YAFFS_OBJECT_TYPE_DIRECTORY:
10998 + case YAFFS_OBJECT_TYPE_SYMLINK:
10999 + alias = in->variant.symLinkVariant.alias;
11001 + alias = _Y("no alias");
11002 + yaffs_strncpy(oh->alias,
11004 + YAFFS_MAX_ALIAS_LENGTH);
11005 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11009 -int yaffs_DeleteFile(yaffs_Object *in)
11011 - int retVal = YAFFS_OK;
11012 - int deleted = in->deleted;
11013 + /* process any xattrib modifications */
11015 + yaffs_ApplyXMod(in, (char *)buffer, xmod);
11017 - yaffs_ResizeFile(in, 0);
11019 - if (in->nDataChunks > 0) {
11020 - /* Use soft deletion if there is data in the file.
11021 - * That won't be the case if it has been resized to zero.
11023 - if (!in->unlinked)
11024 - retVal = yaffs_UnlinkFileIfNeeded(in);
11026 + yaffs_InitialiseTags(&newTags);
11028 + newTags.chunkId = 0;
11029 + newTags.objectId = in->objectId;
11030 + newTags.serialNumber = in->serial;
11032 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11035 - in->myDev->nDeletedFiles++;
11036 - yaffs_SoftDeleteFile(in);
11038 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11040 - /* The file has no data chunks so we toss it immediately */
11041 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11042 - in->variant.fileVariant.top = NULL;
11043 - yaffs_DoGenericObjectDeletion(in);
11044 + /* Add extra info for file header */
11049 + newTags.extraHeaderInfoAvailable = 1;
11050 + newTags.extraParentObjectId = oh->parentObjectId;
11051 + newTags.extraFileLength = oh->fileSize;
11052 + newTags.extraIsShrinkHeader = oh->isShrink;
11053 + newTags.extraEquivalentObjectId = oh->equivalentObjectId;
11054 + newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
11055 + newTags.extraObjectType = in->variantType;
11057 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11059 - /* First check that the directory is empty. */
11060 - if (ylist_empty(&in->variant.directoryVariant.children))
11061 - return yaffs_DoGenericObjectDeletion(in);
11062 + yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
11064 - return YAFFS_FAIL;
11065 + /* Create new chunk in NAND */
11067 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
11068 + (prevChunkId > 0) ? 1 : 0);
11071 + if (newChunkId >= 0) {
11073 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11075 - YFREE(in->variant.symLinkVariant.alias);
11076 + in->hdrChunk = newChunkId;
11078 - return yaffs_DoGenericObjectDeletion(in);
11080 + if (prevChunkId > 0) {
11081 + yaffs_DeleteChunk(dev, prevChunkId, 1,
11085 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11087 - /* remove this hardlink from the list assocaited with the equivalent
11090 - ylist_del_init(&in->hardLinks);
11091 - return yaffs_DoGenericObjectDeletion(in);
11093 + if (!yaffs_ObjectHasCachedWriteData(in))
11096 + /* If this was a shrink, then mark the block that the chunk lives on */
11098 + bi = yaffs_GetBlockInfo(in->myDev,
11099 + newChunkId / in->myDev->param.nChunksPerBlock);
11100 + bi->hasShrinkHeader = 1;
11105 + retVal = newChunkId;
11107 -int yaffs_DeleteObject(yaffs_Object *obj)
11110 - switch (obj->variantType) {
11111 - case YAFFS_OBJECT_TYPE_FILE:
11112 - retVal = yaffs_DeleteFile(obj);
11114 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11115 - return yaffs_DeleteDirectory(obj);
11117 - case YAFFS_OBJECT_TYPE_SYMLINK:
11118 - retVal = yaffs_DeleteSymLink(obj);
11120 - case YAFFS_OBJECT_TYPE_HARDLINK:
11121 - retVal = yaffs_DeleteHardLink(obj);
11123 - case YAFFS_OBJECT_TYPE_SPECIAL:
11124 - retVal = yaffs_DoGenericObjectDeletion(obj);
11126 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11128 - break; /* should not happen. */
11132 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
11137 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11138 +/*------------------------ Short Operations Cache ----------------------------------------
11139 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11140 + * reads might be short sequential reads, and a lot of writes may be short
11141 + * sequential writes. eg. scanning/writing a jpeg file.
11142 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11143 + * with dumb-as-a-rock code.
11144 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11147 + * There are a limited number (~10) of cache chunks per device so that we don't
11148 + * need a very intelligent search.
11151 +static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
11153 + yaffs_Device *dev = obj->myDev;
11155 + yaffs_ChunkCache *cache;
11156 + int nCaches = obj->myDev->param.nShortOpCaches;
11158 - int immediateDeletion = 0;
11159 + for (i = 0; i < nCaches; i++) {
11160 + cache = &dev->srCache[i];
11161 + if (cache->object == obj &&
11167 - if (!obj->myInode)
11168 - immediateDeletion = 1;
11170 - if (obj->inUse <= 0)
11171 - immediateDeletion = 1;
11176 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11177 - return yaffs_DeleteHardLink(obj);
11178 - } else if (!ylist_empty(&obj->hardLinks)) {
11179 - /* Curve ball: We're unlinking an object that has a hardlink.
11181 - * This problem arises because we are not strictly following
11182 - * The Linux link/inode model.
11184 - * We can't really delete the object.
11185 - * Instead, we do the following:
11186 - * - Select a hardlink.
11187 - * - Unhook it from the hard links
11188 - * - Unhook it from its parent directory (so that the rename can work)
11189 - * - Rename the object to the hardlink's name.
11190 - * - Delete the hardlink
11193 - yaffs_Object *hl;
11195 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11196 +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
11198 + yaffs_Device *dev = obj->myDev;
11199 + int lowest = -99; /* Stop compiler whining. */
11201 + yaffs_ChunkCache *cache;
11202 + int chunkWritten = 0;
11203 + int nCaches = obj->myDev->param.nShortOpCaches;
11205 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11206 + if (nCaches > 0) {
11210 - ylist_del_init(&hl->hardLinks);
11211 - ylist_del_init(&hl->siblings);
11212 + /* Find the dirty cache for this object with the lowest chunk id. */
11213 + for (i = 0; i < nCaches; i++) {
11214 + if (dev->srCache[i].object == obj &&
11215 + dev->srCache[i].dirty) {
11217 + || dev->srCache[i].chunkId <
11219 + cache = &dev->srCache[i];
11220 + lowest = cache->chunkId;
11225 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11226 + if (cache && !cache->locked) {
11227 + /* Write it out and free it up */
11229 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11231 + yaffs_WriteChunkDataToObject(cache->object,
11236 + cache->dirty = 0;
11237 + cache->object = NULL;
11240 - if (retVal == YAFFS_OK)
11241 - retVal = yaffs_DoGenericObjectDeletion(hl);
11242 + } while (cache && chunkWritten > 0);
11246 + /* Hoosterman, disk full while writing cache out. */
11247 + T(YAFFS_TRACE_ERROR,
11248 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11250 - } else if (immediateDeletion) {
11251 - switch (obj->variantType) {
11252 - case YAFFS_OBJECT_TYPE_FILE:
11253 - return yaffs_DeleteFile(obj);
11255 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11256 - return yaffs_DeleteDirectory(obj);
11258 - case YAFFS_OBJECT_TYPE_SYMLINK:
11259 - return yaffs_DeleteSymLink(obj);
11261 - case YAFFS_OBJECT_TYPE_SPECIAL:
11262 - return yaffs_DoGenericObjectDeletion(obj);
11264 - case YAFFS_OBJECT_TYPE_HARDLINK:
11265 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11267 - return YAFFS_FAIL;
11270 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11271 - _Y("unlinked"), 0, 0);
11276 +/*yaffs_FlushEntireDeviceCache(dev)
11281 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11282 +void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
11284 + yaffs_Object *obj;
11285 + int nCaches = dev->param.nShortOpCaches;
11288 - if (obj && obj->unlinkAllowed)
11289 - return yaffs_UnlinkWorker(obj);
11290 + /* Find a dirty object in the cache and flush it...
11291 + * until there are no further dirty objects.
11295 + for (i = 0; i < nCaches && !obj; i++) {
11296 + if (dev->srCache[i].object &&
11297 + dev->srCache[i].dirty)
11298 + obj = dev->srCache[i].object;
11300 - return YAFFS_FAIL;
11303 + yaffs_FlushFilesChunkCache(obj);
11308 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11311 +/* Grab us a cache chunk for use.
11312 + * First look for an empty one.
11313 + * Then look for the least recently used non-dirty one.
11314 + * Then look for the least recently used dirty one...., flush and look again.
11316 +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
11318 - yaffs_Object *obj;
11321 - obj = yaffs_FindObjectByName(dir, name);
11322 - return yaffs_UnlinkObject(obj);
11324 + if (dev->param.nShortOpCaches > 0) {
11325 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11326 + if (!dev->srCache[i].object)
11327 + return &dev->srCache[i];
11331 -/*----------------------- Initialisation Scanning ---------------------- */
11335 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11336 - int backwardScanning)
11337 +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
11339 - yaffs_Object *obj;
11340 + yaffs_ChunkCache *cache;
11341 + yaffs_Object *theObj;
11346 - if (!backwardScanning) {
11347 - /* Handle YAFFS1 forward scanning case
11348 - * For YAFFS1 we always do the deletion
11350 + if (dev->param.nShortOpCaches > 0) {
11351 + /* Try find a non-dirty one... */
11354 - /* Handle YAFFS2 case (backward scanning)
11355 - * If the shadowed object exists then ignore.
11357 - if (yaffs_FindObjectByNumber(dev, objId))
11360 + cache = yaffs_GrabChunkCacheWorker(dev);
11362 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11363 - * We put it in unlinked dir to be cleaned up after the scanning
11366 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11367 - YAFFS_OBJECT_TYPE_FILE);
11370 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11371 - obj->variant.fileVariant.shrinkSize = 0;
11372 - obj->valid = 1; /* So that we don't read any other info for this file */
11374 + /* They were all dirty, find the last recently used object and flush
11375 + * its cache, then find again.
11376 + * NB what's here is not very accurate, we actually flush the object
11377 + * the last recently used page.
11381 + /* With locking we can't assume we can use entry zero */
11386 -} yaffs_BlockIndex;
11392 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11393 + if (dev->srCache[i].object &&
11394 + !dev->srCache[i].locked &&
11395 + (dev->srCache[i].lastUse < usage || !cache)) {
11396 + usage = dev->srCache[i].lastUse;
11397 + theObj = dev->srCache[i].object;
11398 + cache = &dev->srCache[i];
11403 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
11405 - yaffs_Object *hl;
11406 - yaffs_Object *in;
11407 + if (!cache || cache->dirty) {
11408 + /* Flush and try again */
11409 + yaffs_FlushFilesChunkCache(theObj);
11410 + cache = yaffs_GrabChunkCacheWorker(dev);
11413 - while (hardList) {
11415 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
11421 - in = yaffs_FindObjectByNumber(dev,
11422 - hl->variant.hardLinkVariant.
11423 - equivalentObjectId);
11427 - /* Add the hardlink pointers */
11428 - hl->variant.hardLinkVariant.equivalentObject = in;
11429 - ylist_add(&hl->hardLinks, &in->hardLinks);
11431 - /* Todo Need to report/handle this better.
11432 - * Got a problem... hardlink to a non-existant object
11434 - hl->variant.hardLinkVariant.equivalentObject = NULL;
11435 - YINIT_LIST_HEAD(&hl->hardLinks);
11436 +/* Find a cached chunk */
11437 +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
11440 + yaffs_Device *dev = obj->myDev;
11442 + if (dev->param.nShortOpCaches > 0) {
11443 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11444 + if (dev->srCache[i].object == obj &&
11445 + dev->srCache[i].chunkId == chunkId) {
11446 + dev->cacheHits++;
11448 + return &dev->srCache[i];
11455 +/* Mark the chunk for the least recently used algorithym */
11456 +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
11460 + if (dev->param.nShortOpCaches > 0) {
11461 + if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
11462 + /* Reset the cache usages */
11464 + for (i = 1; i < dev->param.nShortOpCaches; i++)
11465 + dev->srCache[i].lastUse = 0;
11467 + dev->srLastUse = 0;
11470 + dev->srLastUse++;
11472 + cache->lastUse = dev->srLastUse;
11474 -static int ybicmp(const void *a, const void *b)
11476 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
11477 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
11478 - register int ablock = ((yaffs_BlockIndex *)a)->block;
11479 - register int bblock = ((yaffs_BlockIndex *)b)->block;
11480 - if (aseq == bseq)
11481 - return ablock - bblock;
11483 - return aseq - bseq;
11485 + cache->dirty = 1;
11489 +/* Invalidate a single cache page.
11490 + * Do this when a whole page gets written,
11491 + * ie the short cache for this page is no longer valid.
11493 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
11495 + if (object->myDev->param.nShortOpCaches > 0) {
11496 + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
11498 -struct yaffs_ShadowFixerStruct {
11501 - struct yaffs_ShadowFixerStruct *next;
11505 + cache->object = NULL;
11509 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
11510 +/* Invalidate all the cache pages associated with this object
11511 + * Do this whenever ther file is deleted or resized.
11513 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
11516 - * Sort out state of unlinked and deleted objects after scanning.
11518 - struct ylist_head *i;
11519 - struct ylist_head *n;
11522 + yaffs_Device *dev = in->myDev;
11524 - /* Soft delete all the unlinked files */
11525 - ylist_for_each_safe(i, n,
11526 - &dev->unlinkedDir->variant.directoryVariant.children) {
11528 - l = ylist_entry(i, yaffs_Object, siblings);
11529 - yaffs_DeleteObject(l);
11530 + if (dev->param.nShortOpCaches > 0) {
11531 + /* Invalidate it. */
11532 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11533 + if (dev->srCache[i].object == in)
11534 + dev->srCache[i].object = NULL;
11539 - ylist_for_each_safe(i, n,
11540 - &dev->deletedDir->variant.directoryVariant.children) {
11542 - l = ylist_entry(i, yaffs_Object, siblings);
11543 - yaffs_DeleteObject(l);
11548 +/*--------------------- File read/write ------------------------
11549 + * Read and write have very similar structures.
11550 + * In general the read/write has three parts to it
11551 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
11552 + * Some complete chunks
11553 + * An incomplete chunk to end off with
11555 + * Curve-balls: the first chunk might also be the last chunk.
11558 -static int yaffs_Scan(yaffs_Device *dev)
11559 +int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
11562 - yaffs_ExtendedTags tags;
11564 - int blockIterator;
11565 - int startIterator;
11572 - yaffs_BlockState state;
11573 - yaffs_Object *hardList = NULL;
11574 - yaffs_BlockInfo *bi;
11575 - __u32 sequenceNumber;
11576 - yaffs_ObjectHeader *oh;
11577 - yaffs_Object *in;
11578 - yaffs_Object *parent;
11580 - int alloc_failed = 0;
11585 + yaffs_ChunkCache *cache;
11587 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
11588 + yaffs_Device *dev;
11594 + /* chunk = offset / dev->nDataBytesPerChunk + 1; */
11595 + /* start = offset % dev->nDataBytesPerChunk; */
11596 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11599 + /* OK now check for the curveball where the start and end are in
11600 + * the same chunk.
11602 + if ((start + n) < dev->nDataBytesPerChunk)
11605 + nToCopy = dev->nDataBytesPerChunk - start;
11607 + cache = yaffs_FindChunkCache(in, chunk);
11609 - T(YAFFS_TRACE_SCAN,
11610 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
11611 - dev->internalStartBlock, dev->internalEndBlock));
11613 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
11615 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
11617 - /* Scan all the blocks to determine their state */
11618 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
11619 - bi = yaffs_GetBlockInfo(dev, blk);
11620 - yaffs_ClearChunkBits(dev, blk);
11621 - bi->pagesInUse = 0;
11622 - bi->softDeletions = 0;
11623 + /* If the chunk is already in the cache or it is less than a whole chunk
11624 + * or we're using inband tags then use the cache (if there is caching)
11625 + * else bypass the cache.
11627 + if (cache || nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11628 + if (dev->param.nShortOpCaches > 0) {
11630 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
11631 + /* If we can't find the data in the cache, then load it up. */
11633 - bi->blockState = state;
11634 - bi->sequenceNumber = sequenceNumber;
11636 + cache = yaffs_GrabChunkCache(in->myDev);
11637 + cache->object = in;
11638 + cache->chunkId = chunk;
11639 + cache->dirty = 0;
11640 + cache->locked = 0;
11641 + yaffs_ReadChunkDataFromObject(in, chunk,
11644 + cache->nBytes = 0;
11647 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
11648 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
11649 + yaffs_UseChunkCache(dev, cache, 0);
11651 - T(YAFFS_TRACE_SCAN_DEBUG,
11652 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
11653 - state, sequenceNumber));
11654 + cache->locked = 1;
11656 - if (state == YAFFS_BLOCK_STATE_DEAD) {
11657 - T(YAFFS_TRACE_BAD_BLOCKS,
11658 - (TSTR("block %d is bad" TENDSTR), blk));
11659 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
11660 - T(YAFFS_TRACE_SCAN_DEBUG,
11661 - (TSTR("Block empty " TENDSTR)));
11662 - dev->nErasedBlocks++;
11663 - dev->nFreeChunks += dev->nChunksPerBlock;
11667 - startIterator = dev->internalStartBlock;
11668 - endIterator = dev->internalEndBlock;
11669 + memcpy(buffer, &cache->data[start], nToCopy);
11671 - /* For each block.... */
11672 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
11673 - blockIterator++) {
11674 + cache->locked = 0;
11676 + /* Read into the local buffer then copy..*/
11679 + __u8 *localBuffer =
11680 + yaffs_GetTempBuffer(dev, __LINE__);
11681 + yaffs_ReadChunkDataFromObject(in, chunk,
11685 + memcpy(buffer, &localBuffer[start], nToCopy);
11687 - blk = blockIterator;
11689 - bi = yaffs_GetBlockInfo(dev, blk);
11690 - state = bi->blockState;
11691 + yaffs_ReleaseTempBuffer(dev, localBuffer,
11698 - /* For each chunk in each block that needs scanning....*/
11699 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
11700 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
11701 - /* Read the tags and decide what to do */
11702 - chunk = blk * dev->nChunksPerBlock + c;
11703 + /* A full chunk. Read directly into the supplied buffer. */
11704 + yaffs_ReadChunkDataFromObject(in, chunk, buffer);
11706 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
11710 - /* Let's have a good look at this chunk... */
11712 + offset += nToCopy;
11713 + buffer += nToCopy;
11714 + nDone += nToCopy;
11716 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
11717 - /* YAFFS1 only...
11718 - * A deleted chunk
11721 - dev->nFreeChunks++;
11722 - /*T((" %d %d deleted\n",blk,c)); */
11723 - } else if (!tags.chunkUsed) {
11724 - /* An unassigned chunk in the block
11725 - * This means that either the block is empty or
11726 - * this is the one being allocated from
11731 - /* We're looking at the first chunk in the block so the block is unused */
11732 - state = YAFFS_BLOCK_STATE_EMPTY;
11733 - dev->nErasedBlocks++;
11735 - /* this is the block being allocated from */
11736 - T(YAFFS_TRACE_SCAN,
11738 - (" Allocating from %d %d" TENDSTR),
11740 - state = YAFFS_BLOCK_STATE_ALLOCATING;
11741 - dev->allocationBlock = blk;
11742 - dev->allocationPage = c;
11743 - dev->allocationBlockFinder = blk;
11744 - /* Set it to here to encourage the allocator to go forth from here. */
11749 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
11750 + int nBytes, int writeThrough)
11753 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
11754 - } else if (tags.chunkId > 0) {
11755 - /* chunkId > 0 so it is a data chunk... */
11756 - unsigned int endpos;
11758 - yaffs_SetChunkBit(dev, blk, c);
11759 - bi->pagesInUse++;
11761 - in = yaffs_FindOrCreateObjectByNumber(dev,
11764 - YAFFS_OBJECT_TYPE_FILE);
11765 - /* PutChunkIntoFile checks for a clash (two data chunks with
11766 - * the same chunkId).
11773 + int nToWriteBack;
11774 + int startOfWrite = offset;
11775 + int chunkWritten = 0;
11776 + __u32 nBytesRead;
11777 + __u32 chunkStart;
11780 - alloc_failed = 1;
11781 + yaffs_Device *dev;
11784 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
11785 - alloc_failed = 1;
11790 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
11793 - in->variantType == YAFFS_OBJECT_TYPE_FILE
11794 - && in->variant.fileVariant.scannedFileSize <
11796 - in->variant.fileVariant.
11797 - scannedFileSize = endpos;
11798 - if (!dev->useHeaderFileSize) {
11799 - in->variant.fileVariant.
11801 - in->variant.fileVariant.
11804 + while (n > 0 && chunkWritten >= 0) {
11805 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11808 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
11810 - /* chunkId == 0, so it is an ObjectHeader.
11811 - * Thus, we read in the object header and make the object
11813 - yaffs_SetChunkBit(dev, blk, c);
11814 - bi->pagesInUse++;
11815 + if (chunk * dev->nDataBytesPerChunk + start != offset ||
11816 + start >= dev->nDataBytesPerChunk) {
11817 + T(YAFFS_TRACE_ERROR, (
11818 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
11820 + (int)offset, chunk, start));
11822 + chunk++; /* File pos to chunk in file offset */
11824 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
11828 - oh = (yaffs_ObjectHeader *) chunkData;
11830 - in = yaffs_FindObjectByNumber(dev,
11832 - if (in && in->variantType != oh->type) {
11833 - /* This should not happen, but somehow
11834 - * Wev'e ended up with an objectId that has been reused but not yet
11835 - * deleted, and worse still it has changed type. Delete the old object.
11837 + /* OK now check for the curveball where the start and end are in
11838 + * the same chunk.
11841 - yaffs_DeleteObject(in);
11842 + if ((start + n) < dev->nDataBytesPerChunk) {
11847 + /* Now folks, to calculate how many bytes to write back....
11848 + * If we're overwriting and not writing to then end of file then
11849 + * we need to write back as much as was there before.
11852 - in = yaffs_FindOrCreateObjectByNumber(dev,
11858 - alloc_failed = 1;
11860 - if (in && oh->shadowsObject > 0) {
11862 - struct yaffs_ShadowFixerStruct *fixer;
11863 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
11865 - fixer->next = shadowFixerList;
11866 - shadowFixerList = fixer;
11867 - fixer->objectId = tags.objectId;
11868 - fixer->shadowedId = oh->shadowsObject;
11870 + chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
11873 + if (chunkStart > in->variant.fileVariant.fileSize)
11874 + nBytesRead = 0; /* Past end of file */
11876 + nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
11878 - if (in && in->valid) {
11879 - /* We have already filled this one. We have a duplicate and need to resolve it. */
11880 + if (nBytesRead > dev->nDataBytesPerChunk)
11881 + nBytesRead = dev->nDataBytesPerChunk;
11883 - unsigned existingSerial = in->serial;
11884 - unsigned newSerial = tags.serialNumber;
11887 + (start + n)) ? nBytesRead : (start + n);
11889 - if (((existingSerial + 1) & 3) == newSerial) {
11890 - /* Use new one - destroy the exisiting one */
11891 - yaffs_DeleteChunk(dev,
11896 - /* Use existing - destroy this one. */
11897 - yaffs_DeleteChunk(dev, chunk, 1,
11901 + if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
11904 - if (in && !in->valid &&
11905 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
11906 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
11907 - /* We only load some info, don't fiddle with directory structure */
11909 - in->variantType = oh->type;
11911 + nToCopy = dev->nDataBytesPerChunk - start;
11912 + nToWriteBack = dev->nDataBytesPerChunk;
11915 - in->yst_mode = oh->yst_mode;
11916 -#ifdef CONFIG_YAFFS_WINCE
11917 - in->win_atime[0] = oh->win_atime[0];
11918 - in->win_ctime[0] = oh->win_ctime[0];
11919 - in->win_mtime[0] = oh->win_mtime[0];
11920 - in->win_atime[1] = oh->win_atime[1];
11921 - in->win_ctime[1] = oh->win_ctime[1];
11922 - in->win_mtime[1] = oh->win_mtime[1];
11924 - in->yst_uid = oh->yst_uid;
11925 - in->yst_gid = oh->yst_gid;
11926 - in->yst_atime = oh->yst_atime;
11927 - in->yst_mtime = oh->yst_mtime;
11928 - in->yst_ctime = oh->yst_ctime;
11929 - in->yst_rdev = oh->yst_rdev;
11931 - in->hdrChunk = chunk;
11932 - in->serial = tags.serialNumber;
11933 + if (nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11934 + /* An incomplete start or end chunk (or maybe both start and end chunk),
11935 + * or we're using inband tags, so we want to use the cache buffers.
11937 + if (dev->param.nShortOpCaches > 0) {
11938 + yaffs_ChunkCache *cache;
11939 + /* If we can't find the data in the cache, then load the cache */
11940 + cache = yaffs_FindChunkCache(in, chunk);
11942 - } else if (in && !in->valid) {
11943 - /* we need to load this info */
11945 + && yaffs_CheckSpaceForAllocation(dev, 1)) {
11946 + cache = yaffs_GrabChunkCache(dev);
11947 + cache->object = in;
11948 + cache->chunkId = chunk;
11949 + cache->dirty = 0;
11950 + cache->locked = 0;
11951 + yaffs_ReadChunkDataFromObject(in, chunk,
11953 + } else if (cache &&
11955 + !yaffs_CheckSpaceForAllocation(dev, 1)) {
11956 + /* Drop the cache if it was a read cache item and
11957 + * no space check has been made for it.
11963 - in->variantType = oh->type;
11965 + yaffs_UseChunkCache(dev, cache, 1);
11966 + cache->locked = 1;
11968 - in->yst_mode = oh->yst_mode;
11969 -#ifdef CONFIG_YAFFS_WINCE
11970 - in->win_atime[0] = oh->win_atime[0];
11971 - in->win_ctime[0] = oh->win_ctime[0];
11972 - in->win_mtime[0] = oh->win_mtime[0];
11973 - in->win_atime[1] = oh->win_atime[1];
11974 - in->win_ctime[1] = oh->win_ctime[1];
11975 - in->win_mtime[1] = oh->win_mtime[1];
11977 - in->yst_uid = oh->yst_uid;
11978 - in->yst_gid = oh->yst_gid;
11979 - in->yst_atime = oh->yst_atime;
11980 - in->yst_mtime = oh->yst_mtime;
11981 - in->yst_ctime = oh->yst_ctime;
11982 - in->yst_rdev = oh->yst_rdev;
11984 - in->hdrChunk = chunk;
11985 - in->serial = tags.serialNumber;
11987 - yaffs_SetObjectName(in, oh->name);
11989 + memcpy(&cache->data[start], buffer,
11992 - /* directory stuff...
11993 - * hook up to parent
11997 - yaffs_FindOrCreateObjectByNumber
11998 - (dev, oh->parentObjectId,
11999 - YAFFS_OBJECT_TYPE_DIRECTORY);
12001 - alloc_failed = 1;
12002 - if (parent && parent->variantType ==
12003 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12004 - /* Set up as a directory */
12005 - parent->variantType =
12006 - YAFFS_OBJECT_TYPE_DIRECTORY;
12007 - YINIT_LIST_HEAD(&parent->variant.
12008 - directoryVariant.
12010 - } else if (!parent || parent->variantType !=
12011 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12012 - /* Hoosterman, another problem....
12013 - * We're trying to use a non-directory as a directory
12015 + cache->locked = 0;
12016 + cache->nBytes = nToWriteBack;
12018 - T(YAFFS_TRACE_ERROR,
12020 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12022 - parent = dev->lostNFoundDir;
12023 + if (writeThrough) {
12025 + yaffs_WriteChunkDataToObject
12028 + cache->data, cache->nBytes,
12030 + cache->dirty = 0;
12033 - yaffs_AddObjectToDirectory(parent, in);
12035 + chunkWritten = -1; /* fail the write */
12038 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12039 + * Read into the local buffer then copy, then copy over and write back.
12042 - if (0 && (parent == dev->deletedDir ||
12043 - parent == dev->unlinkedDir)) {
12044 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12045 - dev->nDeletedFiles++;
12047 - /* Note re hardlinks.
12048 - * Since we might scan a hardlink before its equivalent object is scanned
12049 - * we put them all in a list.
12050 - * After scanning is complete, we should have all the objects, so we run through this
12051 - * list and fix up all the chains.
12053 + __u8 *localBuffer =
12054 + yaffs_GetTempBuffer(dev, __LINE__);
12056 - switch (in->variantType) {
12057 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12058 - /* Todo got a problem */
12060 - case YAFFS_OBJECT_TYPE_FILE:
12061 - if (dev->useHeaderFileSize)
12063 - in->variant.fileVariant.
12068 - case YAFFS_OBJECT_TYPE_HARDLINK:
12069 - in->variant.hardLinkVariant.
12070 - equivalentObjectId =
12071 - oh->equivalentObjectId;
12072 - in->hardLinks.next =
12073 - (struct ylist_head *)
12077 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12080 - case YAFFS_OBJECT_TYPE_SPECIAL:
12083 - case YAFFS_OBJECT_TYPE_SYMLINK:
12084 - in->variant.symLinkVariant.alias =
12085 - yaffs_CloneString(oh->alias);
12086 - if (!in->variant.symLinkVariant.alias)
12087 - alloc_failed = 1;
12090 + yaffs_ReadChunkDataFromObject(in, chunk,
12094 - if (parent == dev->deletedDir) {
12095 - yaffs_DestroyObject(in);
12096 - bi->hasShrinkHeader = 1;
12103 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12104 - /* If we got this far while scanning, then the block is fully allocated.*/
12105 - state = YAFFS_BLOCK_STATE_FULL;
12108 - bi->blockState = state;
12109 + memcpy(&localBuffer[start], buffer, nToCopy);
12111 - /* Now let's see if it was dirty */
12112 - if (bi->pagesInUse == 0 &&
12113 - !bi->hasShrinkHeader &&
12114 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12115 - yaffs_BlockBecameDirty(dev, blk);
12118 + yaffs_WriteChunkDataToObject(in, chunk,
12124 + yaffs_ReleaseTempBuffer(dev, localBuffer,
12129 - /* Ok, we've done all the scanning.
12130 - * Fix up the hard link chains.
12131 - * We should now have scanned all the objects, now it's time to add these
12135 + /* A full chunk. Write directly from the supplied buffer. */
12137 - yaffs_HardlinkFixup(dev, hardList);
12139 - /* Fix up any shadowed objects */
12141 - struct yaffs_ShadowFixerStruct *fixer;
12142 - yaffs_Object *obj;
12144 - while (shadowFixerList) {
12145 - fixer = shadowFixerList;
12146 - shadowFixerList = fixer->next;
12147 - /* Complete the rename transaction by deleting the shadowed object
12148 - * then setting the object header to unshadowed.
12150 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12152 - yaffs_DeleteObject(obj);
12154 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12156 + yaffs_WriteChunkDataToObject(in, chunk, buffer,
12157 + dev->nDataBytesPerChunk,
12161 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12162 + /* Since we've overwritten the cached data, we better invalidate it. */
12163 + yaffs_InvalidateChunkCache(in, chunk);
12167 + if (chunkWritten >= 0) {
12169 + offset += nToCopy;
12170 + buffer += nToCopy;
12171 + nDone += nToCopy;
12175 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12178 - if (alloc_failed)
12179 - return YAFFS_FAIL;
12180 + /* Update file object */
12182 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12183 + if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
12184 + in->variant.fileVariant.fileSize = (startOfWrite + nDone);
12192 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12193 +int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
12194 + int nBytes, int writeThrough)
12197 - yaffs_ObjectHeader *oh;
12198 - yaffs_Device *dev;
12199 - yaffs_ExtendedTags tags;
12201 - int alloc_failed = 0;
12202 + yaffs2_HandleHole(in,offset);
12203 + return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
12212 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12214 - in->lazyLoaded ? "not yet" : "already"));
12216 +/* ---------------------- File resizing stuff ------------------ */
12218 - if (in->lazyLoaded && in->hdrChunk > 0) {
12219 - in->lazyLoaded = 0;
12220 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12221 +static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
12224 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12225 - oh = (yaffs_ObjectHeader *) chunkData;
12226 + yaffs_Device *dev = in->myDev;
12227 + int oldFileSize = in->variant.fileVariant.fileSize;
12229 - in->yst_mode = oh->yst_mode;
12230 -#ifdef CONFIG_YAFFS_WINCE
12231 - in->win_atime[0] = oh->win_atime[0];
12232 - in->win_ctime[0] = oh->win_ctime[0];
12233 - in->win_mtime[0] = oh->win_mtime[0];
12234 - in->win_atime[1] = oh->win_atime[1];
12235 - in->win_ctime[1] = oh->win_ctime[1];
12236 - in->win_mtime[1] = oh->win_mtime[1];
12238 - in->yst_uid = oh->yst_uid;
12239 - in->yst_gid = oh->yst_gid;
12240 - in->yst_atime = oh->yst_atime;
12241 - in->yst_mtime = oh->yst_mtime;
12242 - in->yst_ctime = oh->yst_ctime;
12243 - in->yst_rdev = oh->yst_rdev;
12244 + int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
12247 - yaffs_SetObjectName(in, oh->name);
12248 + int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
12249 + dev->nDataBytesPerChunk;
12253 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12254 - in->variant.symLinkVariant.alias =
12255 - yaffs_CloneString(oh->alias);
12256 - if (!in->variant.symLinkVariant.alias)
12257 - alloc_failed = 1; /* Not returned to caller */
12259 + /* Delete backwards so that we don't end up with holes if
12260 + * power is lost part-way through the operation.
12262 + for (i = lastDel; i >= startDel; i--) {
12263 + /* NB this could be optimised somewhat,
12264 + * eg. could retrieve the tags and write them without
12265 + * using yaffs_DeleteChunk
12268 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12269 + chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
12270 + if (chunkId > 0) {
12272 + (dev->internalStartBlock * dev->param.nChunksPerBlock)
12274 + ((dev->internalEndBlock +
12275 + 1) * dev->param.nChunksPerBlock)) {
12276 + T(YAFFS_TRACE_ALWAYS,
12277 + (TSTR("Found daft chunkId %d for %d" TENDSTR),
12280 + in->nDataChunks--;
12281 + yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
12288 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12290 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize)
12292 - yaffs_ExtendedTags tags;
12294 - int blockIterator;
12295 - int startIterator;
12297 - int nBlocksToScan = 0;
12298 + int newFullChunks;
12299 + __u32 newSizeOfPartialChunk;
12300 + yaffs_Device *dev = obj->myDev;
12306 - yaffs_BlockState state;
12307 - yaffs_Object *hardList = NULL;
12308 - yaffs_BlockInfo *bi;
12309 - __u32 sequenceNumber;
12310 - yaffs_ObjectHeader *oh;
12311 - yaffs_Object *in;
12312 - yaffs_Object *parent;
12313 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12316 + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
12320 - int foundChunksInBlock;
12321 - int equivalentObjectId;
12322 - int alloc_failed = 0;
12323 + yaffs_PruneResizedChunks(obj, newSize);
12325 + if (newSizeOfPartialChunk != 0) {
12326 + int lastChunk = 1 + newFullChunks;
12327 + __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
12329 - yaffs_BlockIndex *blockIndex = NULL;
12330 - int altBlockIndex = 0;
12331 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12332 + yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer);
12333 + memset(localBuffer + newSizeOfPartialChunk, 0,
12334 + dev->nDataBytesPerChunk - newSizeOfPartialChunk);
12336 - if (!dev->isYaffs2) {
12337 - T(YAFFS_TRACE_SCAN,
12338 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12339 - return YAFFS_FAIL;
12340 + yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer,
12341 + newSizeOfPartialChunk, 1);
12343 + yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
12346 - T(YAFFS_TRACE_SCAN,
12348 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12349 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12350 + obj->variant.fileVariant.fileSize = newSize;
12352 + yaffs_PruneFileStructure(dev, &obj->variant.fileVariant);
12356 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12357 +int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
12359 + yaffs_Device *dev = in->myDev;
12360 + int oldFileSize = in->variant.fileVariant.fileSize;
12362 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12363 + yaffs_FlushFilesChunkCache(in);
12364 + yaffs_InvalidateWholeChunkCache(in);
12366 - if (!blockIndex) {
12367 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12368 - altBlockIndex = 1;
12370 + yaffs_CheckGarbageCollection(dev,0);
12372 - if (!blockIndex) {
12373 - T(YAFFS_TRACE_SCAN,
12374 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
12375 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
12379 - dev->blocksInCheckpoint = 0;
12380 + if (newSize == oldFileSize)
12383 + if(newSize > oldFileSize){
12384 + yaffs2_HandleHole(in,newSize);
12385 + in->variant.fileVariant.fileSize = newSize;
12387 + /* newSize < oldFileSize */
12388 + yaffs_ResizeDown(in, newSize);
12391 + /* Write a new object header to reflect the resize.
12392 + * show we've shrunk the file, if need be
12393 + * Do this only if the file is not in the deleted directories
12394 + * and is not shadowed.
12396 + if (in->parent &&
12397 + !in->isShadowed &&
12398 + in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
12399 + in->parent->objectId != YAFFS_OBJECTID_DELETED)
12400 + yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL);
12403 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12407 - /* Scan all the blocks to determine their state */
12408 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12409 - bi = yaffs_GetBlockInfo(dev, blk);
12410 - yaffs_ClearChunkBits(dev, blk);
12411 - bi->pagesInUse = 0;
12412 - bi->softDeletions = 0;
12413 +loff_t yaffs_GetFileSize(yaffs_Object *obj)
12415 + YCHAR *alias = NULL;
12416 + obj = yaffs_GetEquivalentObject(obj);
12418 + switch (obj->variantType) {
12419 + case YAFFS_OBJECT_TYPE_FILE:
12420 + return obj->variant.fileVariant.fileSize;
12421 + case YAFFS_OBJECT_TYPE_SYMLINK:
12422 + alias = obj->variant.symLinkVariant.alias;
12425 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
12431 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12433 - bi->blockState = state;
12434 - bi->sequenceNumber = sequenceNumber;
12436 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
12437 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
12438 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12439 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12440 +int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
12444 + yaffs_FlushFilesChunkCache(in);
12445 + if(dataSync) /* Only sync data */
12448 + if (updateTime) {
12449 +#ifdef CONFIG_YAFFS_WINCE
12450 + yfsd_WinFileTimeNow(in->win_mtime);
12453 - T(YAFFS_TRACE_SCAN_DEBUG,
12454 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12455 - state, sequenceNumber));
12456 + in->yst_mtime = Y_CURRENT_TIME;
12461 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
12462 - dev->blocksInCheckpoint++;
12463 + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >=
12464 + 0) ? YAFFS_OK : YAFFS_FAIL;
12467 + retVal = YAFFS_OK;
12470 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
12471 - T(YAFFS_TRACE_BAD_BLOCKS,
12472 - (TSTR("block %d is bad" TENDSTR), blk));
12473 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12474 - T(YAFFS_TRACE_SCAN_DEBUG,
12475 - (TSTR("Block empty " TENDSTR)));
12476 - dev->nErasedBlocks++;
12477 - dev->nFreeChunks += dev->nChunksPerBlock;
12478 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12481 - /* Determine the highest sequence number */
12482 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
12483 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
12486 - blockIndex[nBlocksToScan].seq = sequenceNumber;
12487 - blockIndex[nBlocksToScan].block = blk;
12488 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
12492 + /* First off, invalidate the file's data in the cache, without flushing. */
12493 + yaffs_InvalidateWholeChunkCache(in);
12495 - if (sequenceNumber >= dev->sequenceNumber)
12496 - dev->sequenceNumber = sequenceNumber;
12498 - /* TODO: Nasty sequence number! */
12499 - T(YAFFS_TRACE_SCAN,
12501 - ("Block scanning block %d has bad sequence number %d"
12502 - TENDSTR), blk, sequenceNumber));
12503 + if (in->myDev->param.isYaffs2 && (in->parent != in->myDev->deletedDir)) {
12504 + /* Move to the unlinked directory so we have a record that it was deleted. */
12505 + yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
12511 - T(YAFFS_TRACE_SCAN,
12512 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
12513 + yaffs_RemoveObjectFromDirectory(in);
12514 + yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
12515 + in->hdrChunk = 0;
12517 + yaffs_FreeObject(in);
12523 +/* yaffs_DeleteFile deletes the whole file data
12524 + * and the inode associated with the file.
12525 + * It does not delete the links associated with the file.
12527 +static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
12530 - /* Sort the blocks */
12531 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
12533 - /* Use qsort now. */
12534 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
12538 - /* Dungy old bubble sort... */
12540 + int immediateDeletion = 0;
12541 + yaffs_Device *dev = in->myDev;
12543 - yaffs_BlockIndex temp;
12546 + if (!in->myInode)
12547 + immediateDeletion = 1;
12549 - for (i = 0; i < nBlocksToScan; i++)
12550 - for (j = i + 1; j < nBlocksToScan; j++)
12551 - if (blockIndex[i].seq > blockIndex[j].seq) {
12552 - temp = blockIndex[j];
12553 - blockIndex[j] = blockIndex[i];
12554 - blockIndex[i] = temp;
12556 + if (immediateDeletion) {
12558 + yaffs_ChangeObjectName(in, in->myDev->deletedDir,
12559 + _Y("deleted"), 0, 0);
12560 + T(YAFFS_TRACE_TRACING,
12561 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
12564 + in->myDev->nDeletedFiles++;
12565 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12566 + yaffs_ResizeFile(in, 0);
12567 + yaffs_SoftDeleteFile(in);
12570 + yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
12571 + _Y("unlinked"), 0, 0);
12577 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
12581 +int yaffs_DeleteFile(yaffs_Object *in)
12583 + int retVal = YAFFS_OK;
12584 + int deleted; /* Need to cache value on stack if in is freed */
12585 + yaffs_Device *dev = in->myDev;
12587 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12588 + yaffs_ResizeFile(in, 0);
12590 + if (in->nDataChunks > 0) {
12591 + /* Use soft deletion if there is data in the file.
12592 + * That won't be the case if it has been resized to zero.
12594 + if (!in->unlinked)
12595 + retVal = yaffs_UnlinkFileIfNeeded(in);
12597 - /* Now scan the blocks looking at the data. */
12598 - startIterator = 0;
12599 - endIterator = nBlocksToScan - 1;
12600 - T(YAFFS_TRACE_SCAN_DEBUG,
12601 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
12602 + deleted = in->deleted;
12604 - /* For each block.... backwards */
12605 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
12606 - blockIterator--) {
12607 - /* Cooperative multitasking! This loop can run for so
12608 - long that watchdog timers expire. */
12610 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
12613 + in->myDev->nDeletedFiles++;
12614 + yaffs_SoftDeleteFile(in);
12616 + return deleted ? YAFFS_OK : YAFFS_FAIL;
12618 + /* The file has no data chunks so we toss it immediately */
12619 + yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
12620 + in->variant.fileVariant.top = NULL;
12621 + yaffs_DoGenericObjectDeletion(in);
12623 - /* get the block to scan in the correct order */
12624 - blk = blockIndex[blockIterator].block;
12629 - bi = yaffs_GetBlockInfo(dev, blk);
12630 +static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
12632 + return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
12633 + !(ylist_empty(&obj->variant.directoryVariant.children));
12636 +static int yaffs_DeleteDirectory(yaffs_Object *obj)
12638 + /* First check that the directory is empty. */
12639 + if (yaffs_IsNonEmptyDirectory(obj))
12640 + return YAFFS_FAIL;
12642 - state = bi->blockState;
12643 + return yaffs_DoGenericObjectDeletion(obj);
12647 +static int yaffs_DeleteSymLink(yaffs_Object *in)
12649 + if(in->variant.symLinkVariant.alias)
12650 + YFREE(in->variant.symLinkVariant.alias);
12651 + in->variant.symLinkVariant.alias=NULL;
12653 - /* For each chunk in each block that needs scanning.... */
12654 - foundChunksInBlock = 0;
12655 - for (c = dev->nChunksPerBlock - 1;
12656 - !alloc_failed && c >= 0 &&
12657 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12658 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
12659 - /* Scan backwards...
12660 - * Read the tags and decide what to do
12662 + return yaffs_DoGenericObjectDeletion(in);
12665 - chunk = blk * dev->nChunksPerBlock + c;
12666 +static int yaffs_DeleteHardLink(yaffs_Object *in)
12668 + /* remove this hardlink from the list assocaited with the equivalent
12671 + ylist_del_init(&in->hardLinks);
12672 + return yaffs_DoGenericObjectDeletion(in);
12675 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12677 +int yaffs_DeleteObject(yaffs_Object *obj)
12680 + switch (obj->variantType) {
12681 + case YAFFS_OBJECT_TYPE_FILE:
12682 + retVal = yaffs_DeleteFile(obj);
12684 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12685 + if(!ylist_empty(&obj->variant.directoryVariant.dirty)){
12686 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->objectId));
12687 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12689 + return yaffs_DeleteDirectory(obj);
12691 + case YAFFS_OBJECT_TYPE_SYMLINK:
12692 + retVal = yaffs_DeleteSymLink(obj);
12694 + case YAFFS_OBJECT_TYPE_HARDLINK:
12695 + retVal = yaffs_DeleteHardLink(obj);
12697 + case YAFFS_OBJECT_TYPE_SPECIAL:
12698 + retVal = yaffs_DoGenericObjectDeletion(obj);
12700 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12702 + break; /* should not happen. */
12705 - /* Let's have a good look at this chunk... */
12709 - if (!tags.chunkUsed) {
12710 - /* An unassigned chunk in the block.
12711 - * If there are used chunks after this one, then
12712 - * it is a chunk that was skipped due to failing the erased
12713 - * check. Just skip it so that it can be deleted.
12714 - * But, more typically, We get here when this is an unallocated
12715 - * chunk and his means that either the block is empty or
12716 - * this is the one being allocated from
12718 +static int yaffs_UnlinkWorker(yaffs_Object *obj)
12721 - if (foundChunksInBlock) {
12722 - /* This is a chunk that was skipped due to failing the erased check */
12723 - } else if (c == 0) {
12724 - /* We're looking at the first chunk in the block so the block is unused */
12725 - state = YAFFS_BLOCK_STATE_EMPTY;
12726 - dev->nErasedBlocks++;
12728 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12729 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
12730 - if (dev->sequenceNumber == bi->sequenceNumber) {
12731 - /* this is the block being allocated from */
12733 - T(YAFFS_TRACE_SCAN,
12735 - (" Allocating from %d %d"
12736 - TENDSTR), blk, c));
12738 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12739 - dev->allocationBlock = blk;
12740 - dev->allocationPage = c;
12741 - dev->allocationBlockFinder = blk;
12743 - /* This is a partially written block that is not
12744 - * the current allocation block. This block must have
12745 - * had a write failure, so set up for retirement.
12748 - /* bi->needsRetiring = 1; ??? TODO */
12749 - bi->gcPrioritise = 1;
12751 - T(YAFFS_TRACE_ALWAYS,
12752 - (TSTR("Partially written block %d detected" TENDSTR),
12757 + int immediateDeletion = 0;
12759 - dev->nFreeChunks++;
12760 + if (!obj->myInode)
12761 + immediateDeletion = 1;
12763 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
12764 - T(YAFFS_TRACE_SCAN,
12765 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
12768 - dev->nFreeChunks++;
12770 - } else if (tags.chunkId > 0) {
12771 - /* chunkId > 0 so it is a data chunk... */
12772 - unsigned int endpos;
12773 - __u32 chunkBase =
12774 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
12776 - foundChunksInBlock = 1;
12779 - yaffs_SetChunkBit(dev, blk, c);
12780 - bi->pagesInUse++;
12782 - in = yaffs_FindOrCreateObjectByNumber(dev,
12785 - YAFFS_OBJECT_TYPE_FILE);
12787 - /* Out of memory */
12788 - alloc_failed = 1;
12791 + yaffs_UpdateParent(obj->parent);
12794 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12796 - in->variant.fileVariant.shrinkSize) {
12797 - /* This has not been invalidated by a resize */
12798 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
12800 - alloc_failed = 1;
12802 + if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
12803 + return yaffs_DeleteHardLink(obj);
12804 + } else if (!ylist_empty(&obj->hardLinks)) {
12805 + /* Curve ball: We're unlinking an object that has a hardlink.
12807 + * This problem arises because we are not strictly following
12808 + * The Linux link/inode model.
12810 + * We can't really delete the object.
12811 + * Instead, we do the following:
12812 + * - Select a hardlink.
12813 + * - Unhook it from the hard links
12814 + * - Move it from its parent directory (so that the rename can work)
12815 + * - Rename the object to the hardlink's name.
12816 + * - Delete the hardlink
12819 - /* File size is calculated by looking at the data chunks if we have not
12820 - * seen an object header yet. Stop this practice once we find an object header.
12824 - 1) * dev->nDataBytesPerChunk +
12827 - if (!in->valid && /* have not got an object header yet */
12828 - in->variant.fileVariant.
12829 - scannedFileSize < endpos) {
12830 - in->variant.fileVariant.
12831 - scannedFileSize = endpos;
12832 - in->variant.fileVariant.
12834 - in->variant.fileVariant.
12837 + yaffs_Object *hl;
12838 + yaffs_Object *parent;
12840 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
12843 - /* This chunk has been invalidated by a resize, so delete */
12844 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
12845 + hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
12849 - /* chunkId == 0, so it is an ObjectHeader.
12850 - * Thus, we read in the object header and make the object
12852 - foundChunksInBlock = 1;
12853 + yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
12854 + parent = hl->parent;
12856 - yaffs_SetChunkBit(dev, blk, c);
12857 - bi->pagesInUse++;
12858 + ylist_del_init(&hl->hardLinks);
12862 + yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl);
12864 - if (tags.extraHeaderInfoAvailable) {
12865 - in = yaffs_FindOrCreateObjectByNumber
12866 - (dev, tags.objectId,
12867 - tags.extraObjectType);
12869 - alloc_failed = 1;
12871 + retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0);
12874 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
12877 - tags.extraShadows ||
12879 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12880 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
12882 - /* If we don't have valid info then we need to read the chunk
12883 - * TODO In future we can probably defer reading the chunk and
12884 - * living with invalid data until needed.
12886 + if (retVal == YAFFS_OK)
12887 + retVal = yaffs_DoGenericObjectDeletion(hl);
12889 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
12894 - oh = (yaffs_ObjectHeader *) chunkData;
12896 - if (dev->inbandTags) {
12897 - /* Fix up the header if they got corrupted by inband tags */
12898 - oh->shadowsObject = oh->inbandShadowsObject;
12899 - oh->isShrink = oh->inbandIsShrink;
12904 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
12906 - alloc_failed = 1;
12908 + } else if (immediateDeletion) {
12909 + switch (obj->variantType) {
12910 + case YAFFS_OBJECT_TYPE_FILE:
12911 + return yaffs_DeleteFile(obj);
12913 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12914 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12915 + return yaffs_DeleteDirectory(obj);
12917 + case YAFFS_OBJECT_TYPE_SYMLINK:
12918 + return yaffs_DeleteSymLink(obj);
12920 + case YAFFS_OBJECT_TYPE_SPECIAL:
12921 + return yaffs_DoGenericObjectDeletion(obj);
12923 + case YAFFS_OBJECT_TYPE_HARDLINK:
12924 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12926 + return YAFFS_FAIL;
12928 + } else if(yaffs_IsNonEmptyDirectory(obj))
12929 + return YAFFS_FAIL;
12931 + return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
12932 + _Y("unlinked"), 0, 0);
12938 - /* TODO Hoosterman we have a problem! */
12939 - T(YAFFS_TRACE_ERROR,
12941 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
12942 - TENDSTR), tags.objectId, chunk));
12945 +static int yaffs_UnlinkObject(yaffs_Object *obj)
12949 - /* We have already filled this one.
12950 - * We have a duplicate that will be discarded, but
12951 - * we first have to suck out resize info if it is a file.
12953 + if (obj && obj->unlinkAllowed)
12954 + return yaffs_UnlinkWorker(obj);
12956 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
12958 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
12959 - (tags.extraHeaderInfoAvailable &&
12960 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
12962 - (oh) ? oh->fileSize : tags.
12964 - __u32 parentObjectId =
12966 - parentObjectId : tags.
12967 - extraParentObjectId;
12971 - (oh) ? oh->isShrink : tags.
12972 - extraIsShrinkHeader;
12973 + return YAFFS_FAIL;
12975 - /* If it is deleted (unlinked at start also means deleted)
12976 - * we treat the file size as being zeroed at this point.
12978 - if (parentObjectId ==
12979 - YAFFS_OBJECTID_DELETED
12980 - || parentObjectId ==
12981 - YAFFS_OBJECTID_UNLINKED) {
12986 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
12988 + yaffs_Object *obj;
12991 - in->variant.fileVariant.
12992 - shrinkSize > thisSize) {
12993 - in->variant.fileVariant.
12997 + obj = yaffs_FindObjectByName(dir, name);
12998 + return yaffs_UnlinkObject(obj);
13002 - bi->hasShrinkHeader = 1;
13003 +/*----------------------- Initialisation Scanning ---------------------- */
13006 - /* Use existing - destroy this one. */
13007 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13008 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
13009 + int backwardScanning)
13011 + yaffs_Object *obj;
13014 + if (!backwardScanning) {
13015 + /* Handle YAFFS1 forward scanning case
13016 + * For YAFFS1 we always do the deletion
13019 - if (!in->valid && in->variantType !=
13020 - (oh ? oh->type : tags.extraObjectType))
13021 - T(YAFFS_TRACE_ERROR, (
13022 - TSTR("yaffs tragedy: Bad object type, "
13023 - TCONT("%d != %d, for object %d at chunk ")
13024 - TCONT("%d during scan")
13026 - oh->type : tags.extraObjectType,
13027 - in->variantType, tags.objectId,
13030 - if (!in->valid &&
13031 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13033 - YAFFS_OBJECTID_LOSTNFOUND)) {
13034 - /* We only load some info, don't fiddle with directory structure */
13037 + /* Handle YAFFS2 case (backward scanning)
13038 + * If the shadowed object exists then ignore.
13040 + obj = yaffs_FindObjectByNumber(dev, objId);
13046 - in->variantType = oh->type;
13047 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13048 + * We put it in unlinked dir to be cleaned up after the scanning
13051 + yaffs_FindOrCreateObjectByNumber(dev, objId,
13052 + YAFFS_OBJECT_TYPE_FILE);
13055 + obj->isShadowed = 1;
13056 + yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
13057 + obj->variant.fileVariant.shrinkSize = 0;
13058 + obj->valid = 1; /* So that we don't read any other info for this file */
13060 - in->yst_mode = oh->yst_mode;
13061 -#ifdef CONFIG_YAFFS_WINCE
13062 - in->win_atime[0] = oh->win_atime[0];
13063 - in->win_ctime[0] = oh->win_ctime[0];
13064 - in->win_mtime[0] = oh->win_mtime[0];
13065 - in->win_atime[1] = oh->win_atime[1];
13066 - in->win_ctime[1] = oh->win_ctime[1];
13067 - in->win_mtime[1] = oh->win_mtime[1];
13069 - in->yst_uid = oh->yst_uid;
13070 - in->yst_gid = oh->yst_gid;
13071 - in->yst_atime = oh->yst_atime;
13072 - in->yst_mtime = oh->yst_mtime;
13073 - in->yst_ctime = oh->yst_ctime;
13074 - in->yst_rdev = oh->yst_rdev;
13079 - in->variantType = tags.extraObjectType;
13080 - in->lazyLoaded = 1;
13083 - in->hdrChunk = chunk;
13084 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
13086 + yaffs_Object *hl;
13087 + yaffs_Object *in;
13089 - } else if (!in->valid) {
13090 - /* we need to load this info */
13091 + while (hardList) {
13093 + hardList = (yaffs_Object *) (hardList->hardLinks.next);
13096 - in->hdrChunk = chunk;
13097 + in = yaffs_FindObjectByNumber(dev,
13098 + hl->variant.hardLinkVariant.
13099 + equivalentObjectId);
13102 - in->variantType = oh->type;
13104 + /* Add the hardlink pointers */
13105 + hl->variant.hardLinkVariant.equivalentObject = in;
13106 + ylist_add(&hl->hardLinks, &in->hardLinks);
13108 + /* Todo Need to report/handle this better.
13109 + * Got a problem... hardlink to a non-existant object
13111 + hl->variant.hardLinkVariant.equivalentObject = NULL;
13112 + YINIT_LIST_HEAD(&hl->hardLinks);
13114 - in->yst_mode = oh->yst_mode;
13115 -#ifdef CONFIG_YAFFS_WINCE
13116 - in->win_atime[0] = oh->win_atime[0];
13117 - in->win_ctime[0] = oh->win_ctime[0];
13118 - in->win_mtime[0] = oh->win_mtime[0];
13119 - in->win_atime[1] = oh->win_atime[1];
13120 - in->win_ctime[1] = oh->win_ctime[1];
13121 - in->win_mtime[1] = oh->win_mtime[1];
13123 - in->yst_uid = oh->yst_uid;
13124 - in->yst_gid = oh->yst_gid;
13125 - in->yst_atime = oh->yst_atime;
13126 - in->yst_mtime = oh->yst_mtime;
13127 - in->yst_ctime = oh->yst_ctime;
13128 - in->yst_rdev = oh->yst_rdev;
13134 - if (oh->shadowsObject > 0)
13135 - yaffs_HandleShadowedObject(dev,
13141 - yaffs_SetObjectName(in, oh->name);
13143 - yaffs_FindOrCreateObjectByNumber
13144 - (dev, oh->parentObjectId,
13145 - YAFFS_OBJECT_TYPE_DIRECTORY);
13147 - fileSize = oh->fileSize;
13148 - isShrink = oh->isShrink;
13149 - equivalentObjectId = oh->equivalentObjectId;
13152 - in->variantType = tags.extraObjectType;
13154 - yaffs_FindOrCreateObjectByNumber
13155 - (dev, tags.extraParentObjectId,
13156 - YAFFS_OBJECT_TYPE_DIRECTORY);
13157 - fileSize = tags.extraFileLength;
13158 - isShrink = tags.extraIsShrinkHeader;
13159 - equivalentObjectId = tags.extraEquivalentObjectId;
13160 - in->lazyLoaded = 1;
13161 +static void yaffs_StripDeletedObjects(yaffs_Device *dev)
13164 + * Sort out state of unlinked and deleted objects after scanning.
13166 + struct ylist_head *i;
13167 + struct ylist_head *n;
13172 + if (dev->readOnly)
13176 - alloc_failed = 1;
13177 + /* Soft delete all the unlinked files */
13178 + ylist_for_each_safe(i, n,
13179 + &dev->unlinkedDir->variant.directoryVariant.children) {
13181 + l = ylist_entry(i, yaffs_Object, siblings);
13182 + yaffs_DeleteObject(l);
13186 - /* directory stuff...
13187 - * hook up to parent
13189 + ylist_for_each_safe(i, n,
13190 + &dev->deletedDir->variant.directoryVariant.children) {
13192 + l = ylist_entry(i, yaffs_Object, siblings);
13193 + yaffs_DeleteObject(l);
13197 - if (parent && parent->variantType ==
13198 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13199 - /* Set up as a directory */
13200 - parent->variantType =
13201 - YAFFS_OBJECT_TYPE_DIRECTORY;
13202 - YINIT_LIST_HEAD(&parent->variant.
13203 - directoryVariant.
13205 - } else if (!parent || parent->variantType !=
13206 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13207 - /* Hoosterman, another problem....
13208 - * We're trying to use a non-directory as a directory
13212 - T(YAFFS_TRACE_ERROR,
13214 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13216 - parent = dev->lostNFoundDir;
13219 + * This code iterates through all the objects making sure that they are rooted.
13220 + * Any unrooted objects are re-rooted in lost+found.
13221 + * An object needs to be in one of:
13222 + * - Directly under deleted, unlinked
13223 + * - Directly or indirectly under root.
13226 + * This code assumes that we don't ever change the current relationships between
13228 + * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
13229 + * lostNfound->parent == rootDir
13231 + * This fixes the problem where directories might have inadvertently been deleted
13232 + * leaving the object "hanging" without being rooted in the directory tree.
13235 +static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
13237 + return (obj == dev->deletedDir ||
13238 + obj == dev->unlinkedDir||
13239 + obj == dev->rootDir);
13242 - yaffs_AddObjectToDirectory(parent, in);
13243 +static void yaffs_FixHangingObjects(yaffs_Device *dev)
13245 + yaffs_Object *obj;
13246 + yaffs_Object *parent;
13248 + struct ylist_head *lh;
13249 + struct ylist_head *n;
13253 - itsUnlinked = (parent == dev->deletedDir) ||
13254 - (parent == dev->unlinkedDir);
13255 + if (dev->readOnly)
13259 - /* Mark the block as having a shrinkHeader */
13260 - bi->hasShrinkHeader = 1;
13262 + /* Iterate through the objects in each hash entry,
13263 + * looking at each object.
13264 + * Make sure it is rooted.
13267 - /* Note re hardlinks.
13268 - * Since we might scan a hardlink before its equivalent object is scanned
13269 - * we put them all in a list.
13270 - * After scanning is complete, we should have all the objects, so we run
13271 - * through this list and fix up all the chains.
13272 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13273 + ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
13275 + obj = ylist_entry(lh, yaffs_Object, hashLink);
13276 + parent= obj->parent;
13278 + if(yaffs_HasNULLParent(dev,obj)){
13279 + /* These directories are not hanging */
13282 + else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13284 + else if(yaffs_HasNULLParent(dev,parent))
13288 + * Need to follow the parent chain to see if it is hanging.
13293 - switch (in->variantType) {
13294 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13295 - /* Todo got a problem */
13297 - case YAFFS_OBJECT_TYPE_FILE:
13299 - if (in->variant.fileVariant.
13300 - scannedFileSize < fileSize) {
13301 - /* This covers the case where the file size is greater
13302 - * than where the data is
13303 - * This will happen if the file is resized to be larger
13304 - * than its current data extents.
13306 - in->variant.fileVariant.fileSize = fileSize;
13307 - in->variant.fileVariant.scannedFileSize =
13308 - in->variant.fileVariant.fileSize;
13312 - in->variant.fileVariant.shrinkSize > fileSize) {
13313 - in->variant.fileVariant.shrinkSize = fileSize;
13317 - case YAFFS_OBJECT_TYPE_HARDLINK:
13318 - if (!itsUnlinked) {
13319 - in->variant.hardLinkVariant.equivalentObjectId =
13320 - equivalentObjectId;
13321 - in->hardLinks.next =
13322 - (struct ylist_head *) hardList;
13326 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13329 - case YAFFS_OBJECT_TYPE_SPECIAL:
13332 - case YAFFS_OBJECT_TYPE_SYMLINK:
13334 - in->variant.symLinkVariant.alias =
13335 - yaffs_CloneString(oh->alias);
13336 - if (!in->variant.symLinkVariant.alias)
13337 - alloc_failed = 1;
13340 + while(parent != dev->rootDir &&
13341 + parent->parent &&
13342 + parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
13344 + parent = parent->parent;
13348 + if(parent != dev->rootDir)
13352 + T(YAFFS_TRACE_SCAN,
13353 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13355 + yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
13363 - } /* End of scanning for each chunk */
13365 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13366 - /* If we got this far while scanning, then the block is fully allocated. */
13367 - state = YAFFS_BLOCK_STATE_FULL;
13370 + * Delete directory contents for cleaning up lost and found.
13372 +static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
13374 + yaffs_Object *obj;
13375 + struct ylist_head *lh;
13376 + struct ylist_head *n;
13378 - bi->blockState = state;
13379 + if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13382 + ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
13384 + obj = ylist_entry(lh, yaffs_Object, siblings);
13385 + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
13386 + yaffs_DeleteDirectoryContents(obj);
13388 + T(YAFFS_TRACE_SCAN,
13389 + (TSTR("Deleting lost_found object %d" TENDSTR),
13392 - /* Now let's see if it was dirty */
13393 - if (bi->pagesInUse == 0 &&
13394 - !bi->hasShrinkHeader &&
13395 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13396 - yaffs_BlockBecameDirty(dev, blk);
13397 + /* Need to use UnlinkObject since Delete would not handle
13398 + * hardlinked objects correctly.
13400 + yaffs_UnlinkObject(obj);
13407 - if (altBlockIndex)
13408 - YFREE_ALT(blockIndex);
13410 - YFREE(blockIndex);
13411 +static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
13413 + yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
13416 - /* Ok, we've done all the scanning.
13417 - * Fix up the hard link chains.
13418 - * We should now have scanned all the objects, now it's time to add these
13421 - yaffs_HardlinkFixup(dev, hardList);
13422 +static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
13425 + yaffs_ObjectHeader *oh;
13426 + yaffs_Device *dev;
13427 + yaffs_ExtendedTags tags;
13429 + int alloc_failed = 0;
13434 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13437 - if (alloc_failed)
13438 - return YAFFS_FAIL;
13440 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
13442 + in->lazyLoaded ? "not yet" : "already"));
13445 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
13446 + if (in->lazyLoaded && in->hdrChunk > 0) {
13447 + in->lazyLoaded = 0;
13448 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13452 + result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
13453 + oh = (yaffs_ObjectHeader *) chunkData;
13455 -/*------------------------------ Directory Functions ----------------------------- */
13456 + in->yst_mode = oh->yst_mode;
13457 +#ifdef CONFIG_YAFFS_WINCE
13458 + in->win_atime[0] = oh->win_atime[0];
13459 + in->win_ctime[0] = oh->win_ctime[0];
13460 + in->win_mtime[0] = oh->win_mtime[0];
13461 + in->win_atime[1] = oh->win_atime[1];
13462 + in->win_ctime[1] = oh->win_ctime[1];
13463 + in->win_mtime[1] = oh->win_mtime[1];
13465 + in->yst_uid = oh->yst_uid;
13466 + in->yst_gid = oh->yst_gid;
13467 + in->yst_atime = oh->yst_atime;
13468 + in->yst_mtime = oh->yst_mtime;
13469 + in->yst_ctime = oh->yst_ctime;
13470 + in->yst_rdev = oh->yst_rdev;
13472 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
13474 - struct ylist_head *lh;
13475 - yaffs_Object *listObj;
13477 + yaffs_SetObjectNameFromOH(in, oh);
13480 + if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
13481 + in->variant.symLinkVariant.alias =
13482 + yaffs_CloneString(oh->alias);
13483 + if (!in->variant.symLinkVariant.alias)
13484 + alloc_failed = 1; /* Not returned to caller */
13488 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
13491 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13495 - if (yaffs_SkipVerification(obj->myDev))
13497 +/*------------------------------ Directory Functions ----------------------------- */
13499 - if (!obj->parent) {
13500 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
13503 + *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
13504 + * link (ie. name) is created or deleted in the directory.
13507 + * create dir/a : update dir's mtime/ctime
13508 + * rm dir/a: update dir's mtime/ctime
13509 + * modify dir/a: don't update dir's mtimme/ctime
13511 + * This can be handled immediately or defered. Defering helps reduce the number
13512 + * of updates when many files in a directory are changed within a brief period.
13514 + * If the directory updating is defered then yaffs_UpdateDirtyDirecories must be
13515 + * called periodically.
13518 +static void yaffs_UpdateParent(yaffs_Object *obj)
13520 + yaffs_Device *dev;
13525 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13526 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
13530 - /* Iterate through the objects in each hash entry */
13531 +#ifndef CONFIG_YAFFS_WINCE
13533 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
13535 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13536 - yaffs_VerifyObject(listObj);
13537 - if (obj == listObj)
13539 + dev = obj->myDev;
13541 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
13542 + if(dev->param.deferDirectoryUpdate){
13543 + struct ylist_head *link = &obj->variant.directoryVariant.dirty;
13545 + if(ylist_empty(link)){
13546 + ylist_add(link,&dev->dirtyDirectories);
13547 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->objectId));
13551 - if (count != 1) {
13552 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
13556 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13560 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
13561 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
13563 - struct ylist_head *lh;
13564 - yaffs_Object *listObj;
13566 - if (!directory) {
13570 + struct ylist_head *link;
13571 + yaffs_Object *obj;
13572 + yaffs_DirectoryStructure *dS;
13573 + yaffs_ObjectVariant *oV;
13575 - if (yaffs_SkipFullVerification(directory->myDev))
13577 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
13579 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13580 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
13583 + while(!ylist_empty(&dev->dirtyDirectories)){
13584 + link = dev->dirtyDirectories.next;
13585 + ylist_del_init(link);
13587 + dS=ylist_entry(link,yaffs_DirectoryStructure,dirty);
13588 + oV = ylist_entry(dS,yaffs_ObjectVariant,directoryVariant);
13589 + obj = ylist_entry(oV,yaffs_Object,variant);
13591 - /* Iterate through the objects in each hash entry */
13592 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId));
13594 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
13596 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13597 - if (listObj->parent != directory) {
13598 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
13601 - yaffs_VerifyObjectInDirectory(listObj);
13604 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13609 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
13611 yaffs_Device *dev = obj->myDev;
13612 @@ -6677,18 +4474,17 @@ static void yaffs_RemoveObjectFromDirect
13614 yaffs_VerifyDirectory(parent);
13616 - if (dev && dev->removeObjectCallback)
13617 - dev->removeObjectCallback(obj);
13618 + if (dev && dev->param.removeObjectCallback)
13619 + dev->param.removeObjectCallback(obj);
13622 ylist_del_init(&obj->siblings);
13623 obj->parent = NULL;
13626 yaffs_VerifyDirectory(parent);
13630 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13631 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13635 @@ -6781,7 +4577,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
13638 yaffs_GetObjectName(l, buffer,
13639 - YAFFS_MAX_NAME_LENGTH);
13640 + YAFFS_MAX_NAME_LENGTH + 1);
13641 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
13644 @@ -6842,36 +4638,124 @@ yaffs_Object *yaffs_GetEquivalentObject(
13648 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
13650 - memset(name, 0, buffSize * sizeof(YCHAR));
13652 - yaffs_CheckObjectDetailsLoaded(obj);
13654 + * A note or two on object names.
13655 + * * If the object name is missing, we then make one up in the form objnnn
13657 + * * ASCII names are stored in the object header's name field from byte zero
13658 + * * Unicode names are historically stored starting from byte zero.
13660 + * Then there are automatic Unicode names...
13661 + * The purpose of these is to save names in a way that can be read as
13662 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
13663 + * system to share files.
13665 + * These automatic unicode are stored slightly differently...
13666 + * - If the name can fit in the ASCII character space then they are saved as
13667 + * ascii names as per above.
13668 + * - If the name needs Unicode then the name is saved in Unicode
13669 + * starting at oh->name[1].
13671 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13672 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13673 - } else if (obj->hdrChunk <= 0) {
13675 +static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize)
13677 + /* Create an object name if we could not find one. */
13678 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
13680 YCHAR numString[20];
13681 YCHAR *x = &numString[19];
13682 unsigned v = obj->objectId;
13687 *x = '0' + (v % 10);
13690 /* make up a name */
13691 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
13692 - yaffs_strcat(locName, x);
13693 + yaffs_strcat(locName,x);
13694 yaffs_strncpy(name, locName, buffSize - 1);
13698 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
13700 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13701 + if(dev->param.autoUnicode){
13703 + /* It is an ASCII name, so do an ASCII to unicode conversion */
13704 + const char *asciiOhName = (const char *)ohName;
13705 + int n = bufferSize - 1;
13706 + while(n > 0 && *asciiOhName){
13707 + *name = *asciiOhName;
13713 + yaffs_strncpy(name,ohName+1, bufferSize -1);
13716 + yaffs_strncpy(name, ohName, bufferSize - 1);
13720 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name)
13722 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13727 + if(dev->param.autoUnicode){
13732 + /* Figure out if the name will fit in ascii character set */
13733 + while(isAscii && *w){
13734 + if((*w) & 0xff00)
13740 + /* It is an ASCII name, so do a unicode to ascii conversion */
13741 + char *asciiOhName = (char *)ohName;
13742 + int n = YAFFS_MAX_NAME_LENGTH - 1;
13743 + while(n > 0 && *name){
13744 + *asciiOhName= *name;
13750 + /* It is a unicode name, so save starting at the second YCHAR */
13752 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
13757 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
13761 +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
13763 + memset(name, 0, buffSize * sizeof(YCHAR));
13765 + yaffs_CheckObjectDetailsLoaded(obj);
13767 + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13768 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13770 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
13771 - else if (obj->shortName[0])
13772 + else if (obj->shortName[0]) {
13773 yaffs_strcpy(name, obj->shortName);
13777 + else if(obj->hdrChunk > 0) {
13779 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
13781 @@ -6884,14 +4768,17 @@ int yaffs_GetObjectName(yaffs_Object *ob
13782 obj->hdrChunk, buffer,
13785 - yaffs_strncpy(name, oh->name, buffSize - 1);
13786 + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize);
13788 yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
13791 - return yaffs_strlen(name);
13792 + yaffs_FixNullName(obj,name,buffSize);
13794 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
13798 int yaffs_GetObjectFileLength(yaffs_Object *obj)
13800 /* Dereference any hard linking */
13801 @@ -6899,9 +4786,11 @@ int yaffs_GetObjectFileLength(yaffs_Obje
13803 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
13804 return obj->variant.fileVariant.fileSize;
13805 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
13806 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
13808 + if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
13809 + if(!obj->variant.symLinkVariant.alias)
13811 + return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
13813 /* Only a directory should drop through to here */
13814 return obj->myDev->nDataBytesPerChunk;
13816 @@ -6992,7 +4881,7 @@ int yaffs_SetAttributes(yaffs_Object *ob
13817 if (valid & ATTR_SIZE)
13818 yaffs_ResizeFile(obj, attr->ia_size);
13820 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
13821 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
13825 @@ -7025,12 +4914,129 @@ int yaffs_GetAttributes(yaffs_Object *ob
13830 +static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags)
13832 + yaffs_XAttrMod xmod;
13837 + xmod.name = name;
13838 + xmod.data = value;
13839 + xmod.size = size;
13840 + xmod.flags = flags;
13841 + xmod.result = -ENOSPC;
13843 + result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod);
13846 + return xmod.result;
13851 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod)
13854 + int x_offs = sizeof(yaffs_ObjectHeader);
13855 + yaffs_Device *dev = obj->myDev;
13856 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13858 + char * x_buffer = buffer + x_offs;
13861 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
13863 + retval = nval_del(x_buffer, x_size, xmod->name);
13865 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13866 + obj->xattrKnown = 1;
13868 + xmod->result = retval;
13873 +static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13875 + char *buffer = NULL;
13877 + yaffs_ExtendedTags tags;
13878 + yaffs_Device *dev = obj->myDev;
13879 + int x_offs = sizeof(yaffs_ObjectHeader);
13880 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13886 + if(obj->hdrChunk < 1)
13889 + /* If we know that the object has no xattribs then don't do all the
13890 + * reading and parsing.
13892 + if(obj->xattrKnown && !obj->hasXattr){
13899 + buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__);
13903 + result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags);
13905 + if(result != YAFFS_OK)
13906 + retval = -ENOENT;
13908 + x_buffer = buffer + x_offs;
13910 + if (!obj->xattrKnown){
13911 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13912 + obj->xattrKnown = 1;
13916 + retval = nval_get(x_buffer, x_size, name, value, size);
13918 + retval = nval_list(x_buffer, x_size, value,size);
13920 + yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__);
13924 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags)
13926 + return yaffs_DoXMod(obj, 1, name, value, size, flags);
13929 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name)
13931 + return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
13934 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13936 + return yaffs_DoXFetch(obj, name, value, size);
13939 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size)
13941 + return yaffs_DoXFetch(obj, NULL, buffer,size);
13947 int yaffs_DumpObject(yaffs_Object *obj)
13951 - yaffs_GetObjectName(obj, name, 256);
13952 + yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
13954 T(YAFFS_TRACE_ALWAYS,
13956 @@ -7050,30 +5056,32 @@ static int yaffs_CheckDevFunctions(const
13959 /* Common functions, gotta have */
13960 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
13961 + if (!dev->param.eraseBlockInNAND || !dev->param.initialiseNAND)
13964 #ifdef CONFIG_YAFFS_YAFFS2
13966 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
13967 - if (dev->writeChunkWithTagsToNAND &&
13968 - dev->readChunkWithTagsFromNAND &&
13969 - !dev->writeChunkToNAND &&
13970 - !dev->readChunkFromNAND &&
13971 - dev->markNANDBlockBad && dev->queryNANDBlock)
13972 + if (dev->param.writeChunkWithTagsToNAND &&
13973 + dev->param.readChunkWithTagsFromNAND &&
13974 + !dev->param.writeChunkToNAND &&
13975 + !dev->param.readChunkFromNAND &&
13976 + dev->param.markNANDBlockBad &&
13977 + dev->param.queryNANDBlock)
13981 /* Can use the "spare" style interface for yaffs1 */
13982 - if (!dev->isYaffs2 &&
13983 - !dev->writeChunkWithTagsToNAND &&
13984 - !dev->readChunkWithTagsFromNAND &&
13985 - dev->writeChunkToNAND &&
13986 - dev->readChunkFromNAND &&
13987 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
13988 + if (!dev->param.isYaffs2 &&
13989 + !dev->param.writeChunkWithTagsToNAND &&
13990 + !dev->param.readChunkWithTagsFromNAND &&
13991 + dev->param.writeChunkToNAND &&
13992 + dev->param.readChunkFromNAND &&
13993 + !dev->param.markNANDBlockBad &&
13994 + !dev->param.queryNANDBlock)
13997 - return 0; /* bad */
13998 + return 0; /* bad */
14002 @@ -7120,35 +5128,35 @@ int yaffs_GutsInitialise(yaffs_Device *d
14006 - dev->internalStartBlock = dev->startBlock;
14007 - dev->internalEndBlock = dev->endBlock;
14008 + dev->internalStartBlock = dev->param.startBlock;
14009 + dev->internalEndBlock = dev->param.endBlock;
14010 dev->blockOffset = 0;
14011 dev->chunkOffset = 0;
14012 dev->nFreeChunks = 0;
14014 - dev->gcBlock = -1;
14015 + dev->gcBlock = 0;
14017 - if (dev->startBlock == 0) {
14018 - dev->internalStartBlock = dev->startBlock + 1;
14019 - dev->internalEndBlock = dev->endBlock + 1;
14020 + if (dev->param.startBlock == 0) {
14021 + dev->internalStartBlock = dev->param.startBlock + 1;
14022 + dev->internalEndBlock = dev->param.endBlock + 1;
14023 dev->blockOffset = 1;
14024 - dev->chunkOffset = dev->nChunksPerBlock;
14025 + dev->chunkOffset = dev->param.nChunksPerBlock;
14028 /* Check geometry parameters. */
14030 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14031 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14032 - (dev->inbandTags && !dev->isYaffs2) ||
14033 - dev->nChunksPerBlock < 2 ||
14034 - dev->nReservedBlocks < 2 ||
14035 + if ((!dev->param.inbandTags && dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 1024) ||
14036 + (!dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 512) ||
14037 + (dev->param.inbandTags && !dev->param.isYaffs2) ||
14038 + dev->param.nChunksPerBlock < 2 ||
14039 + dev->param.nReservedBlocks < 2 ||
14040 dev->internalStartBlock <= 0 ||
14041 dev->internalEndBlock <= 0 ||
14042 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14043 + dev->internalEndBlock <= (dev->internalStartBlock + dev->param.nReservedBlocks + 2)) { /* otherwise it is too small */
14044 T(YAFFS_TRACE_ALWAYS,
14046 ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14047 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14048 + TENDSTR), dev->param.totalBytesPerChunk, dev->param.isYaffs2 ? "2" : "", dev->param.inbandTags));
14052 @@ -7159,10 +5167,10 @@ int yaffs_GutsInitialise(yaffs_Device *d
14055 /* Sort out space for inband tags, if required */
14056 - if (dev->inbandTags)
14057 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14058 + if (dev->param.inbandTags)
14059 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14061 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
14062 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk;
14064 /* Got the right mix of functions? */
14065 if (!yaffs_CheckDevFunctions(dev)) {
14066 @@ -7209,12 +5217,12 @@ int yaffs_GutsInitialise(yaffs_Device *d
14067 * We need to find the next power of 2 > than internalEndBlock
14070 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
14071 + x = dev->param.nChunksPerBlock * (dev->internalEndBlock + 1);
14073 bits = ShiftsGE(x);
14075 /* Set up tnode width if wide tnodes are enabled. */
14076 - if (!dev->wideTnodesDisabled) {
14077 + if (!dev->param.wideTnodesDisabled) {
14078 /* bits must be even so that we end up with 32-bit words */
14081 @@ -7238,10 +5246,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14083 dev->chunkGroupBits = bits - dev->tnodeWidth;
14085 + dev->tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
14086 + if(dev->tnodeSize < sizeof(yaffs_Tnode))
14087 + dev->tnodeSize = sizeof(yaffs_Tnode);
14089 dev->chunkGroupSize = 1 << dev->chunkGroupBits;
14091 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
14092 + if (dev->param.nChunksPerBlock < dev->chunkGroupSize) {
14093 /* We have a problem because the soft delete won't work if
14094 * the chunk group size > chunks per block.
14095 * This can be remedied by using larger "virtual blocks".
14096 @@ -7255,9 +5266,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14097 /* OK, we've finished verifying the device, lets continue with initialisation */
14099 /* More device initialisation */
14100 - dev->garbageCollections = 0;
14101 - dev->passiveGarbageCollections = 0;
14102 - dev->currentDirtyChecker = 0;
14104 + dev->passiveGCs = 0;
14105 + dev->oldestDirtyGCs = 0;
14106 + dev->backgroundGCs = 0;
14107 + dev->gcBlockFinder = 0;
14108 dev->bufferedBlock = -1;
14109 dev->doingBufferedBlockRewrite = 0;
14110 dev->nDeletedFiles = 0;
14111 @@ -7269,8 +5282,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14112 dev->tagsEccUnfixed = 0;
14113 dev->nErasureFailures = 0;
14114 dev->nErasedBlocks = 0;
14115 - dev->isDoingGC = 0;
14116 + dev->gcDisable= 0;
14117 dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
14118 + YINIT_LIST_HEAD(&dev->dirtyDirectories);
14119 + dev->oldestDirtySequence = 0;
14120 + dev->oldestDirtyBlock = 0;
14122 /* Initialise temporary buffers and caches. */
14123 if (!yaffs_InitialiseTempBuffers(dev))
14124 @@ -7281,13 +5297,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14127 if (!init_failed &&
14128 - dev->nShortOpCaches > 0) {
14129 + dev->param.nShortOpCaches > 0) {
14132 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
14133 + int srCacheBytes = dev->param.nShortOpCaches * sizeof(yaffs_ChunkCache);
14135 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14136 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14137 + if (dev->param.nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14138 + dev->param.nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14140 dev->srCache = YMALLOC(srCacheBytes);
14142 @@ -7296,11 +5312,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14144 memset(dev->srCache, 0, srCacheBytes);
14146 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
14147 + for (i = 0; i < dev->param.nShortOpCaches && buf; i++) {
14148 dev->srCache[i].object = NULL;
14149 dev->srCache[i].lastUse = 0;
14150 dev->srCache[i].dirty = 0;
14151 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
14152 + dev->srCache[i].data = buf = YMALLOC_DMA(dev->param.totalBytesPerChunk);
14156 @@ -7311,19 +5327,18 @@ int yaffs_GutsInitialise(yaffs_Device *d
14157 dev->cacheHits = 0;
14159 if (!init_failed) {
14160 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
14161 + dev->gcCleanupList = YMALLOC(dev->param.nChunksPerBlock * sizeof(__u32));
14162 if (!dev->gcCleanupList)
14166 - if (dev->isYaffs2)
14167 - dev->useHeaderFileSize = 1;
14168 + if (dev->param.isYaffs2)
14169 + dev->param.useHeaderFileSize = 1;
14171 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14174 - yaffs_InitialiseTnodes(dev);
14175 - yaffs_InitialiseObjects(dev);
14176 + yaffs_InitialiseTnodesAndObjects(dev);
14178 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14180 @@ -7331,8 +5346,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14182 if (!init_failed) {
14183 /* Now scan the flash. */
14184 - if (dev->isYaffs2) {
14185 - if (yaffs_CheckpointRestore(dev)) {
14186 + if (dev->param.isYaffs2) {
14187 + if (yaffs2_CheckpointRestore(dev)) {
14188 yaffs_CheckObjectDetailsLoaded(dev->rootDir);
14189 T(YAFFS_TRACE_ALWAYS,
14190 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
14191 @@ -7342,9 +5357,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14192 * and scan backwards.
14194 yaffs_DeinitialiseBlocks(dev);
14195 - yaffs_DeinitialiseTnodes(dev);
14196 - yaffs_DeinitialiseObjects(dev);
14198 + yaffs_DeinitialiseTnodesAndObjects(dev);
14200 dev->nErasedBlocks = 0;
14201 dev->nFreeChunks = 0;
14202 @@ -7353,24 +5367,25 @@ int yaffs_GutsInitialise(yaffs_Device *d
14203 dev->nDeletedFiles = 0;
14204 dev->nUnlinkedFiles = 0;
14205 dev->nBackgroundDeletions = 0;
14206 - dev->oldestDirtySequence = 0;
14208 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14211 - yaffs_InitialiseTnodes(dev);
14212 - yaffs_InitialiseObjects(dev);
14213 + yaffs_InitialiseTnodesAndObjects(dev);
14215 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14218 - if (!init_failed && !yaffs_ScanBackwards(dev))
14219 + if (!init_failed && !yaffs2_ScanBackwards(dev))
14222 - } else if (!yaffs_Scan(dev))
14223 + } else if (!yaffs1_Scan(dev))
14226 yaffs_StripDeletedObjects(dev);
14227 + yaffs_FixHangingObjects(dev);
14228 + if(dev->param.emptyLostAndFound)
14229 + yaffs_EmptyLostAndFound(dev);
14233 @@ -7394,6 +5409,9 @@ int yaffs_GutsInitialise(yaffs_Device *d
14234 yaffs_VerifyFreeChunks(dev);
14235 yaffs_VerifyBlocks(dev);
14237 + /* Clean up any aborted checkpoint data */
14238 + if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
14239 + yaffs2_InvalidateCheckpoint(dev);
14241 T(YAFFS_TRACE_TRACING,
14242 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
14243 @@ -7407,12 +5425,11 @@ void yaffs_Deinitialise(yaffs_Device *de
14246 yaffs_DeinitialiseBlocks(dev);
14247 - yaffs_DeinitialiseTnodes(dev);
14248 - yaffs_DeinitialiseObjects(dev);
14249 - if (dev->nShortOpCaches > 0 &&
14250 + yaffs_DeinitialiseTnodesAndObjects(dev);
14251 + if (dev->param.nShortOpCaches > 0 &&
14254 - for (i = 0; i < dev->nShortOpCaches; i++) {
14255 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
14256 if (dev->srCache[i].data)
14257 YFREE(dev->srCache[i].data);
14258 dev->srCache[i].data = NULL;
14259 @@ -7429,34 +5446,33 @@ void yaffs_Deinitialise(yaffs_Device *de
14261 dev->isMounted = 0;
14263 - if (dev->deinitialiseNAND)
14264 - dev->deinitialiseNAND(dev);
14265 + if (dev->param.deinitialiseNAND)
14266 + dev->param.deinitialiseNAND(dev);
14270 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
14271 +int yaffs_CountFreeChunks(yaffs_Device *dev)
14277 yaffs_BlockInfo *blk;
14279 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
14281 - blk = yaffs_GetBlockInfo(dev, b);
14283 + blk = dev->blockInfo;
14284 + for (b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) {
14285 switch (blk->blockState) {
14286 case YAFFS_BLOCK_STATE_EMPTY:
14287 case YAFFS_BLOCK_STATE_ALLOCATING:
14288 case YAFFS_BLOCK_STATE_COLLECTING:
14289 case YAFFS_BLOCK_STATE_FULL:
14291 - (dev->nChunksPerBlock - blk->pagesInUse +
14292 + (dev->param.nChunksPerBlock - blk->pagesInUse +
14293 blk->softDeletions);
14302 @@ -7481,21 +5497,19 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14304 /* Now count the number of dirty chunks in the cache and subtract those */
14306 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
14307 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.nShortOpCaches; i++) {
14308 if (dev->srCache[i].dirty)
14309 nDirtyCacheChunks++;
14312 nFree -= nDirtyCacheChunks;
14314 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
14315 + nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock);
14317 /* Now we figure out how much to reserve for the checkpoint and report that... */
14318 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
14319 - if (blocksForCheckpoint < 0)
14320 - blocksForCheckpoint = 0;
14321 + blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev);
14323 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
14324 + nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock);
14328 @@ -7504,27 +5518,6 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14332 -static int yaffs_freeVerificationFailures;
14334 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
14339 - if (yaffs_SkipVerification(dev))
14342 - counted = yaffs_CountFreeChunks(dev);
14344 - difference = dev->nFreeChunks - counted;
14346 - if (difference) {
14347 - T(YAFFS_TRACE_ALWAYS,
14348 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
14349 - dev->nFreeChunks, counted, difference));
14350 - yaffs_freeVerificationFailures++;
14354 /*---------------------------------------- YAFFS test code ----------------------*/
14356 @@ -7532,7 +5525,7 @@ static void yaffs_VerifyFreeChunks(yaffs
14358 if (sizeof(structure) != syze) { \
14359 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
14360 - name, syze, sizeof(structure))); \
14361 + name, syze, (int) sizeof(structure))); \
14362 return YAFFS_FAIL; \
14365 @@ -7542,9 +5535,8 @@ static int yaffs_CheckStructures(void)
14366 /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
14367 /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
14368 /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
14369 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
14370 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
14372 +/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
14374 #ifndef CONFIG_YAFFS_WINCE
14375 yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
14377 --- a/fs/yaffs2/yaffs_guts.h
14378 +++ b/fs/yaffs2/yaffs_guts.h
14381 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14383 - * Copyright (C) 2002-2007 Aleph One Ltd.
14384 + * Copyright (C) 2002-2010 Aleph One Ltd.
14385 * for Toby Churchill Ltd and Brightstar Engineering
14387 * Created by Charles Manning <charles@aleph1.co.uk>
14389 #ifndef __YAFFS_GUTS_H__
14390 #define __YAFFS_GUTS_H__
14392 -#include "devextras.h"
14393 #include "yportenv.h"
14394 +#include "devextras.h"
14395 +#include "yaffs_list.h"
14398 #define YAFFS_FAIL 0
14401 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
14403 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
14405 #define YAFFS_ALLOCATION_NOBJECTS 100
14406 #define YAFFS_ALLOCATION_NTNODES 100
14410 #define YAFFS_OBJECT_SPACE 0x40000
14411 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
14413 -#define YAFFS_CHECKPOINT_VERSION 3
14414 +#define YAFFS_CHECKPOINT_VERSION 4
14416 #ifdef CONFIG_YAFFS_UNICODE
14417 #define YAFFS_MAX_NAME_LENGTH 127
14418 @@ -81,12 +82,11 @@
14419 #define YAFFS_OBJECTID_UNLINKED 3
14420 #define YAFFS_OBJECTID_DELETED 4
14422 -/* Sseudo object ids for checkpointing */
14423 +/* Pseudo object ids for checkpointing */
14424 #define YAFFS_OBJECTID_SB_HEADER 0x10
14425 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
14426 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
14430 #define YAFFS_MAX_SHORT_OP_CACHES 20
14432 @@ -119,11 +119,7 @@ typedef struct {
14434 int nBytes; /* Only valid if the cache is dirty */
14435 int locked; /* Can't push out or flush while locked. */
14436 -#ifdef CONFIG_YAFFS_YAFFS2
14439 - __u8 data[YAFFS_BYTES_PER_CHUNK];
14441 } yaffs_ChunkCache;
14444 @@ -234,6 +230,8 @@ typedef enum {
14445 YAFFS_BLOCK_STATE_UNKNOWN = 0,
14447 YAFFS_BLOCK_STATE_SCANNING,
14448 + /* Being scanned */
14450 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
14451 /* The block might have something on it (ie it is allocating or full, perhaps empty)
14452 * but it needs to be scanned to determine its true state.
14453 @@ -249,21 +247,23 @@ typedef enum {
14454 /* This block is partially allocated.
14455 * At least one page holds valid data.
14456 * This is the one currently being used for page
14457 - * allocation. Should never be more than one of these
14458 + * allocation. Should never be more than one of these.
14459 + * If a block is only partially allocated at mount it is treated as full.
14462 YAFFS_BLOCK_STATE_FULL,
14463 /* All the pages in this block have been allocated.
14464 + * If a block was only partially allocated when mounted we treat
14465 + * it as fully allocated.
14468 YAFFS_BLOCK_STATE_DIRTY,
14469 - /* All pages have been allocated and deleted.
14470 + /* The block was full and now all chunks have been deleted.
14471 * Erase me, reuse me.
14474 YAFFS_BLOCK_STATE_CHECKPOINT,
14475 - /* This block is assigned to holding checkpoint data.
14477 + /* This block is assigned to holding checkpoint data. */
14479 YAFFS_BLOCK_STATE_COLLECTING,
14480 /* This block is being garbage collected */
14481 @@ -351,23 +351,12 @@ typedef struct {
14482 /*--------------------------- Tnode -------------------------- */
14484 union yaffs_Tnode_union {
14485 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
14486 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
14488 union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
14490 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
14494 typedef union yaffs_Tnode_union yaffs_Tnode;
14496 -struct yaffs_TnodeList_struct {
14497 - struct yaffs_TnodeList_struct *next;
14498 - yaffs_Tnode *tnodes;
14501 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
14503 /*------------------------ Object -----------------------------*/
14504 /* An object can be one of:
14505 @@ -387,6 +376,7 @@ typedef struct {
14508 struct ylist_head children; /* list of child links */
14509 + struct ylist_head dirty; /* Entry for list of dirty directories */
14510 } yaffs_DirectoryStructure;
14513 @@ -405,6 +395,8 @@ typedef union {
14514 yaffs_HardLinkStructure hardLinkVariant;
14515 } yaffs_ObjectVariant;
14519 struct yaffs_ObjectStruct {
14520 __u8 deleted:1; /* This should only apply to unlinked files. */
14521 __u8 softDeleted:1; /* it has also been soft deleted */
14522 @@ -424,6 +416,10 @@ struct yaffs_ObjectStruct {
14523 * until the inode is released.
14525 __u8 beingCreated:1; /* This object is still being created so skip some checks. */
14526 + __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */
14528 + __u8 xattrKnown:1; /* We know if this has object has xattribs or not. */
14529 + __u8 hasXattr:1; /* This object has xattribs. Valid if xattrKnown. */
14531 __u8 serial; /* serial number of chunk in NAND. Cached here */
14532 __u16 sum; /* sum of the name to speed searching */
14533 @@ -452,10 +448,6 @@ struct yaffs_ObjectStruct {
14534 YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
14537 -#ifndef __KERNEL__
14541 #ifdef CONFIG_YAFFS_WINCE
14542 __u32 win_ctime[2];
14543 __u32 win_mtime[2];
14544 @@ -470,10 +462,7 @@ struct yaffs_ObjectStruct {
14549 - struct inode *myInode;
14554 yaffs_ObjectType variantType;
14556 @@ -483,13 +472,6 @@ struct yaffs_ObjectStruct {
14558 typedef struct yaffs_ObjectStruct yaffs_Object;
14560 -struct yaffs_ObjectList_struct {
14561 - yaffs_Object *objects;
14562 - struct yaffs_ObjectList_struct *next;
14565 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
14568 struct ylist_head list;
14570 @@ -531,12 +513,18 @@ typedef struct {
14572 /*----------------- Device ---------------------------------*/
14574 -struct yaffs_DeviceStruct {
14575 - struct ylist_head devList;
14576 - const char *name;
14578 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
14579 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
14580 +struct yaffs_DeviceParamStruct {
14581 + const YCHAR *name;
14584 + * Entry parameters set up way early. Yaffs sets up the rest.
14585 + * The structure should be zeroed out before use so that unused
14586 + * and defualt values are zero.
14589 + int inbandTags; /* Use unband tags */
14590 + __u32 totalBytesPerChunk; /* Should be >= 512, does not need to be a power of 2 */
14591 int nChunksPerBlock; /* does not need to be a power of 2 */
14592 int spareBytesPerChunk; /* spare area size */
14593 int startBlock; /* Start block we're allowed to use */
14594 @@ -545,24 +533,24 @@ struct yaffs_DeviceStruct {
14595 /* reserved blocks on NOR and RAM. */
14598 - /* Stuff used by the shared space checkpointing mechanism */
14599 - /* If this value is zero, then this mechanism is disabled */
14601 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
14604 int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
14605 - * the number of short op caches (don't use too many)
14606 + * the number of short op caches (don't use too many).
14607 + * 10 to 20 is a good bet.
14609 + int useNANDECC; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
14610 + int noTagsECC; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
14612 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14613 + int isYaffs2; /* Use yaffs2 mode on this device */
14615 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
14616 + int emptyLostAndFound; /* Auto-empty lost+found directory on mount */
14618 - void *genericDevice; /* Pointer to device context
14619 - * On an mtd this holds the mtd pointer.
14621 - void *superBlock;
14622 + int refreshPeriod; /* How often we should check to do a block refresh */
14624 + /* Checkpoint control. Can be set before or after initialisation */
14625 + __u8 skipCheckpointRead;
14626 + __u8 skipCheckpointWrite;
14628 + int enableXattr; /* Enable xattribs */
14630 /* NAND access functions (Must be set before calling YAFFS)*/
14632 @@ -589,58 +577,68 @@ struct yaffs_DeviceStruct {
14633 yaffs_BlockState *state, __u32 *sequenceNumber);
14638 /* The removeObjectCallback function must be supplied by OS flavours that
14639 - * need it. The Linux kernel does not use this, but yaffs direct does use
14640 - * it to implement the faster readdir
14642 + * yaffs direct uses it to implement the faster readdir.
14643 + * Linux uses it to protect the directory during unlocking.
14645 void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
14647 - /* Callback to mark the superblock dirsty */
14648 - void (*markSuperBlockDirty)(void *superblock);
14649 + /* Callback to mark the superblock dirty */
14650 + void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev);
14652 + /* Callback to control garbage collection. */
14653 + unsigned (*gcControl)(struct yaffs_DeviceStruct *dev);
14655 + /* Debug control flags. Don't use unless you know what you're doing */
14656 + int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14657 + int disableLazyLoad; /* Disable lazy loading on this device */
14658 int wideTnodesDisabled; /* Set to disable wide tnodes */
14659 + int disableSoftDelete; /* yaffs 1 only: Set to disable the use of softdeletion. */
14661 + int deferDirectoryUpdate; /* Set to defer directory updates */
14663 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14666 + int alwaysCheckErased; /* Force chunk erased check always on */
14669 - YCHAR *pathDividers; /* String of legal path dividers */
14670 +typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam;
14672 +struct yaffs_DeviceStruct {
14673 + struct yaffs_DeviceParamStruct param;
14675 - /* End of stuff that must be set before initialisation. */
14676 + /* Context storage. Holds extra OS specific data for this device */
14678 - /* Checkpoint control. Can be set before or after initialisation */
14679 - __u8 skipCheckpointRead;
14680 - __u8 skipCheckpointWrite;
14682 + void *driverContext;
14684 + struct ylist_head devList;
14686 /* Runtime parameters. Set up by YAFFS. */
14687 + int nDataBytesPerChunk;
14689 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
14690 + /* Non-wide tnode stuff */
14691 + __u16 chunkGroupBits; /* Number of bits that need to be resolved if
14692 + * the tnodes are not wide enough.
14694 __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
14696 /* Stuff to support wide tnodes */
14701 /* Stuff for figuring out file offset to chunk conversions */
14702 __u32 chunkShift; /* Shift value */
14703 __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
14704 __u32 chunkMask; /* Mask to use for power-of-2 case */
14706 - /* Stuff to handle inband tags */
14708 - __u32 totalBytesPerChunk;
14712 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
14713 - struct semaphore grossLock; /* Gross locking semaphore */
14714 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
14715 - * at compile time so we have to allocate it.
14717 - void (*putSuperFunc) (struct super_block *sb);
14724 int isCheckpointed;
14727 @@ -682,51 +680,31 @@ struct yaffs_DeviceStruct {
14728 __u32 allocationPage;
14729 int allocationBlockFinder; /* Used to search for next allocation block */
14731 - /* Runtime state */
14732 - int nTnodesCreated;
14733 - yaffs_Tnode *freeTnodes;
14735 - yaffs_TnodeList *allocatedTnodeList;
14741 - int nObjectsCreated;
14742 - yaffs_Object *freeObjects;
14743 - int nFreeObjects;
14744 + /* Object and Tnode memory management */
14751 - yaffs_ObjectList *allocatedObjectList;
14753 yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
14754 + __u32 bucketFinder;
14758 - int currentDirtyChecker; /* Used to find current dirtiest block */
14760 + /* Garbage collection control */
14761 __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
14762 - int nonAggressiveSkip; /* GC state/mode */
14768 - int nBlockErasures;
14769 - int nErasureFailures;
14771 - int garbageCollections;
14772 - int passiveGarbageCollections;
14773 - int nRetriedWrites;
14774 - int nRetiredBlocks;
14777 - int tagsEccFixed;
14778 - int tagsEccUnfixed;
14780 - int nUnmarkedDeletions;
14782 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14783 + unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14784 + unsigned gcDisable;
14785 + unsigned gcBlockFinder;
14786 + unsigned gcDirtiest;
14787 + unsigned gcPagesInUse;
14788 + unsigned gcNotDone;
14789 + unsigned gcBlock;
14790 + unsigned gcChunk;
14793 /* Special directories */
14794 yaffs_Object *rootDir;
14795 @@ -743,8 +721,6 @@ struct yaffs_DeviceStruct {
14796 yaffs_ChunkCache *srCache;
14801 /* Stuff for background deletion and unlinked files.*/
14802 yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
14803 yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
14804 @@ -753,7 +729,6 @@ struct yaffs_DeviceStruct {
14805 int nUnlinkedFiles; /* Count of unlinked files. */
14806 int nBackgroundDeletions; /* Count of background deletions. */
14809 /* Temporary buffer management */
14810 yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
14812 @@ -764,6 +739,36 @@ struct yaffs_DeviceStruct {
14813 /* yaffs2 runtime stuff */
14814 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14815 unsigned oldestDirtySequence;
14816 + unsigned oldestDirtyBlock;
14818 + /* Block refreshing */
14819 + int refreshSkip; /* A skip down counter. Refresh happens when this gets to zero. */
14821 + /* Dirty directory handling */
14822 + struct ylist_head dirtyDirectories; /* List of dirty directories */
14826 + __u32 nPageWrites;
14827 + __u32 nPageReads;
14828 + __u32 nBlockErasures;
14829 + __u32 nErasureFailures;
14832 + __u32 passiveGCs;
14833 + __u32 oldestDirtyGCs;
14835 + __u32 backgroundGCs;
14836 + __u32 nRetriedWrites;
14837 + __u32 nRetiredBlocks;
14839 + __u32 eccUnfixed;
14840 + __u32 tagsEccFixed;
14841 + __u32 tagsEccUnfixed;
14842 + __u32 nDeletions;
14843 + __u32 nUnmarkedDeletions;
14844 + __u32 refreshCount;
14849 @@ -796,7 +801,6 @@ typedef struct {
14851 /* yaffs2 runtime stuff */
14852 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14853 - unsigned oldestDirtySequence;
14855 } yaffs_CheckpointDevice;
14857 @@ -809,6 +813,23 @@ typedef struct {
14858 } yaffs_CheckpointValidity;
14861 +struct yaffs_ShadowFixerStruct {
14864 + struct yaffs_ShadowFixerStruct *next;
14867 +/* Structure for doing xattr modifications */
14869 + int set; /* If 0 then this is a deletion */
14870 + const YCHAR *name;
14871 + const void *data;
14878 /*----------------------- YAFFS Functions -----------------------*/
14880 int yaffs_GutsInitialise(yaffs_Device *dev);
14881 @@ -840,7 +861,8 @@ int yaffs_ResizeFile(yaffs_Object *obj,
14883 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
14884 __u32 mode, __u32 uid, __u32 gid);
14885 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
14887 +int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync);
14889 /* Flushing and checkpointing */
14890 void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
14891 @@ -873,6 +895,12 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Objec
14892 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
14893 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
14896 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags);
14897 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size);
14898 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size);
14899 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name);
14901 /* Special directories */
14902 yaffs_Object *yaffs_Root(yaffs_Device *dev);
14903 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
14904 @@ -882,18 +910,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Dev
14905 void yfsd_WinFileTimeNow(__u32 target[2]);
14910 void yaffs_HandleDeferedFree(yaffs_Object *obj);
14913 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev);
14915 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency);
14918 int yaffs_DumpObject(yaffs_Object *obj);
14920 void yaffs_GutsTest(yaffs_Device *dev);
14922 -/* A few useful functions */
14923 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
14924 +/* A few useful functions to be used within the core files*/
14925 void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
14926 int yaffs_CheckFF(__u8 *buffer, int nBytes);
14927 void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
14928 @@ -901,4 +929,41 @@ void yaffs_HandleChunkError(yaffs_Device
14929 __u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
14930 void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
14932 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
14934 + yaffs_ObjectType type);
14935 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
14936 + int chunkInNAND, int inScan);
14937 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name);
14938 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh);
14939 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14940 + yaffs_Object *obj);
14941 +YCHAR *yaffs_CloneString(const YCHAR *str);
14942 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
14943 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo);
14944 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
14945 + int force, int isShrink, int shadows,
14946 + yaffs_XAttrMod *xop);
14947 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
14948 + int backwardScanning);
14949 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks);
14950 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev);
14951 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
14952 + yaffs_FileStructure *fStruct,
14954 + yaffs_Tnode *passedTn);
14956 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
14957 + int nBytes, int writeThrough);
14958 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize);
14959 +void yaffs_SkipRestOfBlock(yaffs_Device *dev);
14961 +int yaffs_CountFreeChunks(yaffs_Device *dev);
14963 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
14964 + yaffs_FileStructure *fStruct,
14967 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
14970 --- a/fs/yaffs2/yaffsinterface.h
14971 +++ b/fs/yaffs2/yaffsinterface.h
14974 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14976 - * Copyright (C) 2002-2007 Aleph One Ltd.
14977 + * Copyright (C) 2002-2010 Aleph One Ltd.
14978 * for Toby Churchill Ltd and Brightstar Engineering
14980 * Created by Charles Manning <charles@aleph1.co.uk>
14982 +++ b/fs/yaffs2/yaffs_linux_allocator.c
14985 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14987 + * Copyright (C) 2002-2010 Aleph One Ltd.
14988 + * for Toby Churchill Ltd and Brightstar Engineering
14990 + * Created by Charles Manning <charles@aleph1.co.uk>
14992 + * This program is free software; you can redistribute it and/or modify
14993 + * it under the terms of the GNU Lesser General Public License version 2.1 as
14994 + * published by the Free Software Foundation.
14996 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14998 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
15002 +#include "yaffs_allocator.h"
15003 +#include "yaffs_guts.h"
15004 +#include "yaffs_trace.h"
15005 +#include "yportenv.h"
15006 +#include "yaffs_linux.h"
15008 + * Start out with the same allocator as yaffs direct.
15009 + * Todo: Change to Linux slab allocator.
15014 +#define NAMELEN 20
15015 +struct yaffs_AllocatorStruct {
15016 + char tnode_name[NAMELEN+1];
15017 + char object_name[NAMELEN+1];
15018 + struct kmem_cache *tnode_cache;
15019 + struct kmem_cache *object_cache;
15022 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
15026 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
15028 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
15030 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
15033 + if(allocator->tnode_cache){
15034 + kmem_cache_destroy(allocator->tnode_cache);
15035 + allocator->tnode_cache = NULL;
15037 + T(YAFFS_TRACE_ALWAYS,
15038 + (TSTR("NULL tnode cache\n")));
15042 + if(allocator->object_cache){
15043 + kmem_cache_destroy(allocator->object_cache);
15044 + allocator->object_cache = NULL;
15046 + T(YAFFS_TRACE_ALWAYS,
15047 + (TSTR("NULL object cache\n")));
15051 + YFREE(allocator);
15054 + T(YAFFS_TRACE_ALWAYS,
15055 + (TSTR("Deinitialising NULL allocator\n")));
15058 + dev->allocator = NULL;
15062 +static void fake_ctor0(void *data){data = data;}
15063 +static void fake_ctor1(void *data){data = data;}
15064 +static void fake_ctor2(void *data){data = data;}
15065 +static void fake_ctor3(void *data){data = data;}
15066 +static void fake_ctor4(void *data){data = data;}
15067 +static void fake_ctor5(void *data){data = data;}
15068 +static void fake_ctor6(void *data){data = data;}
15069 +static void fake_ctor7(void *data){data = data;}
15070 +static void fake_ctor8(void *data){data = data;}
15071 +static void fake_ctor9(void *data){data = data;}
15073 +static void (*fake_ctor_list[10]) (void *) = {
15086 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
15088 + yaffs_Allocator *allocator;
15089 + unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id;
15091 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
15093 + if(dev->allocator)
15095 + else if(mount_id >= 10){
15096 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
15098 + allocator = YMALLOC(sizeof(yaffs_Allocator));
15099 + memset(allocator,0,sizeof(yaffs_Allocator));
15100 + dev->allocator = allocator;
15102 + if(!dev->allocator){
15103 + T(YAFFS_TRACE_ALWAYS,
15104 + (TSTR("yaffs allocator creation failed\n")));
15110 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
15111 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
15113 + allocator->tnode_cache =
15114 + kmem_cache_create(allocator->tnode_name,
15117 + fake_ctor_list[mount_id]);
15118 + if(allocator->tnode_cache)
15119 + T(YAFFS_TRACE_ALLOCATE,
15120 + (TSTR("tnode cache \"%s\" %p\n"),
15121 + allocator->tnode_name,allocator->tnode_cache));
15123 + T(YAFFS_TRACE_ALWAYS,
15124 + (TSTR("yaffs cache creation failed\n")));
15129 + allocator->object_cache =
15130 + kmem_cache_create(allocator->object_name,
15131 + sizeof(yaffs_Object),
15133 + fake_ctor_list[mount_id]);
15135 + if(allocator->object_cache)
15136 + T(YAFFS_TRACE_ALLOCATE,
15137 + (TSTR("object cache \"%s\" %p\n"),
15138 + allocator->object_name,allocator->object_cache));
15141 + T(YAFFS_TRACE_ALWAYS,
15142 + (TSTR("yaffs cache creation failed\n")));
15149 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
15151 + yaffs_Allocator *allocator = dev->allocator;
15152 + if(!allocator || !allocator->tnode_cache){
15156 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
15159 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
15161 + yaffs_Allocator *allocator = dev->allocator;
15162 + kmem_cache_free(allocator->tnode_cache,tn);
15165 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
15167 + yaffs_Allocator *allocator = dev->allocator;
15172 + if(!allocator->object_cache){
15176 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
15179 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
15181 + yaffs_Allocator *allocator = dev->allocator;
15182 + kmem_cache_free(allocator->object_cache,obj);
15185 +++ b/fs/yaffs2/yaffs_linux.h
15188 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15190 + * Copyright (C) 2002-2010 Aleph One Ltd.
15191 + * for Toby Churchill Ltd and Brightstar Engineering
15193 + * Created by Charles Manning <charles@aleph1.co.uk>
15195 + * This program is free software; you can redistribute it and/or modify
15196 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15197 + * published by the Free Software Foundation.
15199 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15202 +#ifndef __YAFFS_LINUX_H__
15203 +#define __YAFFS_LINUX_H__
15205 +#include "devextras.h"
15206 +#include "yportenv.h"
15208 +struct yaffs_LinuxContext {
15209 + struct ylist_head contextList; /* List of these we have mounted */
15210 + struct yaffs_DeviceStruct *dev;
15211 + struct super_block * superBlock;
15212 + struct task_struct *bgThread; /* Background thread for this device */
15214 + struct semaphore grossLock; /* Gross locking semaphore */
15215 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
15216 + * at compile time so we have to allocate it.
15218 + struct ylist_head searchContexts;
15219 + void (*putSuperFunc)(struct super_block *sb);
15221 + struct task_struct *readdirProcess;
15222 + unsigned mount_id;
15225 +#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext))
15226 +#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext))
15231 +++ b/fs/yaffs2/yaffs_list.h
15234 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15236 + * Copyright (C) 2002-2010 Aleph One Ltd.
15237 + * for Toby Churchill Ltd and Brightstar Engineering
15239 + * Created by Charles Manning <charles@aleph1.co.uk>
15241 + * This program is free software; you can redistribute it and/or modify
15242 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15243 + * published by the Free Software Foundation.
15245 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15249 + * This file is just holds extra declarations of macros that would normally
15250 + * be providesd in the Linux kernel. These macros have been written from
15251 + * scratch but are functionally equivalent to the Linux ones.
15255 +#ifndef __YAFFS_LIST_H__
15256 +#define __YAFFS_LIST_H__
15259 +#include "yportenv.h"
15262 + * This is a simple doubly linked list implementation that matches the
15263 + * way the Linux kernel doubly linked list implementation works.
15266 +struct ylist_head {
15267 + struct ylist_head *next; /* next in chain */
15268 + struct ylist_head *prev; /* previous in chain */
15272 +/* Initialise a static list */
15273 +#define YLIST_HEAD(name) \
15274 +struct ylist_head name = { &(name), &(name)}
15278 +/* Initialise a list head to an empty list */
15279 +#define YINIT_LIST_HEAD(p) \
15281 + (p)->next = (p);\
15282 + (p)->prev = (p); \
15286 +/* Add an element to a list */
15287 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
15288 + struct ylist_head *list)
15290 + struct ylist_head *listNext = list->next;
15292 + list->next = newEntry;
15293 + newEntry->prev = list;
15294 + newEntry->next = listNext;
15295 + listNext->prev = newEntry;
15299 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
15300 + struct ylist_head *list)
15302 + struct ylist_head *listPrev = list->prev;
15304 + list->prev = newEntry;
15305 + newEntry->next = list;
15306 + newEntry->prev = listPrev;
15307 + listPrev->next = newEntry;
15312 +/* Take an element out of its current list, with or without
15313 + * reinitialising the links.of the entry*/
15314 +static Y_INLINE void ylist_del(struct ylist_head *entry)
15316 + struct ylist_head *listNext = entry->next;
15317 + struct ylist_head *listPrev = entry->prev;
15319 + listNext->prev = listPrev;
15320 + listPrev->next = listNext;
15324 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
15326 + ylist_del(entry);
15327 + entry->next = entry->prev = entry;
15331 +/* Test if the list is empty */
15332 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
15334 + return (entry->next == entry);
15338 +/* ylist_entry takes a pointer to a list entry and offsets it to that
15339 + * we can find a pointer to the object it is embedded in.
15343 +#define ylist_entry(entry, type, member) \
15344 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
15347 +/* ylist_for_each and list_for_each_safe iterate over lists.
15348 + * ylist_for_each_safe uses temporary storage to make the list delete safe
15351 +#define ylist_for_each(itervar, list) \
15352 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
15354 +#define ylist_for_each_safe(itervar, saveVar, list) \
15355 + for (itervar = (list)->next, saveVar = (list)->next->next; \
15356 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
15360 --- a/fs/yaffs2/yaffs_mtdif1.c
15361 +++ b/fs/yaffs2/yaffs_mtdif1.c
15363 * YAFFS: Yet another FFS. A NAND-flash specific file system.
15364 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15366 - * Copyright (C) 2002 Aleph One Ltd.
15367 + * Copyright (C) 2002-2010 Aleph One Ltd.
15368 * for Toby Churchill Ltd and Brightstar Engineering
15370 * This program is free software; you can redistribute it and/or modify
15374 #include "yportenv.h"
15375 +#include "yaffs_trace.h"
15376 #include "yaffs_guts.h"
15377 #include "yaffs_packedtags1.h"
15378 #include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
15379 +#include "yaffs_linux.h"
15381 #include "linux/kernel.h"
15382 #include "linux/version.h"
15384 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15385 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
15387 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
15389 #ifndef CONFIG_YAFFS_9BYTE_TAGS
15390 # define YTAG1_SIZE 8
15392 @@ -91,7 +91,7 @@ static struct nand_ecclayout nand_oob_16
15393 int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15394 int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
15396 - struct mtd_info *mtd = dev->genericDevice;
15397 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15398 int chunkBytes = dev->nDataBytesPerChunk;
15399 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15400 struct mtd_oob_ops ops;
15401 @@ -102,8 +102,6 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15402 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15403 compile_time_assertion(sizeof(yaffs_Tags) == 8);
15405 - dev->nPageWrites++;
15407 yaffs_PackTags1(&pt1, etags);
15408 yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15410 @@ -137,9 +135,9 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15412 retval = mtd->write_oob(mtd, addr, &ops);
15414 - yaffs_trace(YAFFS_TRACE_MTD,
15415 - "write_oob failed, chunk %d, mtd error %d\n",
15416 - chunkInNAND, retval);
15417 + T(YAFFS_TRACE_MTD,
15418 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
15419 + chunkInNAND, retval));
15421 return retval ? YAFFS_FAIL : YAFFS_OK;
15423 @@ -171,7 +169,7 @@ static int rettags(yaffs_ExtendedTags *e
15424 int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15425 int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
15427 - struct mtd_info *mtd = dev->genericDevice;
15428 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15429 int chunkBytes = dev->nDataBytesPerChunk;
15430 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15431 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15432 @@ -180,8 +178,6 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15436 - dev->nPageReads++;
15438 memset(&ops, 0, sizeof(ops));
15439 ops.mode = MTD_OOB_AUTO;
15440 ops.len = (data) ? chunkBytes : 0;
15441 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15443 retval = mtd->read_oob(mtd, addr, &ops);
15445 - yaffs_trace(YAFFS_TRACE_MTD,
15446 - "read_oob failed, chunk %d, mtd error %d\n",
15447 - chunkInNAND, retval);
15448 + T(YAFFS_TRACE_MTD,
15449 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
15450 + chunkInNAND, retval));
15454 @@ -284,11 +280,11 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15456 int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15458 - struct mtd_info *mtd = dev->genericDevice;
15459 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15460 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15461 + int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk;
15464 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
15465 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), blockNo));
15467 retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15468 return (retval) ? YAFFS_FAIL : YAFFS_OK;
15469 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
15470 int oobavail = mtd->ecclayout->oobavail;
15472 if (oobavail < YTAG1_SIZE) {
15473 - yaffs_trace(YAFFS_TRACE_ERROR,
15474 - "mtd device has only %d bytes for tags, need %d\n",
15475 - oobavail, YTAG1_SIZE);
15476 + T(YAFFS_TRACE_ERROR,
15477 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
15478 + oobavail, YTAG1_SIZE));
15482 @@ -325,8 +321,8 @@ static int nandmtd1_TestPrerequists(stru
15483 int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15484 yaffs_BlockState *pState, __u32 *pSequenceNumber)
15486 - struct mtd_info *mtd = dev->genericDevice;
15487 - int chunkNo = blockNo * dev->nChunksPerBlock;
15488 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15489 + int chunkNo = blockNo * dev->param.nChunksPerBlock;
15490 loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
15491 yaffs_ExtendedTags etags;
15492 int state = YAFFS_BLOCK_STATE_DEAD;
15493 @@ -342,8 +338,8 @@ int nandmtd1_QueryNANDBlock(struct yaffs
15494 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15495 etags.blockBad = (mtd->block_isbad)(mtd, addr);
15496 if (etags.blockBad) {
15497 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15498 - "block %d is marked bad\n", blockNo);
15499 + T(YAFFS_TRACE_BAD_BLOCKS,
15500 + (TSTR("block %d is marked bad"TENDSTR), blockNo));
15501 state = YAFFS_BLOCK_STATE_DEAD;
15502 } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
15503 /* bad tags, need to look more closely */
15504 --- a/fs/yaffs2/yaffs_mtdif1-compat.c
15507 -From ian@brightstareng.com Fri May 18 15:06:49 2007
15508 -From ian@brightstareng.com Fri May 18 15:08:21 2007
15509 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
15510 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
15511 - (envelope-from <ian@brightstareng.com>)
15512 - id 1Hp380-00011e-T6
15513 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
15514 -Received: from localhost (localhost.localdomain [127.0.0.1])
15515 - by zebra.brightstareng.com (Postfix) with ESMTP
15516 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
15517 -Received: from zebra.brightstareng.com ([127.0.0.1])
15518 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
15519 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
15520 -Received: from pippin (unknown [192.168.1.25])
15521 - by zebra.brightstareng.com (Postfix) with ESMTP
15522 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
15523 -From: Ian McDonnell <ian@brightstareng.com>
15524 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
15525 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
15526 -Date: Fri, 18 May 2007 10:06:49 -0400
15527 -User-Agent: KMail/1.9.1
15528 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
15529 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
15530 -Cc: Andrea Conti <alyf@alyf.net>,
15531 - Charles Manning <manningc2@actrix.gen.nz>
15533 -Content-Type: Multipart/Mixed;
15534 - boundary="Boundary-00=_5LbTGmt62YoutxM"
15535 -Message-Id: <200705181006.49860.ian@brightstareng.com>
15536 -X-Virus-Scanned: by amavisd-new at brightstareng.com
15539 -X-KMail-EncryptionState:
15540 -X-KMail-SignatureState:
15543 ---Boundary-00=_5LbTGmt62YoutxM
15544 -Content-Type: text/plain;
15545 - charset="iso-8859-15"
15546 -Content-Transfer-Encoding: 7bit
15547 -Content-Disposition: inline
15551 -On Friday 18 May 2007 08:34, you wrote:
15552 -> Yea team. With this fix in place (I put it in the wrong place
15553 -> at first) I can now mount and ls the Yaffs partition without
15554 -> an error messages!
15558 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
15559 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
15560 -See the LINUX_VERSION_CODE conditional in
15561 -nandmtd1_ReadChunkWithTagsFromNAND.
15565 ---Boundary-00=_5LbTGmt62YoutxM
15566 -Content-Type: text/x-csrc;
15567 - charset="iso-8859-15";
15568 - name="yaffs_mtdif1.c"
15569 -Content-Transfer-Encoding: 7bit
15570 -Content-Disposition: attachment;
15571 - filename="yaffs_mtdif1.c"
15574 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
15575 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15577 - * Copyright (C) 2002 Aleph One Ltd.
15578 - * for Toby Churchill Ltd and Brightstar Engineering
15580 - * This program is free software; you can redistribute it and/or modify
15581 - * it under the terms of the GNU General Public License version 2 as
15582 - * published by the Free Software Foundation.
15586 - * This module provides the interface between yaffs_nand.c and the
15587 - * MTD API. This version is used when the MTD interface supports the
15588 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
15589 - * and we have small-page NAND device.
15591 - * These functions are invoked via function pointers in yaffs_nand.c.
15592 - * This replaces functionality provided by functions in yaffs_mtdif.c
15593 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
15594 - * called in yaffs_mtdif.c when the function pointers are NULL.
15595 - * We assume the MTD layer is performing ECC (useNANDECC is true).
15598 -#include "yportenv.h"
15599 -#include "yaffs_guts.h"
15600 -#include "yaffs_packedtags1.h"
15601 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
15603 -#include "linux/kernel.h"
15604 -#include "linux/version.h"
15605 -#include "linux/types.h"
15606 -#include "linux/mtd/mtd.h"
15608 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15609 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
15611 -const char *yaffs_mtdif1_c_version = "$Id$";
15613 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15614 -# define YTAG1_SIZE 8
15616 -# define YTAG1_SIZE 9
15620 -/* Use the following nand_ecclayout with MTD when using
15621 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
15622 - * If you have existing Yaffs images and the byte order differs from this,
15623 - * adjust 'oobfree' to match your existing Yaffs data.
15625 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
15626 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
15629 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
15630 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
15631 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
15632 - * byte and B is the small-page bad-block indicator byte.
15634 -static struct nand_ecclayout nand_oob_16 = {
15636 - .eccpos = { 8, 9, 10, 13, 14, 15 },
15638 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
15642 -/* Write a chunk (page) of data to NAND.
15644 - * Caller always provides ExtendedTags data which are converted to a more
15645 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
15646 - * contents of the tags meta-data; used to valid the tags when read.
15648 - * - Pack ExtendedTags to PackedTags1 form
15649 - * - Compute mini-ECC for PackedTags1
15650 - * - Write data and packed tags to NAND.
15652 - * Note: Due to the use of the PackedTags1 meta-data which does not include
15653 - * a full sequence number (as found in the larger PackedTags2 form) it is
15654 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
15655 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
15656 - * to be written just once. When Yaffs performs this operation, this
15657 - * function is called with a NULL data pointer -- calling MTD write_oob
15658 - * without data is valid usage (2.6.17).
15660 - * Any underlying MTD error results in YAFFS_FAIL.
15661 - * Returns YAFFS_OK or YAFFS_FAIL.
15663 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15664 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
15666 - struct mtd_info * mtd = dev->genericDevice;
15667 - int chunkBytes = dev->nDataBytesPerChunk;
15668 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15669 - struct mtd_oob_ops ops;
15670 - yaffs_PackedTags1 pt1;
15673 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
15674 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15675 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
15677 - yaffs_PackTags1(&pt1, etags);
15678 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15680 - /* When deleting a chunk, the upper layer provides only skeletal
15681 - * etags, one with chunkDeleted set. However, we need to update the
15682 - * tags, not erase them completely. So we use the NAND write property
15683 - * that only zeroed-bits stick and set tag bytes to all-ones and
15684 - * zero just the (not) deleted bit.
15686 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15687 - if (etags->chunkDeleted) {
15688 - memset(&pt1, 0xff, 8);
15689 - /* clear delete status bit to indicate deleted */
15693 - ((__u8 *)&pt1)[8] = 0xff;
15694 - if (etags->chunkDeleted) {
15695 - memset(&pt1, 0xff, 8);
15696 - /* zero pageStatus byte to indicate deleted */
15697 - ((__u8 *)&pt1)[8] = 0;
15701 - memset(&ops, 0, sizeof(ops));
15702 - ops.mode = MTD_OOB_AUTO;
15703 - ops.len = (data) ? chunkBytes : 0;
15704 - ops.ooblen = YTAG1_SIZE;
15705 - ops.datbuf = (__u8 *)data;
15706 - ops.oobbuf = (__u8 *)&pt1;
15708 - retval = mtd->write_oob(mtd, addr, &ops);
15710 - yaffs_trace(YAFFS_TRACE_MTD,
15711 - "write_oob failed, chunk %d, mtd error %d\n",
15712 - chunkInNAND, retval);
15714 - return retval ? YAFFS_FAIL : YAFFS_OK;
15717 -/* Return with empty ExtendedTags but add eccResult.
15719 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
15722 - memset(etags, 0, sizeof(*etags));
15723 - etags->eccResult = eccResult;
15728 -/* Read a chunk (page) from NAND.
15730 - * Caller expects ExtendedTags data to be usable even on error; that is,
15731 - * all members except eccResult and blockBad are zeroed.
15733 - * - Check ECC results for data (if applicable)
15734 - * - Check for blank/erased block (return empty ExtendedTags if blank)
15735 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
15736 - * - Convert PackedTags1 to ExtendedTags
15737 - * - Update eccResult and blockBad members to refect state.
15739 - * Returns YAFFS_OK or YAFFS_FAIL.
15741 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15742 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
15744 - struct mtd_info * mtd = dev->genericDevice;
15745 - int chunkBytes = dev->nDataBytesPerChunk;
15746 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15747 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15748 - struct mtd_oob_ops ops;
15749 - yaffs_PackedTags1 pt1;
15753 - memset(&ops, 0, sizeof(ops));
15754 - ops.mode = MTD_OOB_AUTO;
15755 - ops.len = (data) ? chunkBytes : 0;
15756 - ops.ooblen = YTAG1_SIZE;
15757 - ops.datbuf = data;
15758 - ops.oobbuf = (__u8 *)&pt1;
15760 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
15761 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
15762 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
15764 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
15766 - /* Read page and oob using MTD.
15767 - * Check status and determine ECC result.
15769 - retval = mtd->read_oob(mtd, addr, &ops);
15771 - yaffs_trace(YAFFS_TRACE_MTD,
15772 - "read_oob failed, chunk %d, mtd error %d\n",
15773 - chunkInNAND, retval);
15776 - switch (retval) {
15782 - /* MTD's ECC fixed the data */
15783 - eccres = YAFFS_ECC_RESULT_FIXED;
15788 - /* MTD's ECC could not fix the data */
15789 - dev->eccUnfixed++;
15790 - /* fall into... */
15792 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
15793 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
15794 - return YAFFS_FAIL;
15797 - /* Check for a blank/erased chunk.
15799 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
15800 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
15801 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
15804 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15805 - /* Read deleted status (bit) then return it to it's non-deleted
15806 - * state before performing tags mini-ECC check. pt1.deleted is
15809 - deleted = !pt1.deleted;
15812 - (void) deleted; /* not used */
15815 - /* Check the packed tags mini-ECC and correct if necessary/possible.
15817 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
15818 - switch (retval) {
15820 - /* no tags error, use MTD result */
15823 - /* recovered tags-ECC error */
15824 - dev->tagsEccFixed++;
15825 - eccres = YAFFS_ECC_RESULT_FIXED;
15828 - /* unrecovered tags-ECC error */
15829 - dev->tagsEccUnfixed++;
15830 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
15833 - /* Unpack the tags to extended form and set ECC result.
15834 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
15836 - pt1.shouldBeFF = 0xFFFFFFFF;
15837 - yaffs_UnpackTags1(etags, &pt1);
15838 - etags->eccResult = eccres;
15840 - /* Set deleted state.
15842 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15843 - etags->chunkDeleted = deleted;
15845 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
15850 -/* Mark a block bad.
15852 - * This is a persistant state.
15853 - * Use of this function should be rare.
15855 - * Returns YAFFS_OK or YAFFS_FAIL.
15857 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15859 - struct mtd_info * mtd = dev->genericDevice;
15860 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15863 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
15865 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15866 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
15869 -/* Check any MTD prerequists.
15871 - * Returns YAFFS_OK or YAFFS_FAIL.
15873 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
15875 - /* 2.6.18 has mtd->ecclayout->oobavail */
15876 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
15877 - int oobavail = mtd->ecclayout->oobavail;
15879 - if (oobavail < YTAG1_SIZE) {
15880 - yaffs_trace(YAFFS_TRACE_ERROR,
15881 - "mtd device has only %d bytes for tags, need %d",
15882 - oobavail, YTAG1_SIZE);
15883 - return YAFFS_FAIL;
15888 -/* Query for the current state of a specific block.
15890 - * Examine the tags of the first chunk of the block and return the state:
15891 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
15892 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
15893 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
15895 - * Always returns YAFFS_OK.
15897 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15898 - yaffs_BlockState * pState, int *pSequenceNumber)
15900 - struct mtd_info * mtd = dev->genericDevice;
15901 - int chunkNo = blockNo * dev->nChunksPerBlock;
15902 - yaffs_ExtendedTags etags;
15903 - int state = YAFFS_BLOCK_STATE_DEAD;
15907 - /* We don't yet have a good place to test for MTD config prerequists.
15908 - * Do it here as we are called during the initial scan.
15910 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
15911 - return YAFFS_FAIL;
15914 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15915 - if (etags.blockBad) {
15916 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15917 - "block %d is marked bad", blockNo);
15918 - state = YAFFS_BLOCK_STATE_DEAD;
15920 - else if (etags.chunkUsed) {
15921 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
15922 - seqnum = etags.sequenceNumber;
15925 - state = YAFFS_BLOCK_STATE_EMPTY;
15929 - *pSequenceNumber = seqnum;
15931 - /* query always succeeds */
15935 -#endif /*KERNEL_VERSION*/
15937 ---Boundary-00=_5LbTGmt62YoutxM--
15941 --- a/fs/yaffs2/yaffs_mtdif1.h
15942 +++ b/fs/yaffs2/yaffs_mtdif1.h
15945 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
15947 - * Copyright (C) 2002-2007 Aleph One Ltd.
15948 + * Copyright (C) 2002-2010 Aleph One Ltd.
15949 * for Toby Churchill Ltd and Brightstar Engineering
15951 * This program is free software; you can redistribute it and/or modify
15952 --- a/fs/yaffs2/yaffs_mtdif2.c
15953 +++ b/fs/yaffs2/yaffs_mtdif2.c
15956 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
15958 - * Copyright (C) 2002-2007 Aleph One Ltd.
15959 + * Copyright (C) 2002-2010 Aleph One Ltd.
15960 * for Toby Churchill Ltd and Brightstar Engineering
15962 * Created by Charles Manning <charles@aleph1.co.uk>
15965 /* mtd interface for YAFFS2 */
15967 -const char *yaffs_mtdif2_c_version =
15968 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
15970 #include "yportenv.h"
15972 +#include "yaffs_trace.h"
15974 #include "yaffs_mtdif2.h"
15976 @@ -27,6 +24,8 @@ const char *yaffs_mtdif2_c_version =
15978 #include "yaffs_packedtags2.h"
15980 +#include "yaffs_linux.h"
15982 /* NB For use with inband tags....
15983 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
15984 * use it to load the tags.
15985 @@ -35,7 +34,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
15987 const yaffs_ExtendedTags *tags)
15989 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
15990 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15991 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
15992 struct mtd_oob_ops ops;
15994 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
15996 yaffs_PackedTags2 pt;
15998 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
15999 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt;
16003 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
16004 TENDSTR), chunkInNAND, data, tags));
16007 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16008 + addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16010 /* For yaffs2 writing there must be both data and tags.
16011 * If we're using inband tags, then the tags are stuffed into
16012 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16014 if (!data || !tags)
16016 - else if (dev->inbandTags) {
16017 + else if (dev->param.inbandTags) {
16018 yaffs_PackedTags2TagsPart *pt2tp;
16019 pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
16020 yaffs_PackTags2TagsPart(pt2tp, tags);
16022 - yaffs_PackTags2(&pt, tags);
16023 + yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC);
16025 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16026 ops.mode = MTD_OOB_AUTO;
16027 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
16028 - ops.len = dev->totalBytesPerChunk;
16029 + ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size;
16030 + ops.len = dev->param.totalBytesPerChunk;
16032 ops.datbuf = (__u8 *)data;
16033 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
16034 + ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr;
16035 retval = mtd->write_oob(mtd, addr, &ops);
16038 - if (!dev->inbandTags) {
16039 + if (!dev->param.inbandTags) {
16041 mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16042 - &dummy, data, (__u8 *) &pt, NULL);
16043 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
16046 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
16047 + mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy,
16051 @@ -98,7 +100,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16052 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
16053 __u8 *data, yaffs_ExtendedTags *tags)
16055 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16056 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16057 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16058 struct mtd_oob_ops ops;
16060 @@ -106,16 +108,19 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16064 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16065 + loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16067 yaffs_PackedTags2 pt;
16069 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
16070 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt;
16074 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
16075 TENDSTR), chunkInNAND, data, tags));
16077 - if (dev->inbandTags) {
16078 + if (dev->param.inbandTags) {
16082 @@ -127,20 +132,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16085 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16086 - if (dev->inbandTags || (data && !tags))
16087 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
16088 + if (dev->param.inbandTags || (data && !tags))
16089 + retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk,
16092 ops.mode = MTD_OOB_AUTO;
16093 - ops.ooblen = sizeof(pt);
16094 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
16095 + ops.ooblen = packed_tags_size;
16096 + ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size;
16099 - ops.oobbuf = dev->spareBuffer;
16100 + ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer;
16101 retval = mtd->read_oob(mtd, addr, &ops);
16104 - if (!dev->inbandTags && data && tags) {
16105 + if (!dev->param.inbandTags && data && tags) {
16107 retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16108 &dummy, data, dev->spareBuffer,
16109 @@ -150,7 +155,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16111 mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16113 - if (!dev->inbandTags && tags)
16114 + if (!dev->param.inbandTags && tags)
16116 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
16118 @@ -158,7 +163,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16122 - if (dev->inbandTags) {
16123 + if (dev->param.inbandTags) {
16125 yaffs_PackedTags2TagsPart *pt2tp;
16126 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
16127 @@ -166,16 +171,22 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16131 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
16132 - yaffs_UnpackTags2(tags, &pt);
16133 + memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size);
16134 + yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC);
16139 yaffs_ReleaseTempBuffer(dev, data, __LINE__);
16141 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
16142 + if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16143 tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
16144 + dev->eccUnfixed++;
16146 + if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16147 + tags->eccResult = YAFFS_ECC_RESULT_FIXED;
16153 @@ -184,15 +195,15 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16155 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
16157 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16158 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16161 (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
16164 mtd->block_markbad(mtd,
16165 - blockNo * dev->nChunksPerBlock *
16166 - dev->totalBytesPerChunk);
16167 + blockNo * dev->param.nChunksPerBlock *
16168 + dev->param.totalBytesPerChunk);
16172 @@ -204,15 +215,15 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
16173 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
16174 yaffs_BlockState *state, __u32 *sequenceNumber)
16176 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16177 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16181 (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
16183 mtd->block_isbad(mtd,
16184 - blockNo * dev->nChunksPerBlock *
16185 - dev->totalBytesPerChunk);
16186 + blockNo * dev->param.nChunksPerBlock *
16187 + dev->param.totalBytesPerChunk);
16190 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
16191 @@ -223,7 +234,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs
16192 yaffs_ExtendedTags t;
16193 nandmtd2_ReadChunkWithTagsFromNAND(dev,
16195 - dev->nChunksPerBlock, NULL,
16196 + dev->param.nChunksPerBlock, NULL,
16200 --- a/fs/yaffs2/yaffs_mtdif2.h
16201 +++ b/fs/yaffs2/yaffs_mtdif2.h
16204 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16206 - * Copyright (C) 2002-2007 Aleph One Ltd.
16207 + * Copyright (C) 2002-2010 Aleph One Ltd.
16208 * for Toby Churchill Ltd and Brightstar Engineering
16210 * Created by Charles Manning <charles@aleph1.co.uk>
16211 --- a/fs/yaffs2/yaffs_mtdif.c
16212 +++ b/fs/yaffs2/yaffs_mtdif.c
16215 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16217 - * Copyright (C) 2002-2007 Aleph One Ltd.
16218 + * Copyright (C) 2002-2010 Aleph One Ltd.
16219 * for Toby Churchill Ltd and Brightstar Engineering
16221 * Created by Charles Manning <charles@aleph1.co.uk>
16223 * published by the Free Software Foundation.
16226 -const char *yaffs_mtdif_c_version =
16227 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
16229 #include "yportenv.h"
16232 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
16233 #include "linux/time.h"
16234 #include "linux/mtd/nand.h"
16236 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
16237 -static struct nand_oobinfo yaffs_oobinfo = {
16240 - .eccpos = {8, 9, 10, 13, 14, 15}
16243 -static struct nand_oobinfo yaffs_noeccinfo = {
16248 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16249 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
16251 - oob[0] = spare->tagByte0;
16252 - oob[1] = spare->tagByte1;
16253 - oob[2] = spare->tagByte2;
16254 - oob[3] = spare->tagByte3;
16255 - oob[4] = spare->tagByte4;
16256 - oob[5] = spare->tagByte5 & 0x3f;
16257 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
16258 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
16259 - oob[6] = spare->tagByte6;
16260 - oob[7] = spare->tagByte7;
16263 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
16265 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
16266 - spare->tagByte0 = oob[0];
16267 - spare->tagByte1 = oob[1];
16268 - spare->tagByte2 = oob[2];
16269 - spare->tagByte3 = oob[3];
16270 - spare->tagByte4 = oob[4];
16271 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
16272 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
16273 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
16274 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
16275 - spare->tagByte6 = oob[6];
16276 - spare->tagByte7 = oob[7];
16277 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
16279 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
16283 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16284 - const __u8 *data, const yaffs_Spare *spare)
16286 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16287 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16288 - struct mtd_oob_ops ops;
16293 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16294 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16295 - __u8 spareAsBytes[8]; /* OOB */
16297 - if (data && !spare)
16298 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
16300 - else if (spare) {
16301 - if (dev->useNANDECC) {
16302 - translate_spare2oob(spare, spareAsBytes);
16303 - ops.mode = MTD_OOB_AUTO;
16304 - ops.ooblen = 8; /* temp hack */
16306 - ops.mode = MTD_OOB_RAW;
16307 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16309 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16310 - ops.datbuf = (u8 *)data;
16312 - ops.oobbuf = spareAsBytes;
16313 - retval = mtd->write_oob(mtd, addr, &ops);
16316 - __u8 *spareAsBytes = (__u8 *) spare;
16318 - if (data && spare) {
16319 - if (dev->useNANDECC)
16321 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16322 - &dummy, data, spareAsBytes,
16326 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16327 - &dummy, data, spareAsBytes,
16328 - &yaffs_noeccinfo);
16332 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16336 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16337 - &dummy, spareAsBytes);
16344 - return YAFFS_FAIL;
16347 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16348 - yaffs_Spare *spare)
16350 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16351 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16352 - struct mtd_oob_ops ops;
16357 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16358 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16359 - __u8 spareAsBytes[8]; /* OOB */
16361 - if (data && !spare)
16362 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
16364 - else if (spare) {
16365 - if (dev->useNANDECC) {
16366 - ops.mode = MTD_OOB_AUTO;
16367 - ops.ooblen = 8; /* temp hack */
16369 - ops.mode = MTD_OOB_RAW;
16370 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16372 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16373 - ops.datbuf = data;
16375 - ops.oobbuf = spareAsBytes;
16376 - retval = mtd->read_oob(mtd, addr, &ops);
16377 - if (dev->useNANDECC)
16378 - translate_oob2spare(spare, spareAsBytes);
16381 - __u8 *spareAsBytes = (__u8 *) spare;
16383 - if (data && spare) {
16384 - if (dev->useNANDECC) {
16385 - /* Careful, this call adds 2 ints */
16386 - /* to the end of the spare data. Calling function */
16387 - /* should allocate enough memory for spare, */
16388 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
16390 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16391 - &dummy, data, spareAsBytes,
16395 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16396 - &dummy, data, spareAsBytes,
16397 - &yaffs_noeccinfo);
16402 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16406 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16407 - &dummy, spareAsBytes);
16414 - return YAFFS_FAIL;
16416 +#include "yaffs_linux.h"
16418 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
16420 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16421 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16423 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
16424 - * dev->nChunksPerBlock;
16425 + ((loff_t) blockNumber) * dev->param.totalBytesPerChunk
16426 + * dev->param.nChunksPerBlock;
16427 struct erase_info ei;
16433 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
16434 + ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock;
16437 ei.callback = NULL;
16438 ei.priv = (u_long) dev;
16440 - /* Todo finish off the ei if required */
16442 - sema_init(&dev->sem, 0);
16444 retval = mtd->erase(mtd, &ei);
16447 --- a/fs/yaffs2/yaffs_mtdif.h
16448 +++ b/fs/yaffs2/yaffs_mtdif.h
16451 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16453 - * Copyright (C) 2002-2007 Aleph One Ltd.
16454 + * Copyright (C) 2002-2010 Aleph One Ltd.
16455 * for Toby Churchill Ltd and Brightstar Engineering
16457 * Created by Charles Manning <charles@aleph1.co.uk>
16459 extern struct nand_oobinfo yaffs_oobinfo;
16460 extern struct nand_oobinfo yaffs_noeccinfo;
16463 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16464 - const __u8 *data, const yaffs_Spare *spare);
16465 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16466 - yaffs_Spare *spare);
16467 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
16468 int nandmtd_InitialiseNAND(yaffs_Device *dev);
16471 +++ b/fs/yaffs2/yaffs_nameval.c
16474 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16476 + * Copyright (C) 2002-2010 Aleph One Ltd.
16477 + * for Toby Churchill Ltd and Brightstar Engineering
16479 + * Created by Charles Manning <charles@aleph1.co.uk>
16481 + * This program is free software; you can redistribute it and/or modify
16482 + * it under the terms of the GNU General Public License version 2 as
16483 + * published by the Free Software Foundation.
16487 + * This simple implementation of a name-value store assumes a small number of values and fits
16488 + * into a small finite buffer.
16490 + * Each attribute is stored as a record:
16491 + * sizeof(int) bytes record size.
16492 + * strnlen+1 bytes name null terminated.
16495 + * total size stored in record size
16497 + * This code has not been tested with unicode yet.
16501 +#include "yaffs_nameval.h"
16503 +#include "yportenv.h"
16505 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
16511 + memcpy(&size,xb,sizeof(int));
16512 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16513 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
16515 + *exist_size = size;
16519 + if(pos < xb_size -sizeof(int))
16520 + memcpy(&size,xb + pos,sizeof(int));
16529 +static int nval_used(const char *xb, int xb_size)
16534 + memcpy(&size,xb + pos,sizeof(int));
16535 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16537 + if(pos < xb_size -sizeof(int))
16538 + memcpy(&size,xb + pos,sizeof(int));
16545 +int nval_del(char *xb, int xb_size, const YCHAR *name)
16547 + int pos = nval_find(xb, xb_size, name, NULL);
16550 + if(pos >= 0 && pos < xb_size){
16551 + /* Find size, shift rest over this record, then zero out the rest of buffer */
16552 + memcpy(&size,xb+pos,sizeof(int));
16553 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
16554 + memset(xb + (xb_size - size),0,size);
16560 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
16563 + int namelen = yaffs_strnlen(name,xb_size);
16565 + int size_exist = 0;
16569 + pos = nval_find(xb,xb_size,name, &size_exist);
16571 + if(flags & XATTR_CREATE && pos >= 0)
16573 + if(flags & XATTR_REPLACE && pos < 0)
16576 + start = nval_used(xb,xb_size);
16577 + space = xb_size - start + size_exist;
16579 + reclen = (sizeof(int) + namelen + 1 + bsize);
16581 + if(reclen > space)
16585 + nval_del(xb,xb_size,name);
16586 + start = nval_used(xb, xb_size);
16591 + memcpy(xb + pos,&reclen,sizeof(int));
16592 + pos +=sizeof(int);
16593 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
16594 + pos+= (namelen+1);
16595 + memcpy(xb + pos,buf,bsize);
16599 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
16601 + int pos = nval_find(xb,xb_size,name,NULL);
16604 + if(pos >= 0 && pos< xb_size){
16606 + memcpy(&size,xb +pos,sizeof(int));
16607 + pos+=sizeof(int); /* advance past record length */
16608 + size -= sizeof(int);
16610 + /* Advance over name string */
16611 + while(xb[pos] && size > 0 && pos < xb_size){
16615 + /*Advance over NUL */
16619 + if(size <= bsize){
16620 + memcpy(buf,xb + pos,size);
16631 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
16639 + memcpy(&size,xb + pos,sizeof(int));
16640 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
16641 + pos+= sizeof(int);
16642 + size-=sizeof(int);
16643 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
16644 + if(ncopied + name_len + 1 < bsize){
16645 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
16649 + if(sizeof(YCHAR) > 1){
16653 + ncopied += (name_len+1);
16657 + if(pos < xb_size -sizeof(int))
16658 + memcpy(&size,xb + pos,sizeof(int));
16666 +int nval_hasvalues(const char *xb, int xb_size)
16668 + return nval_used(xb, xb_size) > 0;
16671 +++ b/fs/yaffs2/yaffs_nameval.h
16674 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16676 + * Copyright (C) 2002-2010 Aleph One Ltd.
16677 + * for Toby Churchill Ltd and Brightstar Engineering
16679 + * Created by Charles Manning <charles@aleph1.co.uk>
16681 + * This program is free software; you can redistribute it and/or modify
16682 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16683 + * published by the Free Software Foundation.
16685 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16687 +#ifndef __NAMEVAL_H__
16688 +#define __NAMEVAL_H__
16690 +#include "yportenv.h"
16692 +int nval_del(char *xb, int xb_size, const YCHAR *name);
16693 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
16694 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
16695 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
16696 +int nval_hasvalues(const char *xb, int xb_size);
16698 --- a/fs/yaffs2/yaffs_nand.c
16699 +++ b/fs/yaffs2/yaffs_nand.c
16702 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16704 - * Copyright (C) 2002-2007 Aleph One Ltd.
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 * published by the Free Software Foundation.
16713 -const char *yaffs_nand_c_version =
16714 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
16716 #include "yaffs_nand.h"
16717 #include "yaffs_tagscompat.h"
16718 #include "yaffs_tagsvalidity.h"
16719 @@ -29,12 +26,14 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16721 int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
16723 + dev->nPageReads++;
16725 /* If there are no tags provided, use local tags to get prioritised gc working */
16729 - if (dev->readChunkWithTagsFromNAND)
16730 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16731 + if (dev->param.readChunkWithTagsFromNAND)
16732 + result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16735 result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
16736 @@ -44,7 +43,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16738 tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
16740 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
16741 + yaffs_BlockInfo *bi;
16742 + bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock);
16743 yaffs_HandleChunkError(dev, bi);
16746 @@ -56,6 +56,9 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16747 const __u8 *buffer,
16748 yaffs_ExtendedTags *tags)
16751 + dev->nPageWrites++;
16753 chunkInNAND -= dev->chunkOffset;
16756 @@ -75,8 +78,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16760 - if (dev->writeChunkWithTagsToNAND)
16761 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16762 + if (dev->param.writeChunkWithTagsToNAND)
16763 + return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16766 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
16767 @@ -89,9 +92,9 @@ int yaffs_MarkBlockBad(yaffs_Device *dev
16769 blockNo -= dev->blockOffset;
16772 - if (dev->markNANDBlockBad)
16773 - return dev->markNANDBlockBad(dev, blockNo);
16775 + if (dev->param.markNANDBlockBad)
16776 + return dev->param.markNANDBlockBad(dev, blockNo);
16778 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
16780 @@ -103,8 +106,8 @@ int yaffs_QueryInitialBlockState(yaffs_D
16782 blockNo -= dev->blockOffset;
16784 - if (dev->queryNANDBlock)
16785 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
16786 + if (dev->param.queryNANDBlock)
16787 + return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber);
16789 return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
16791 @@ -119,16 +122,18 @@ int yaffs_EraseBlockInNAND(struct yaffs_
16793 blockInNAND -= dev->blockOffset;
16796 dev->nBlockErasures++;
16797 - result = dev->eraseBlockInNAND(dev, blockInNAND);
16799 + result = dev->param.eraseBlockInNAND(dev, blockInNAND);
16804 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
16806 - return dev->initialiseNAND(dev);
16807 + if(dev->param.initialiseNAND)
16808 + return dev->param.initialiseNAND(dev);
16813 --- a/fs/yaffs2/yaffs_nandemul2k.h
16814 +++ b/fs/yaffs2/yaffs_nandemul2k.h
16817 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16819 - * Copyright (C) 2002-2007 Aleph One Ltd.
16820 + * Copyright (C) 2002-2010 Aleph One Ltd.
16821 * for Toby Churchill Ltd and Brightstar Engineering
16823 * Created by Charles Manning <charles@aleph1.co.uk>
16824 --- a/fs/yaffs2/yaffs_nand.h
16825 +++ b/fs/yaffs2/yaffs_nand.h
16828 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16830 - * Copyright (C) 2002-2007 Aleph One Ltd.
16831 + * Copyright (C) 2002-2010 Aleph One Ltd.
16832 * for Toby Churchill Ltd and Brightstar Engineering
16834 * Created by Charles Manning <charles@aleph1.co.uk>
16835 --- a/fs/yaffs2/yaffs_packedtags1.c
16836 +++ b/fs/yaffs2/yaffs_packedtags1.c
16839 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16841 - * Copyright (C) 2002-2007 Aleph One Ltd.
16842 + * Copyright (C) 2002-2010 Aleph One Ltd.
16843 * for Toby Churchill Ltd and Brightstar Engineering
16845 * Created by Charles Manning <charles@aleph1.co.uk>
16846 --- a/fs/yaffs2/yaffs_packedtags1.h
16847 +++ b/fs/yaffs2/yaffs_packedtags1.h
16850 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16852 - * Copyright (C) 2002-2007 Aleph One Ltd.
16853 + * Copyright (C) 2002-2010 Aleph One Ltd.
16854 * for Toby Churchill Ltd and Brightstar Engineering
16856 * Created by Charles Manning <charles@aleph1.co.uk>
16857 --- a/fs/yaffs2/yaffs_packedtags2.c
16858 +++ b/fs/yaffs2/yaffs_packedtags2.c
16861 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16863 - * Copyright (C) 2002-2007 Aleph One Ltd.
16864 + * Copyright (C) 2002-2010 Aleph One Ltd.
16865 * for Toby Churchill Ltd and Brightstar Engineering
16867 * Created by Charles Manning <charles@aleph1.co.uk>
16870 #include "yaffs_packedtags2.h"
16871 #include "yportenv.h"
16872 +#include "yaffs_trace.h"
16873 #include "yaffs_tagsvalidity.h"
16875 /* This code packs a set of extended tags into a binary structure for
16876 @@ -96,17 +97,14 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
16880 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
16881 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC)
16883 yaffs_PackTags2TagsPart(&pt->t, t);
16885 -#ifndef YAFFS_IGNORE_TAGS_ECC
16888 yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16889 sizeof(yaffs_PackedTags2TagsPart),
16896 @@ -158,27 +156,24 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
16900 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
16901 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC)
16904 yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16906 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
16907 - /* Page is in use */
16908 -#ifndef YAFFS_IGNORE_TAGS_ECC
16910 - yaffs_ECCOther ecc;
16912 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16914 - (yaffs_PackedTags2TagsPart),
16917 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16919 - (yaffs_PackedTags2TagsPart),
16921 - switch (result) {
16922 + if (pt->t.sequenceNumber != 0xFFFFFFFF &&
16924 + /* Chunk is in use and we need to do ECC */
16926 + yaffs_ECCOther ecc;
16928 + yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16929 + sizeof(yaffs_PackedTags2TagsPart),
16931 + result = yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16932 + sizeof(yaffs_PackedTags2TagsPart),
16934 + switch (result) {
16936 eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16938 @@ -190,9 +185,7 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16941 eccResult = YAFFS_ECC_RESULT_UNKNOWN;
16947 yaffs_UnpackTags2TagsPart(t, &pt->t);
16948 @@ -201,6 +194,5 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16950 yaffs_DumpPackedTags2(pt);
16951 yaffs_DumpTags2(t);
16955 --- a/fs/yaffs2/yaffs_packedtags2.h
16956 +++ b/fs/yaffs2/yaffs_packedtags2.h
16959 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16961 - * Copyright (C) 2002-2007 Aleph One Ltd.
16962 + * Copyright (C) 2002-2010 Aleph One Ltd.
16963 * for Toby Churchill Ltd and Brightstar Engineering
16965 * Created by Charles Manning <charles@aleph1.co.uk>
16966 @@ -34,8 +34,8 @@ typedef struct {
16967 } yaffs_PackedTags2;
16969 /* Full packed tags with ECC, used for oob tags */
16970 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
16971 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
16972 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC);
16973 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC);
16975 /* Only the tags part (no ECC for use with inband tags */
16976 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
16977 --- a/fs/yaffs2/yaffs_qsort.h
16978 +++ b/fs/yaffs2/yaffs_qsort.h
16981 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16983 - * Copyright (C) 2002-2007 Aleph One Ltd.
16984 + * Copyright (C) 2002-2010 Aleph One Ltd.
16985 * for Toby Churchill Ltd and Brightstar Engineering
16987 * Created by Charles Manning <charles@aleph1.co.uk>
16989 #ifndef __YAFFS_QSORT_H__
16990 #define __YAFFS_QSORT_H__
16993 +#include <linux/sort.h>
16995 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
16996 + int (*cmp)(const void *, const void *)){
16997 + sort(base, total_elems, size, cmp, NULL);
17002 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
17003 int (*cmp)(const void *, const void *));
17007 --- a/fs/yaffs2/yaffs_tagscompat.c
17008 +++ b/fs/yaffs2/yaffs_tagscompat.c
17011 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17013 - * Copyright (C) 2002-2007 Aleph One Ltd.
17014 + * Copyright (C) 2002-2010 Aleph One Ltd.
17015 * for Toby Churchill Ltd and Brightstar Engineering
17017 * Created by Charles Manning <charles@aleph1.co.uk>
17019 #include "yaffs_tagscompat.h"
17020 #include "yaffs_ecc.h"
17021 #include "yaffs_getblockinfo.h"
17022 +#include "yaffs_trace.h"
17024 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
17026 @@ -163,15 +164,14 @@ static int yaffs_WriteChunkToNAND(struct
17027 int chunkInNAND, const __u8 *data,
17028 yaffs_Spare *spare)
17030 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
17031 + if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) {
17032 T(YAFFS_TRACE_ERROR,
17033 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
17038 - dev->nPageWrites++;
17039 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
17040 + return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare);
17043 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
17044 @@ -184,16 +184,14 @@ static int yaffs_ReadChunkFromNAND(struc
17046 yaffs_Spare localSpare;
17048 - dev->nPageReads++;
17050 if (!spare && data) {
17051 /* If we don't have a real spare, then we use a local one. */
17052 /* Need this for the calculation of the ecc */
17053 spare = &localSpare;
17056 - if (!dev->useNANDECC) {
17057 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
17058 + if (!dev->param.useNANDECC) {
17059 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare);
17060 if (data && doErrorCorrection) {
17061 /* Do ECC correction */
17062 /* Todo handle any errors */
17063 @@ -254,7 +252,7 @@ static int yaffs_ReadChunkFromNAND(struc
17065 memset(&nspare, 0, sizeof(nspare));
17067 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
17068 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data,
17069 (yaffs_Spare *) &nspare);
17070 memcpy(spare, &nspare, sizeof(yaffs_Spare));
17071 if (data && doErrorCorrection) {
17072 @@ -307,10 +305,10 @@ static int yaffs_CheckChunkErased(struct
17073 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
17074 static __u8 data[YAFFS_BYTES_PER_CHUNK];
17075 /* Might as well always allocate the larger size for */
17076 - /* dev->useNANDECC == true; */
17077 + /* dev->param.useNANDECC == true; */
17078 static __u8 spare[sizeof(struct yaffs_NANDSpare)];
17080 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17081 + dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17084 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
17085 @@ -333,7 +331,7 @@ static int yaffs_CheckChunkErased(struct
17087 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
17089 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17090 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17092 /* Mark the block for retirement */
17093 yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
17094 @@ -365,7 +363,7 @@ static void yaffs_HandleUpdateChunk(yaff
17096 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
17098 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17099 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17101 /* Mark the block for retirement */
17102 yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
17103 @@ -424,7 +422,7 @@ int yaffs_TagsCompatabilityWriteChunkWit
17105 tags.serialNumber = eTags->serialNumber;
17107 - if (!dev->useNANDECC && data)
17108 + if (!dev->param.useNANDECC && data)
17109 yaffs_CalcECC(data, &spare);
17111 yaffs_LoadTagsIntoSpare(&spare, &tags);
17112 @@ -498,9 +496,9 @@ int yaffs_TagsCompatabilityMarkNANDBlock
17114 spare.blockStatus = 'Y';
17116 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
17117 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL,
17119 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
17120 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1,
17124 @@ -525,9 +523,9 @@ int yaffs_TagsCompatabilityQueryNANDBloc
17126 *sequenceNumber = 0;
17128 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
17129 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL,
17130 &spare0, &dummy, 1);
17131 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
17132 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL,
17133 &spare1, &dummy, 1);
17135 if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
17136 --- a/fs/yaffs2/yaffs_tagscompat.h
17137 +++ b/fs/yaffs2/yaffs_tagscompat.h
17140 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17142 - * Copyright (C) 2002-2007 Aleph One Ltd.
17143 + * Copyright (C) 2002-2010 Aleph One Ltd.
17144 * for Toby Churchill Ltd and Brightstar Engineering
17146 * Created by Charles Manning <charles@aleph1.co.uk>
17147 --- a/fs/yaffs2/yaffs_tagsvalidity.c
17148 +++ b/fs/yaffs2/yaffs_tagsvalidity.c
17151 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17153 - * Copyright (C) 2002-2007 Aleph One Ltd.
17154 + * Copyright (C) 2002-2010 Aleph One Ltd.
17155 * for Toby Churchill Ltd and Brightstar Engineering
17157 * Created by Charles Manning <charles@aleph1.co.uk>
17158 --- a/fs/yaffs2/yaffs_tagsvalidity.h
17159 +++ b/fs/yaffs2/yaffs_tagsvalidity.h
17162 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17164 - * Copyright (C) 2002-2007 Aleph One Ltd.
17165 + * Copyright (C) 2002-2010 Aleph One Ltd.
17166 * for Toby Churchill Ltd and Brightstar Engineering
17168 * Created by Charles Manning <charles@aleph1.co.uk>
17170 +++ b/fs/yaffs2/yaffs_trace.h
17173 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17175 + * Copyright (C) 2002-2010 Aleph One Ltd.
17176 + * for Toby Churchill Ltd and Brightstar Engineering
17178 + * Created by Charles Manning <charles@aleph1.co.uk>
17180 + * This program is free software; you can redistribute it and/or modify
17181 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17182 + * published by the Free Software Foundation.
17184 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17188 +#ifndef __YTRACE_H__
17189 +#define __YTRACE_H__
17191 +extern unsigned int yaffs_traceMask;
17192 +extern unsigned int yaffs_wr_attempts;
17196 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
17199 +#define YAFFS_TRACE_OS 0x00000002
17200 +#define YAFFS_TRACE_ALLOCATE 0x00000004
17201 +#define YAFFS_TRACE_SCAN 0x00000008
17202 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
17203 +#define YAFFS_TRACE_ERASE 0x00000020
17204 +#define YAFFS_TRACE_GC 0x00000040
17205 +#define YAFFS_TRACE_WRITE 0x00000080
17206 +#define YAFFS_TRACE_TRACING 0x00000100
17207 +#define YAFFS_TRACE_DELETION 0x00000200
17208 +#define YAFFS_TRACE_BUFFERS 0x00000400
17209 +#define YAFFS_TRACE_NANDACCESS 0x00000800
17210 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
17211 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
17212 +#define YAFFS_TRACE_MTD 0x00004000
17213 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
17215 +#define YAFFS_TRACE_VERIFY 0x00010000
17216 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
17217 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
17218 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
17220 +#define YAFFS_TRACE_SYNC 0x00100000
17221 +#define YAFFS_TRACE_BACKGROUND 0x00200000
17222 +#define YAFFS_TRACE_LOCK 0x00400000
17224 +#define YAFFS_TRACE_ERROR 0x40000000
17225 +#define YAFFS_TRACE_BUG 0x80000000
17226 +#define YAFFS_TRACE_ALWAYS 0xF0000000
17229 +#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
17233 +++ b/fs/yaffs2/yaffs_verify.c
17236 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17238 + * Copyright (C) 2002-2010 Aleph One Ltd.
17239 + * for Toby Churchill Ltd and Brightstar Engineering
17241 + * Created by Charles Manning <charles@aleph1.co.uk>
17243 + * This program is free software; you can redistribute it and/or modify
17244 + * it under the terms of the GNU General Public License version 2 as
17245 + * published by the Free Software Foundation.
17249 +#include "yaffs_verify.h"
17250 +#include "yaffs_trace.h"
17251 +#include "yaffs_bitmap.h"
17252 +#include "yaffs_getblockinfo.h"
17253 +#include "yaffs_nand.h"
17255 +int yaffs_SkipVerification(yaffs_Device *dev)
17258 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
17261 +static int yaffs_SkipFullVerification(yaffs_Device *dev)
17264 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
17267 +static int yaffs_SkipNANDVerification(yaffs_Device *dev)
17270 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
17274 +static const char *blockStateName[] = {
17288 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17290 + int actuallyUsed;
17293 + if (yaffs_SkipVerification(dev))
17296 + /* Report illegal runtime states */
17297 + if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
17298 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
17300 + switch (bi->blockState) {
17301 + case YAFFS_BLOCK_STATE_UNKNOWN:
17302 + case YAFFS_BLOCK_STATE_SCANNING:
17303 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
17304 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
17305 + n, blockStateName[bi->blockState]));
17308 + /* Check pages in use and soft deletions are legal */
17310 + actuallyUsed = bi->pagesInUse - bi->softDeletions;
17312 + if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
17313 + bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
17314 + actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
17315 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
17316 + n, bi->pagesInUse, bi->softDeletions));
17319 + /* Check chunk bitmap legal */
17320 + inUse = yaffs_CountChunkBits(dev, n);
17321 + if (inUse != bi->pagesInUse)
17322 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
17323 + n, bi->pagesInUse, inUse));
17329 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17331 + yaffs_VerifyBlock(dev, bi, n);
17333 + /* After collection the block should be in the erased state */
17335 + if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
17336 + bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
17337 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
17338 + n, bi->blockState));
17342 +void yaffs_VerifyBlocks(yaffs_Device *dev)
17345 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
17346 + int nIllegalBlockStates = 0;
17348 + if (yaffs_SkipVerification(dev))
17351 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
17353 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
17354 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
17355 + yaffs_VerifyBlock(dev, bi, i);
17357 + if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
17358 + nBlocksPerState[bi->blockState]++;
17360 + nIllegalBlockStates++;
17363 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17364 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
17366 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
17367 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
17368 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
17370 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
17371 + T(YAFFS_TRACE_VERIFY,
17372 + (TSTR("%s %d blocks"TENDSTR),
17373 + blockStateName[i], nBlocksPerState[i]));
17375 + if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
17376 + T(YAFFS_TRACE_VERIFY,
17377 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
17378 + dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
17380 + if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
17381 + T(YAFFS_TRACE_VERIFY,
17382 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
17383 + dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
17385 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
17386 + T(YAFFS_TRACE_VERIFY,
17387 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
17388 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
17390 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17395 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
17396 + * case those tests will not be performed.
17398 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
17400 + if (obj && yaffs_SkipVerification(obj->myDev))
17403 + if (!(tags && obj && oh)) {
17404 + T(YAFFS_TRACE_VERIFY,
17405 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
17410 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
17411 + oh->type > YAFFS_OBJECT_TYPE_MAX)
17412 + T(YAFFS_TRACE_VERIFY,
17413 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
17414 + tags->objectId, oh->type));
17416 + if (tags->objectId != obj->objectId)
17417 + T(YAFFS_TRACE_VERIFY,
17418 + (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
17419 + tags->objectId, obj->objectId));
17423 + * Check that the object's parent ids match if parentCheck requested.
17425 + * Tests do not apply to the root object.
17428 + if (parentCheck && tags->objectId > 1 && !obj->parent)
17429 + T(YAFFS_TRACE_VERIFY,
17430 + (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
17431 + tags->objectId, oh->parentObjectId));
17433 + if (parentCheck && obj->parent &&
17434 + oh->parentObjectId != obj->parent->objectId &&
17435 + (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
17436 + obj->parent->objectId != YAFFS_OBJECTID_DELETED))
17437 + T(YAFFS_TRACE_VERIFY,
17438 + (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
17439 + tags->objectId, oh->parentObjectId, obj->parent->objectId));
17441 + if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
17442 + T(YAFFS_TRACE_VERIFY,
17443 + (TSTR("Obj %d header name is NULL"TENDSTR),
17446 + if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
17447 + T(YAFFS_TRACE_VERIFY,
17448 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
17454 +/* Not being used, but don't want to throw away yet */
17455 +int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
17456 + __u32 level, int chunkOffset)
17459 + yaffs_Device *dev = obj->myDev;
17465 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
17466 + if (tn->internal[i]) {
17467 + ok = yaffs_VerifyTnodeWorker(obj,
17470 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
17473 + } else if (level == 0) {
17474 + yaffs_ExtendedTags tags;
17475 + __u32 objectId = obj->objectId;
17477 + chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
17479 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
17480 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17482 + if (theChunk > 0) {
17483 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
17484 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17485 + if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
17486 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17487 + objectId, chunkOffset, theChunk,
17488 + tags.objectId, tags.chunkId));
17502 +void yaffs_VerifyFile(yaffs_Object *obj)
17504 + int requiredTallness;
17505 + int actualTallness;
17509 + yaffs_Device *dev;
17510 + yaffs_ExtendedTags tags;
17517 + if (yaffs_SkipVerification(obj->myDev))
17520 + dev = obj->myDev;
17521 + objectId = obj->objectId;
17523 + /* Check file size is consistent with tnode depth */
17524 + lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
17525 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
17526 + requiredTallness = 0;
17528 + x >>= YAFFS_TNODES_INTERNAL_BITS;
17529 + requiredTallness++;
17532 + actualTallness = obj->variant.fileVariant.topLevel;
17534 + /* Check that the chunks in the tnode tree are all correct.
17535 + * We do this by scanning through the tnode tree and
17536 + * checking the tags for every chunk match.
17539 + if (yaffs_SkipNANDVerification(dev))
17542 + for (i = 1; i <= lastChunk; i++) {
17543 + tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
17546 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17547 + if (theChunk > 0) {
17548 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
17549 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17550 + if (tags.objectId != objectId || tags.chunkId != i) {
17551 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17552 + objectId, i, theChunk,
17553 + tags.objectId, tags.chunkId));
17561 +void yaffs_VerifyHardLink(yaffs_Object *obj)
17563 + if (obj && yaffs_SkipVerification(obj->myDev))
17566 + /* Verify sane equivalent object */
17569 +void yaffs_VerifySymlink(yaffs_Object *obj)
17571 + if (obj && yaffs_SkipVerification(obj->myDev))
17574 + /* Verify symlink string */
17577 +void yaffs_VerifySpecial(yaffs_Object *obj)
17579 + if (obj && yaffs_SkipVerification(obj->myDev))
17583 +void yaffs_VerifyObject(yaffs_Object *obj)
17585 + yaffs_Device *dev;
17591 + __u32 chunkInRange;
17592 + __u32 chunkShouldNotBeDeleted;
17593 + __u32 chunkValid;
17598 + if (obj->beingCreated)
17601 + dev = obj->myDev;
17603 + if (yaffs_SkipVerification(dev))
17606 + /* Check sane object header chunk */
17608 + chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
17609 + chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
17611 + chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
17612 + chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
17613 + chunkValid = chunkInRange &&
17614 + yaffs_CheckChunkBit(dev,
17615 + obj->hdrChunk / dev->param.nChunksPerBlock,
17616 + obj->hdrChunk % dev->param.nChunksPerBlock);
17617 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
17619 + if (!obj->fake &&
17620 + (!chunkIdOk || chunkShouldNotBeDeleted)) {
17621 + T(YAFFS_TRACE_VERIFY,
17622 + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
17623 + obj->objectId, obj->hdrChunk,
17624 + chunkIdOk ? "" : ",out of range",
17625 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
17628 + if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
17629 + yaffs_ExtendedTags tags;
17630 + yaffs_ObjectHeader *oh;
17631 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
17633 + oh = (yaffs_ObjectHeader *)buffer;
17635 + yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
17638 + yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
17640 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
17643 + /* Verify it has a parent */
17644 + if (obj && !obj->fake &&
17645 + (!obj->parent || obj->parent->myDev != dev)) {
17646 + T(YAFFS_TRACE_VERIFY,
17647 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
17648 + obj->objectId, obj->parent));
17651 + /* Verify parent is a directory */
17652 + if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17653 + T(YAFFS_TRACE_VERIFY,
17654 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
17655 + obj->objectId, obj->parent->variantType));
17658 + switch (obj->variantType) {
17659 + case YAFFS_OBJECT_TYPE_FILE:
17660 + yaffs_VerifyFile(obj);
17662 + case YAFFS_OBJECT_TYPE_SYMLINK:
17663 + yaffs_VerifySymlink(obj);
17665 + case YAFFS_OBJECT_TYPE_DIRECTORY:
17666 + yaffs_VerifyDirectory(obj);
17668 + case YAFFS_OBJECT_TYPE_HARDLINK:
17669 + yaffs_VerifyHardLink(obj);
17671 + case YAFFS_OBJECT_TYPE_SPECIAL:
17672 + yaffs_VerifySpecial(obj);
17674 + case YAFFS_OBJECT_TYPE_UNKNOWN:
17676 + T(YAFFS_TRACE_VERIFY,
17677 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
17678 + obj->objectId, obj->variantType));
17683 +void yaffs_VerifyObjects(yaffs_Device *dev)
17685 + yaffs_Object *obj;
17687 + struct ylist_head *lh;
17689 + if (yaffs_SkipVerification(dev))
17692 + /* Iterate through the objects in each hash entry */
17694 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
17695 + ylist_for_each(lh, &dev->objectBucket[i].list) {
17697 + obj = ylist_entry(lh, yaffs_Object, hashLink);
17698 + yaffs_VerifyObject(obj);
17705 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
17707 + struct ylist_head *lh;
17708 + yaffs_Object *listObj;
17713 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
17718 + if (yaffs_SkipVerification(obj->myDev))
17721 + if (!obj->parent) {
17722 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
17727 + if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17728 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
17732 + /* Iterate through the objects in each hash entry */
17734 + ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
17736 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17737 + yaffs_VerifyObject(listObj);
17738 + if (obj == listObj)
17743 + if (count != 1) {
17744 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
17749 +void yaffs_VerifyDirectory(yaffs_Object *directory)
17751 + struct ylist_head *lh;
17752 + yaffs_Object *listObj;
17754 + if (!directory) {
17759 + if (yaffs_SkipFullVerification(directory->myDev))
17762 + if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17763 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
17767 + /* Iterate through the objects in each hash entry */
17769 + ylist_for_each(lh, &directory->variant.directoryVariant.children) {
17771 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17772 + if (listObj->parent != directory) {
17773 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
17776 + yaffs_VerifyObjectInDirectory(listObj);
17781 +static int yaffs_freeVerificationFailures;
17783 +void yaffs_VerifyFreeChunks(yaffs_Device *dev)
17788 + if (yaffs_SkipVerification(dev))
17791 + counted = yaffs_CountFreeChunks(dev);
17793 + difference = dev->nFreeChunks - counted;
17795 + if (difference) {
17796 + T(YAFFS_TRACE_ALWAYS,
17797 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
17798 + dev->nFreeChunks, counted, difference));
17799 + yaffs_freeVerificationFailures++;
17803 +int yaffs_VerifyFileSanity(yaffs_Object *in)
17812 + yaffs_Tags localTags;
17813 + yaffs_Tags *tags = &localTags;
17815 + int chunkDeleted;
17817 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
17818 + return YAFFS_FAIL;
17820 + objId = in->objectId;
17821 + fSize = in->variant.fileVariant.fileSize;
17823 + (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
17825 + for (chunk = 1; chunk <= nChunks; chunk++) {
17826 + tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
17831 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
17833 + if (yaffs_CheckChunkBits
17834 + (dev, theChunk / dev->param.nChunksPerBlock,
17835 + theChunk % dev->param.nChunksPerBlock)) {
17837 + yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
17840 + if (yaffs_TagsMatch
17841 + (tags, in->objectId, chunk, chunkDeleted)) {
17851 + /* T(("No level 0 found for %d\n", chunk)); */
17855 + return failed ? YAFFS_FAIL : YAFFS_OK;
17862 +++ b/fs/yaffs2/yaffs_verify.h
17865 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17867 + * Copyright (C) 2002-2010 Aleph One Ltd.
17868 + * for Toby Churchill Ltd and Brightstar Engineering
17870 + * Created by Charles Manning <charles@aleph1.co.uk>
17872 + * This program is free software; you can redistribute it and/or modify
17873 + * it under the terms of the GNU General Public License version 2 as
17874 + * published by the Free Software Foundation.
17877 +#ifndef __YAFFS_VERIFY_H__
17878 +#define __YAFFS_VERIFY_H__
17880 +#include "yaffs_guts.h"
17882 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17883 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17884 +void yaffs_VerifyBlocks(yaffs_Device *dev);
17886 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck);
17887 +void yaffs_VerifyFile(yaffs_Object *obj);
17888 +void yaffs_VerifyHardLink(yaffs_Object *obj);
17889 +void yaffs_VerifySymlink(yaffs_Object *obj);
17890 +void yaffs_VerifySpecial(yaffs_Object *obj);
17891 +void yaffs_VerifyObject(yaffs_Object *obj);
17892 +void yaffs_VerifyObjects(yaffs_Device *dev);
17893 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj);
17894 +void yaffs_VerifyDirectory(yaffs_Object *directory);
17895 +void yaffs_VerifyFreeChunks(yaffs_Device *dev);
17897 +int yaffs_VerifyFileSanity(yaffs_Object *obj);
17899 +int yaffs_SkipVerification(yaffs_Device *dev);
17904 +++ b/fs/yaffs2/yaffs_vfs_glue.c
17907 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17909 + * Copyright (C) 2002-2010 Aleph One Ltd.
17910 + * for Toby Churchill Ltd and Brightstar Engineering
17912 + * Created by Charles Manning <charles@aleph1.co.uk>
17913 + * Acknowledgements:
17914 + * Luc van OostenRyck for numerous patches.
17915 + * Nick Bane for numerous patches.
17916 + * Nick Bane for 2.5/2.6 integration.
17917 + * Andras Toth for mknod rdev issue.
17918 + * Michael Fischer for finding the problem with inode inconsistency.
17919 + * Some code bodily lifted from JFFS
17921 + * This program is free software; you can redistribute it and/or modify
17922 + * it under the terms of the GNU General Public License version 2 as
17923 + * published by the Free Software Foundation.
17928 + * This is the file system front-end to YAFFS that hooks it up to
17932 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
17933 + * this superblock
17934 + * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
17936 + * >> inode->u.generic_ip points to the associated yaffs_Object.
17940 + * There are two variants of the VFS glue code. This variant should compile
17941 + * for any version of Linux.
17943 +#include <linux/version.h>
17945 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
17946 +#define YAFFS_COMPILE_BACKGROUND
17947 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
17948 +#define YAFFS_COMPILE_FREEZER
17952 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
17953 +#define YAFFS_COMPILE_EXPORTFS
17956 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
17957 +#define YAFFS_USE_SETATTR_COPY
17958 +#define YAFFS_USE_TRUNCATE_SETSIZE
17960 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
17961 +#define YAFFS_HAS_EVICT_INODE
17964 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
17965 +#define YAFFS_NEW_FOLLOW_LINK 1
17967 +#define YAFFS_NEW_FOLLOW_LINK 0
17970 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
17971 +#include <linux/config.h>
17974 +#include <linux/kernel.h>
17975 +#include <linux/module.h>
17976 +#include <linux/slab.h>
17977 +#include <linux/init.h>
17978 +#include <linux/fs.h>
17979 +#include <linux/proc_fs.h>
17980 +#include <linux/smp_lock.h>
17981 +#include <linux/pagemap.h>
17982 +#include <linux/mtd/mtd.h>
17983 +#include <linux/interrupt.h>
17984 +#include <linux/string.h>
17985 +#include <linux/ctype.h>
17987 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
17988 +#include <linux/namei.h>
17991 +#ifdef YAFFS_COMPILE_EXPORTFS
17992 +#include <linux/exportfs.h>
17995 +#ifdef YAFFS_COMPILE_BACKGROUND
17996 +#include <linux/kthread.h>
17997 +#include <linux/delay.h>
17999 +#ifdef YAFFS_COMPILE_FREEZER
18000 +#include <linux/freezer.h>
18003 +#include <asm/div64.h>
18005 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18007 +#include <linux/statfs.h>
18009 +#define UnlockPage(p) unlock_page(p)
18010 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
18012 +/* FIXME: use sb->s_id instead ? */
18013 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
18017 +#include <linux/locks.h>
18018 +#define BDEVNAME_SIZE 0
18019 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
18021 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
18022 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
18028 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
18029 +#define YPROC_ROOT (&proc_root)
18031 +#define YPROC_ROOT NULL
18034 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
18035 +#define Y_INIT_TIMER(a) init_timer(a)
18037 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
18040 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18041 +#define WRITE_SIZE_STR "writesize"
18042 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
18044 +#define WRITE_SIZE_STR "oobblock"
18045 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
18048 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
18049 +#define YAFFS_USE_WRITE_BEGIN_END 1
18051 +#define YAFFS_USE_WRITE_BEGIN_END 0
18054 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
18055 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
18057 + uint64_t result = partition_size;
18058 + do_div(result, block_size);
18059 + return (uint32_t)result;
18062 +#define YCALCBLOCKS(s, b) ((s)/(b))
18065 +#include <linux/uaccess.h>
18066 +#include <linux/mtd/mtd.h>
18068 +#include "yportenv.h"
18069 +#include "yaffs_trace.h"
18070 +#include "yaffs_guts.h"
18072 +#include "yaffs_linux.h"
18074 +#include "yaffs_mtdif.h"
18075 +#include "yaffs_mtdif1.h"
18076 +#include "yaffs_mtdif2.h"
18078 +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
18079 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
18080 +unsigned int yaffs_auto_checkpoint = 1;
18081 +unsigned int yaffs_gc_control = 1;
18082 +unsigned int yaffs_bg_enable = 1;
18084 +/* Module Parameters */
18085 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18086 +module_param(yaffs_traceMask, uint, 0644);
18087 +module_param(yaffs_wr_attempts, uint, 0644);
18088 +module_param(yaffs_auto_checkpoint, uint, 0644);
18089 +module_param(yaffs_gc_control, uint, 0644);
18090 +module_param(yaffs_bg_enable, uint, 0644);
18092 +MODULE_PARM(yaffs_traceMask, "i");
18093 +MODULE_PARM(yaffs_wr_attempts, "i");
18094 +MODULE_PARM(yaffs_auto_checkpoint, "i");
18095 +MODULE_PARM(yaffs_gc_control, "i");
18098 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
18099 +/* use iget and read_inode */
18100 +#define Y_IGET(sb, inum) iget((sb), (inum))
18101 +static void yaffs_read_inode(struct inode *inode);
18104 +/* Call local equivalent */
18105 +#define YAFFS_USE_OWN_IGET
18106 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
18108 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
18111 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18112 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
18114 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
18117 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
18118 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
18120 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18121 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
18123 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
18127 +#define update_dir_time(dir) do {\
18128 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
18131 +static void yaffs_put_super(struct super_block *sb);
18133 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
18135 +static ssize_t yaffs_hold_space(struct file *f);
18136 +static void yaffs_release_space(struct file *f);
18138 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18139 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
18141 +static int yaffs_file_flush(struct file *file);
18144 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
18145 +static int yaffs_sync_object(struct file *file, int datasync);
18147 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
18151 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
18153 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18154 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
18155 + struct nameidata *n);
18156 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18157 + struct nameidata *n);
18159 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
18160 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
18162 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
18163 + struct dentry *dentry);
18164 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
18165 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
18166 + const char *symname);
18167 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
18169 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18170 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18173 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18176 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
18177 + struct inode *new_dir, struct dentry *new_dentry);
18178 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
18180 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18181 +static int yaffs_sync_fs(struct super_block *sb, int wait);
18182 +static void yaffs_write_super(struct super_block *sb);
18184 +static int yaffs_sync_fs(struct super_block *sb);
18185 +static int yaffs_write_super(struct super_block *sb);
18188 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18189 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
18190 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18191 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
18193 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
18196 +#ifdef YAFFS_HAS_PUT_INODE
18197 +static void yaffs_put_inode(struct inode *inode);
18200 +#ifdef YAFFS_HAS_EVICT_INODE
18201 +static void yaffs_evict_inode(struct inode *);
18203 +static void yaffs_delete_inode(struct inode *);
18204 +static void yaffs_clear_inode(struct inode *);
18207 +static int yaffs_readpage(struct file *file, struct page *page);
18208 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18209 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
18211 +static int yaffs_writepage(struct page *page);
18214 +#ifdef CONFIG_YAFFS_XATTR
18215 +int yaffs_setxattr(struct dentry *dentry, const char *name,
18216 + const void *value, size_t size, int flags);
18217 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
18219 +int yaffs_removexattr(struct dentry *dentry, const char *name);
18220 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
18224 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
18225 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
18226 + loff_t pos, unsigned len, unsigned flags,
18227 + struct page **pagep, void **fsdata);
18228 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
18229 + loff_t pos, unsigned len, unsigned copied,
18230 + struct page *pg, void *fsdadata);
18232 +static int yaffs_prepare_write(struct file *f, struct page *pg,
18233 + unsigned offset, unsigned to);
18234 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
18239 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18241 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18242 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
18243 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18245 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18248 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
18250 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
18252 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
18255 +static struct address_space_operations yaffs_file_address_operations = {
18256 + .readpage = yaffs_readpage,
18257 + .writepage = yaffs_writepage,
18258 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
18259 + .write_begin = yaffs_write_begin,
18260 + .write_end = yaffs_write_end,
18262 + .prepare_write = yaffs_prepare_write,
18263 + .commit_write = yaffs_commit_write,
18268 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
18269 +static const struct file_operations yaffs_file_operations = {
18270 + .read = do_sync_read,
18271 + .write = do_sync_write,
18272 + .aio_read = generic_file_aio_read,
18273 + .aio_write = generic_file_aio_write,
18274 + .mmap = generic_file_mmap,
18275 + .flush = yaffs_file_flush,
18276 + .fsync = yaffs_sync_object,
18277 + .splice_read = generic_file_splice_read,
18278 + .splice_write = generic_file_splice_write,
18279 + .llseek = generic_file_llseek,
18282 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18284 +static const struct file_operations yaffs_file_operations = {
18285 + .read = do_sync_read,
18286 + .write = do_sync_write,
18287 + .aio_read = generic_file_aio_read,
18288 + .aio_write = generic_file_aio_write,
18289 + .mmap = generic_file_mmap,
18290 + .flush = yaffs_file_flush,
18291 + .fsync = yaffs_sync_object,
18292 + .sendfile = generic_file_sendfile,
18297 +static const struct file_operations yaffs_file_operations = {
18298 + .read = generic_file_read,
18299 + .write = generic_file_write,
18300 + .mmap = generic_file_mmap,
18301 + .flush = yaffs_file_flush,
18302 + .fsync = yaffs_sync_object,
18303 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18304 + .sendfile = generic_file_sendfile,
18309 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
18310 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
18312 + void * kaddr = kmap_atomic(page, KM_USER0);
18313 + memset(kaddr + start, 0, end - start);
18314 + kunmap_atomic(kaddr, KM_USER0);
18315 + flush_dcache_page(page);
18320 +static const struct inode_operations yaffs_file_inode_operations = {
18321 + .setattr = yaffs_setattr,
18322 +#ifdef CONFIG_YAFFS_XATTR
18323 + .setxattr = yaffs_setxattr,
18324 + .getxattr = yaffs_getxattr,
18325 + .listxattr = yaffs_listxattr,
18326 + .removexattr = yaffs_removexattr,
18330 +static const struct inode_operations yaffs_symlink_inode_operations = {
18331 + .readlink = yaffs_readlink,
18332 + .follow_link = yaffs_follow_link,
18333 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18334 + .put_link = yaffs_put_link,
18336 + .setattr = yaffs_setattr,
18337 +#ifdef CONFIG_YAFFS_XATTR
18338 + .setxattr = yaffs_setxattr,
18339 + .getxattr = yaffs_getxattr,
18340 + .listxattr = yaffs_listxattr,
18341 + .removexattr = yaffs_removexattr,
18345 +static const struct inode_operations yaffs_dir_inode_operations = {
18346 + .create = yaffs_create,
18347 + .lookup = yaffs_lookup,
18348 + .link = yaffs_link,
18349 + .unlink = yaffs_unlink,
18350 + .symlink = yaffs_symlink,
18351 + .mkdir = yaffs_mkdir,
18352 + .rmdir = yaffs_unlink,
18353 + .mknod = yaffs_mknod,
18354 + .rename = yaffs_rename,
18355 + .setattr = yaffs_setattr,
18356 +#ifdef CONFIG_YAFFS_XATTR
18357 + .setxattr = yaffs_setxattr,
18358 + .getxattr = yaffs_getxattr,
18359 + .listxattr = yaffs_listxattr,
18360 + .removexattr = yaffs_removexattr,
18364 +static const struct file_operations yaffs_dir_operations = {
18365 + .read = generic_read_dir,
18366 + .readdir = yaffs_readdir,
18367 + .fsync = yaffs_sync_object,
18368 + .llseek = yaffs_dir_llseek,
18371 +static const struct super_operations yaffs_super_ops = {
18372 + .statfs = yaffs_statfs,
18374 +#ifndef YAFFS_USE_OWN_IGET
18375 + .read_inode = yaffs_read_inode,
18377 +#ifdef YAFFS_HAS_PUT_INODE
18378 + .put_inode = yaffs_put_inode,
18380 + .put_super = yaffs_put_super,
18381 +#ifdef YAFFS_HAS_EVICT_INODE
18382 + .evict_inode = yaffs_evict_inode,
18384 + .delete_inode = yaffs_delete_inode,
18385 + .clear_inode = yaffs_clear_inode,
18387 + .sync_fs = yaffs_sync_fs,
18388 + .write_super = yaffs_write_super,
18392 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
18394 +#ifdef YAFFS_USE_SETATTR_COPY
18395 + setattr_copy(inode,attr);
18398 + return inode_setattr(inode, attr);
18403 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
18405 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
18406 + truncate_setsize(inode,newsize);
18409 + truncate_inode_pages(&inode->i_data,newsize);
18415 +static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
18417 + return yaffs_gc_control;
18420 +static void yaffs_GrossLock(yaffs_Device *dev)
18422 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
18423 + down(&(yaffs_DeviceToLC(dev)->grossLock));
18424 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
18427 +static void yaffs_GrossUnlock(yaffs_Device *dev)
18429 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
18430 + up(&(yaffs_DeviceToLC(dev)->grossLock));
18433 +#ifdef YAFFS_COMPILE_EXPORTFS
18435 +static struct inode *
18436 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
18438 + return Y_IGET(sb, ino);
18441 +static struct dentry *
18442 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18444 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
18447 +static struct dentry *
18448 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18450 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
18453 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
18456 + struct super_block *sb = dentry->d_inode->i_sb;
18457 + struct dentry *parent = ERR_PTR(-ENOENT);
18458 + struct inode *inode;
18459 + unsigned long parent_ino;
18460 + yaffs_Object *d_obj;
18461 + yaffs_Object *parent_obj;
18463 + d_obj = yaffs_InodeToObject(dentry->d_inode);
18466 + parent_obj = d_obj->parent;
18467 + if (parent_obj) {
18468 + parent_ino = yaffs_GetObjectInode(parent_obj);
18469 + inode = Y_IGET(sb, parent_ino);
18471 + if (IS_ERR(inode)) {
18472 + parent = ERR_CAST(inode);
18474 + parent = d_obtain_alias(inode);
18475 + if (!IS_ERR(parent)) {
18476 + parent = ERR_PTR(-ENOMEM);
18486 +/* Just declare a zero structure as a NULL value implies
18487 + * using the default functions of exportfs.
18490 +static struct export_operations yaffs_export_ops =
18492 + .fh_to_dentry = yaffs2_fh_to_dentry,
18493 + .fh_to_parent = yaffs2_fh_to_parent,
18494 + .get_parent = yaffs2_get_parent,
18499 +/*-----------------------------------------------------------------*/
18500 +/* Directory search context allows us to unlock access to yaffs during
18501 + * filldir without causing problems with the directory being modified.
18502 + * This is similar to the tried and tested mechanism used in yaffs direct.
18504 + * A search context iterates along a doubly linked list of siblings in the
18505 + * directory. If the iterating object is deleted then this would corrupt
18506 + * the list iteration, likely causing a crash. The search context avoids
18507 + * this by using the removeObjectCallback to move the search context to the
18508 + * next object before the object is deleted.
18510 + * Many readdirs (and thus seach conexts) may be alive simulateously so
18511 + * each yaffs_Device has a list of these.
18513 + * A seach context lives for the duration of a readdir.
18515 + * All these functions must be called while yaffs is locked.
18518 +struct yaffs_SearchContext {
18519 + yaffs_Device *dev;
18520 + yaffs_Object *dirObj;
18521 + yaffs_Object *nextReturn;
18522 + struct ylist_head others;
18526 + * yaffs_NewSearch() creates a new search context, initialises it and
18527 + * adds it to the device's search context list.
18529 + * Called at start of readdir.
18531 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
18533 + yaffs_Device *dev = dir->myDev;
18534 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
18536 + sc->dirObj = dir;
18538 + if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18539 + sc->nextReturn = NULL;
18541 + sc->nextReturn = ylist_entry(
18542 + dir->variant.directoryVariant.children.next,
18543 + yaffs_Object,siblings);
18544 + YINIT_LIST_HEAD(&sc->others);
18545 + ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
18551 + * yaffs_EndSearch() disposes of a search context and cleans up.
18553 +static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
18556 + ylist_del(&sc->others);
18562 + * yaffs_SearchAdvance() moves a search context to the next object.
18563 + * Called when the search iterates or when an object removal causes
18564 + * the search context to be moved to the next object.
18566 +static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
18571 + if( sc->nextReturn == NULL ||
18572 + ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18573 + sc->nextReturn = NULL;
18575 + struct ylist_head *next = sc->nextReturn->siblings.next;
18577 + if( next == &sc->dirObj->variant.directoryVariant.children)
18578 + sc->nextReturn = NULL; /* end of list */
18580 + sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
18585 + * yaffs_RemoveObjectCallback() is called when an object is unlinked.
18586 + * We check open search contexts and advance any which are currently
18587 + * on the object being iterated.
18589 +static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
18592 + struct ylist_head *i;
18593 + struct yaffs_SearchContext *sc;
18594 + struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
18597 + /* Iterate through the directory search contexts.
18598 + * If any are currently on the object being removed, then advance
18599 + * the search context to the next object to prevent a hanging pointer.
18601 + ylist_for_each(i, search_contexts) {
18603 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
18604 + if(sc->nextReturn == obj)
18605 + yaffs_SearchAdvance(sc);
18612 +/*-----------------------------------------------------------------*/
18614 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18617 + unsigned char *alias;
18620 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18622 + yaffs_GrossLock(dev);
18624 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18626 + yaffs_GrossUnlock(dev);
18631 + ret = vfs_readlink(dentry, buffer, buflen, alias);
18636 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18637 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18639 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18642 + unsigned char *alias;
18644 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18646 + yaffs_GrossLock(dev);
18648 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18649 + yaffs_GrossUnlock(dev);
18656 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18657 + nd_set_link(nd, alias);
18658 + ret = (int)alias;
18660 + return ERR_PTR(ret);
18662 + ret = vfs_follow_link(nd, alias);
18669 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18670 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
18675 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
18676 + yaffs_Object *obj);
18679 + * Lookup is used to find objects in the fs
18681 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18683 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18684 + struct nameidata *n)
18686 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
18689 + yaffs_Object *obj;
18690 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
18692 + yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
18694 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18695 + yaffs_GrossLock(dev);
18697 + T(YAFFS_TRACE_OS,
18698 + (TSTR("yaffs_lookup for %d:%s\n"),
18699 + yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
18701 + obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
18702 + dentry->d_name.name);
18704 + obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
18706 + /* Can't hold gross lock when calling yaffs_get_inode() */
18707 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18708 + yaffs_GrossUnlock(dev);
18711 + T(YAFFS_TRACE_OS,
18712 + (TSTR("yaffs_lookup found %d\n"), obj->objectId));
18714 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
18717 + T(YAFFS_TRACE_OS,
18718 + (TSTR("yaffs_loookup dentry \n")));
18719 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
18720 + * d_add even if NULL inode */
18722 + /*dget(dentry); // try to solve directory bug */
18723 + d_add(dentry, inode);
18725 + /* return dentry; */
18731 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
18735 +/* added NCB for 2.5/6 compatability - forces add even if inode is
18736 + * NULL which creates dentry hash */
18737 + d_add(dentry, inode);
18743 +#ifdef YAFFS_HAS_PUT_INODE
18745 +/* For now put inode is just for debugging
18746 + * Put inode is called when the inode **structure** is put.
18748 +static void yaffs_put_inode(struct inode *inode)
18750 + T(YAFFS_TRACE_OS,
18751 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
18752 + atomic_read(&inode->i_count)));
18758 +static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj)
18760 + /* Clear the association between the inode and
18761 + * the yaffs_Object.
18763 + obj->myInode = NULL;
18764 + yaffs_InodeToObjectLV(inode) = NULL;
18766 + /* If the object freeing was deferred, then the real
18767 + * free happens now.
18768 + * This should fix the inode inconsistency problem.
18770 + yaffs_HandleDeferedFree(obj);
18773 +#ifdef YAFFS_HAS_EVICT_INODE
18774 +/* yaffs_evict_inode combines into one operation what was previously done in
18775 + * yaffs_clear_inode() and yaffs_delete_inode()
18778 +static void yaffs_evict_inode( struct inode *inode)
18780 + yaffs_Object *obj;
18781 + yaffs_Device *dev;
18782 + int deleteme = 0;
18784 + obj = yaffs_InodeToObject(inode);
18786 + T(YAFFS_TRACE_OS,
18787 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18788 + atomic_read(&inode->i_count),
18789 + obj ? "object exists" : "null object"));
18791 + if (!inode->i_nlink && !is_bad_inode(inode))
18793 + truncate_inode_pages(&inode->i_data,0);
18794 + end_writeback(inode);
18796 + if(deleteme && obj){
18797 + dev = obj->myDev;
18798 + yaffs_GrossLock(dev);
18799 + yaffs_DeleteObject(obj);
18800 + yaffs_GrossUnlock(dev);
18803 + dev = obj->myDev;
18804 + yaffs_GrossLock(dev);
18805 + yaffs_UnstitchObject(inode,obj);
18806 + yaffs_GrossUnlock(dev);
18813 +/* clear is called to tell the fs to release any per-inode data it holds.
18814 + * The object might still exist on disk and is just being thrown out of the cache
18815 + * or else the object has actually been deleted and we're being called via
18817 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
18820 +static void yaffs_clear_inode(struct inode *inode)
18822 + yaffs_Object *obj;
18823 + yaffs_Device *dev;
18825 + obj = yaffs_InodeToObject(inode);
18827 + T(YAFFS_TRACE_OS,
18828 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18829 + atomic_read(&inode->i_count),
18830 + obj ? "object exists" : "null object"));
18833 + dev = obj->myDev;
18834 + yaffs_GrossLock(dev);
18835 + yaffs_UnstitchObject(inode,obj);
18836 + yaffs_GrossUnlock(dev);
18841 +/* delete is called when the link count is zero and the inode
18842 + * is put (ie. nobody wants to know about it anymore, time to
18843 + * delete the file).
18844 + * NB Must call clear_inode()
18846 +static void yaffs_delete_inode(struct inode *inode)
18848 + yaffs_Object *obj = yaffs_InodeToObject(inode);
18849 + yaffs_Device *dev;
18851 + T(YAFFS_TRACE_OS,
18852 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18853 + atomic_read(&inode->i_count),
18854 + obj ? "object exists" : "null object"));
18857 + dev = obj->myDev;
18858 + yaffs_GrossLock(dev);
18859 + yaffs_DeleteObject(obj);
18860 + yaffs_GrossUnlock(dev);
18862 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
18863 + truncate_inode_pages(&inode->i_data, 0);
18865 + clear_inode(inode);
18870 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18871 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
18873 +static int yaffs_file_flush(struct file *file)
18876 + yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
18878 + yaffs_Device *dev = obj->myDev;
18880 + T(YAFFS_TRACE_OS,
18881 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId,
18882 + obj->dirty ? "dirty" : "clean"));
18884 + yaffs_GrossLock(dev);
18886 + yaffs_FlushFile(obj, 1, 0);
18888 + yaffs_GrossUnlock(dev);
18893 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
18895 + /* Lifted from jffs2 */
18897 + yaffs_Object *obj;
18898 + unsigned char *pg_buf;
18901 + yaffs_Device *dev;
18903 + T(YAFFS_TRACE_OS,
18904 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
18905 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
18906 + (unsigned)PAGE_CACHE_SIZE));
18908 + obj = yaffs_DentryToObject(f->f_dentry);
18910 + dev = obj->myDev;
18912 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18913 + BUG_ON(!PageLocked(pg));
18915 + if (!PageLocked(pg))
18919 + pg_buf = kmap(pg);
18920 + /* FIXME: Can kmap fail? */
18922 + yaffs_GrossLock(dev);
18924 + ret = yaffs_ReadDataFromFile(obj, pg_buf,
18925 + pg->index << PAGE_CACHE_SHIFT,
18926 + PAGE_CACHE_SIZE);
18928 + yaffs_GrossUnlock(dev);
18934 + ClearPageUptodate(pg);
18935 + SetPageError(pg);
18937 + SetPageUptodate(pg);
18938 + ClearPageError(pg);
18941 + flush_dcache_page(pg);
18944 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
18948 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
18950 + int ret = yaffs_readpage_nolock(f, pg);
18955 +static int yaffs_readpage(struct file *f, struct page *pg)
18959 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
18960 + ret=yaffs_readpage_unlock(f, pg);
18961 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
18965 +/* writepage inspired by/stolen from smbfs */
18967 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18968 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
18970 +static int yaffs_writepage(struct page *page)
18973 + yaffs_Device *dev;
18974 + struct address_space *mapping = page->mapping;
18975 + struct inode *inode;
18976 + unsigned long end_index;
18978 + yaffs_Object *obj;
18979 + int nWritten = 0;
18985 + inode = mapping->host;
18988 + i_size = i_size_read(inode);
18990 + end_index = i_size >> PAGE_CACHE_SHIFT;
18992 + if(page->index < end_index)
18993 + nBytes = PAGE_CACHE_SIZE;
18995 + nBytes = i_size & (PAGE_CACHE_SIZE -1);
18997 + if (page->index > end_index || !nBytes) {
18998 + T(YAFFS_TRACE_OS,
18999 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
19000 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
19001 + (unsigned)inode->i_size));
19002 + T(YAFFS_TRACE_OS,
19003 + (TSTR(" -> don't care!!\n")));
19005 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
19006 + set_page_writeback(page);
19007 + unlock_page(page);
19008 + end_page_writeback(page);
19013 + if(nBytes != PAGE_CACHE_SIZE)
19014 + zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
19018 + buffer = kmap(page);
19020 + obj = yaffs_InodeToObject(inode);
19021 + dev = obj->myDev;
19022 + yaffs_GrossLock(dev);
19024 + T(YAFFS_TRACE_OS,
19025 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
19026 + (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
19027 + T(YAFFS_TRACE_OS,
19028 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
19029 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19031 + nWritten = yaffs_WriteDataToFile(obj, buffer,
19032 + page->index << PAGE_CACHE_SHIFT, nBytes, 0);
19034 + yaffs_MarkSuperBlockDirty(dev);
19036 + T(YAFFS_TRACE_OS,
19037 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
19038 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19040 + yaffs_GrossUnlock(dev);
19043 + set_page_writeback(page);
19044 + unlock_page(page);
19045 + end_page_writeback(page);
19048 + return (nWritten == nBytes) ? 0 : -ENOSPC;
19052 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19053 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
19054 + loff_t pos, unsigned len, unsigned flags,
19055 + struct page **pagep, void **fsdata)
19057 + struct page *pg = NULL;
19058 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
19061 + int space_held = 0;
19064 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
19065 + pg = grab_cache_page_write_begin(mapping, index, flags);
19067 + pg = __grab_cache_page(mapping, index);
19075 + T(YAFFS_TRACE_OS,
19076 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
19077 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
19079 + /* Get fs space */
19080 + space_held = yaffs_hold_space(filp);
19082 + if (!space_held) {
19087 + /* Update page if required */
19089 + if (!Page_Uptodate(pg))
19090 + ret = yaffs_readpage_nolock(filp, pg);
19095 + /* Happy path return */
19096 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
19101 + T(YAFFS_TRACE_OS,
19102 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
19104 + yaffs_release_space(filp);
19107 + page_cache_release(pg);
19114 +static int yaffs_prepare_write(struct file *f, struct page *pg,
19115 + unsigned offset, unsigned to)
19117 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
19119 + if (!Page_Uptodate(pg))
19120 + return yaffs_readpage_nolock(f, pg);
19125 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19126 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
19127 + loff_t pos, unsigned len, unsigned copied,
19128 + struct page *pg, void *fsdadata)
19131 + void *addr, *kva;
19132 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
19135 + addr = kva + offset_into_page;
19137 + T(YAFFS_TRACE_OS,
19138 + ("yaffs_write_end addr %p pos %x nBytes %d\n",
19139 + addr,(unsigned)pos, copied));
19141 + ret = yaffs_file_write(filp, addr, copied, &pos);
19143 + if (ret != copied) {
19144 + T(YAFFS_TRACE_OS,
19145 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
19147 + SetPageError(pg);
19154 + yaffs_release_space(filp);
19156 + page_cache_release(pg);
19161 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
19164 + void *addr, *kva;
19166 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
19167 + int nBytes = to - offset;
19170 + unsigned spos = pos;
19174 + addr = kva + offset;
19176 + saddr = (unsigned) addr;
19178 + T(YAFFS_TRACE_OS,
19179 + (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"),
19180 + saddr, spos, nBytes));
19182 + nWritten = yaffs_file_write(f, addr, nBytes, &pos);
19184 + if (nWritten != nBytes) {
19185 + T(YAFFS_TRACE_OS,
19186 + (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"),
19187 + nWritten, nBytes));
19188 + SetPageError(pg);
19195 + T(YAFFS_TRACE_OS,
19196 + (TSTR("yaffs_commit_write returning %d\n"),
19197 + nWritten == nBytes ? 0 : nWritten));
19199 + return nWritten == nBytes ? 0 : nWritten;
19204 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
19206 + if (inode && obj) {
19209 + /* Check mode against the variant type and attempt to repair if broken. */
19210 + __u32 mode = obj->yst_mode;
19211 + switch (obj->variantType) {
19212 + case YAFFS_OBJECT_TYPE_FILE:
19213 + if (!S_ISREG(mode)) {
19214 + obj->yst_mode &= ~S_IFMT;
19215 + obj->yst_mode |= S_IFREG;
19219 + case YAFFS_OBJECT_TYPE_SYMLINK:
19220 + if (!S_ISLNK(mode)) {
19221 + obj->yst_mode &= ~S_IFMT;
19222 + obj->yst_mode |= S_IFLNK;
19226 + case YAFFS_OBJECT_TYPE_DIRECTORY:
19227 + if (!S_ISDIR(mode)) {
19228 + obj->yst_mode &= ~S_IFMT;
19229 + obj->yst_mode |= S_IFDIR;
19233 + case YAFFS_OBJECT_TYPE_UNKNOWN:
19234 + case YAFFS_OBJECT_TYPE_HARDLINK:
19235 + case YAFFS_OBJECT_TYPE_SPECIAL:
19241 + inode->i_flags |= S_NOATIME;
19243 + inode->i_ino = obj->objectId;
19244 + inode->i_mode = obj->yst_mode;
19245 + inode->i_uid = obj->yst_uid;
19246 + inode->i_gid = obj->yst_gid;
19247 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
19248 + inode->i_blksize = inode->i_sb->s_blocksize;
19250 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19252 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
19253 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
19254 + inode->i_atime.tv_nsec = 0;
19255 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
19256 + inode->i_mtime.tv_nsec = 0;
19257 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
19258 + inode->i_ctime.tv_nsec = 0;
19260 + inode->i_rdev = obj->yst_rdev;
19261 + inode->i_atime = obj->yst_atime;
19262 + inode->i_mtime = obj->yst_mtime;
19263 + inode->i_ctime = obj->yst_ctime;
19265 + inode->i_size = yaffs_GetObjectFileLength(obj);
19266 + inode->i_blocks = (inode->i_size + 511) >> 9;
19268 + inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19270 + T(YAFFS_TRACE_OS,
19271 + (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"),
19272 + inode->i_mode, inode->i_uid, inode->i_gid,
19273 + (int)inode->i_size, atomic_read(&inode->i_count)));
19275 + switch (obj->yst_mode & S_IFMT) {
19276 + default: /* fifo, device or socket */
19277 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19278 + init_special_inode(inode, obj->yst_mode,
19279 + old_decode_dev(obj->yst_rdev));
19281 + init_special_inode(inode, obj->yst_mode,
19282 + (dev_t) (obj->yst_rdev));
19285 + case S_IFREG: /* file */
19286 + inode->i_op = &yaffs_file_inode_operations;
19287 + inode->i_fop = &yaffs_file_operations;
19288 + inode->i_mapping->a_ops =
19289 + &yaffs_file_address_operations;
19291 + case S_IFDIR: /* directory */
19292 + inode->i_op = &yaffs_dir_inode_operations;
19293 + inode->i_fop = &yaffs_dir_operations;
19295 + case S_IFLNK: /* symlink */
19296 + inode->i_op = &yaffs_symlink_inode_operations;
19300 + yaffs_InodeToObjectLV(inode) = obj;
19302 + obj->myInode = inode;
19305 + T(YAFFS_TRACE_OS,
19306 + (TSTR("yaffs_FileInode invalid parameters\n")));
19311 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
19312 + yaffs_Object *obj)
19314 + struct inode *inode;
19317 + T(YAFFS_TRACE_OS,
19318 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
19324 + T(YAFFS_TRACE_OS,
19325 + (TSTR("yaffs_get_inode for NULL object!!\n")));
19330 + T(YAFFS_TRACE_OS,
19331 + (TSTR("yaffs_get_inode for object %d\n"), obj->objectId));
19333 + inode = Y_IGET(sb, obj->objectId);
19334 + if (IS_ERR(inode))
19337 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
19338 + /* iget also increments the inode's i_count */
19339 + /* NB You can't be holding grossLock or deadlock will happen! */
19344 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
19347 + yaffs_Object *obj;
19348 + int nWritten, ipos;
19349 + struct inode *inode;
19350 + yaffs_Device *dev;
19352 + obj = yaffs_DentryToObject(f->f_dentry);
19354 + dev = obj->myDev;
19356 + yaffs_GrossLock(dev);
19358 + inode = f->f_dentry->d_inode;
19360 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
19361 + ipos = inode->i_size;
19366 + T(YAFFS_TRACE_OS,
19367 + (TSTR("yaffs_file_write: hey obj is null!\n")));
19369 + T(YAFFS_TRACE_OS,
19370 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
19371 + "to object %d at %d(%x)\n"),
19372 + (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
19374 + nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
19376 + yaffs_MarkSuperBlockDirty(dev);
19378 + T(YAFFS_TRACE_OS,
19379 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
19380 + (unsigned )n,(unsigned)n));
19382 + if (nWritten > 0) {
19383 + ipos += nWritten;
19385 + if (ipos > inode->i_size) {
19386 + inode->i_size = ipos;
19387 + inode->i_blocks = (ipos + 511) >> 9;
19389 + T(YAFFS_TRACE_OS,
19390 + (TSTR("yaffs_file_write size updated to %d bytes, "
19392 + ipos, (int)(inode->i_blocks)));
19396 + yaffs_GrossUnlock(dev);
19397 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
19400 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
19401 +/* For now we just assume few parallel writes and check against a small number. */
19402 +/* Todo: need to do this with a counter to handle parallel reads better */
19404 +static ssize_t yaffs_hold_space(struct file *f)
19406 + yaffs_Object *obj;
19407 + yaffs_Device *dev;
19412 + obj = yaffs_DentryToObject(f->f_dentry);
19414 + dev = obj->myDev;
19416 + yaffs_GrossLock(dev);
19418 + nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
19420 + yaffs_GrossUnlock(dev);
19422 + return (nFreeChunks > 20) ? 1 : 0;
19425 +static void yaffs_release_space(struct file *f)
19427 + yaffs_Object *obj;
19428 + yaffs_Device *dev;
19431 + obj = yaffs_DentryToObject(f->f_dentry);
19433 + dev = obj->myDev;
19435 + yaffs_GrossLock(dev);
19438 + yaffs_GrossUnlock(dev);
19442 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
19444 + long long retval;
19450 + offset += i_size_read(file->f_path.dentry->d_inode);
19453 + offset += file->f_pos;
19455 + retval = -EINVAL;
19457 + if (offset >= 0){
19458 + if (offset != file->f_pos)
19459 + file->f_pos = offset;
19468 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
19470 + yaffs_Object *obj;
19471 + yaffs_Device *dev;
19472 + struct yaffs_SearchContext *sc;
19473 + struct inode *inode = f->f_dentry->d_inode;
19474 + unsigned long offset, curoffs;
19478 + char name[YAFFS_MAX_NAME_LENGTH + 1];
19480 + obj = yaffs_DentryToObject(f->f_dentry);
19481 + dev = obj->myDev;
19483 + yaffs_GrossLock(dev);
19485 + yaffs_DeviceToLC(dev)->readdirProcess = current;
19487 + offset = f->f_pos;
19489 + sc = yaffs_NewSearch(obj);
19491 + retVal = -ENOMEM;
19495 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
19497 + if (offset == 0) {
19498 + T(YAFFS_TRACE_OS,
19499 + (TSTR("yaffs_readdir: entry . ino %d \n"),
19500 + (int)inode->i_ino));
19501 + yaffs_GrossUnlock(dev);
19502 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
19503 + yaffs_GrossLock(dev);
19506 + yaffs_GrossLock(dev);
19510 + if (offset == 1) {
19511 + T(YAFFS_TRACE_OS,
19512 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
19513 + (int)f->f_dentry->d_parent->d_inode->i_ino));
19514 + yaffs_GrossUnlock(dev);
19515 + if (filldir(dirent, "..", 2, offset,
19516 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
19517 + yaffs_GrossLock(dev);
19520 + yaffs_GrossLock(dev);
19527 + /* If the directory has changed since the open or last call to
19528 + readdir, rewind to after the 2 canned entries. */
19529 + if (f->f_version != inode->i_version) {
19531 + f->f_pos = offset;
19532 + f->f_version = inode->i_version;
19535 + while(sc->nextReturn){
19537 + l = sc->nextReturn;
19538 + if (curoffs >= offset) {
19539 + int this_inode = yaffs_GetObjectInode(l);
19540 + int this_type = yaffs_GetObjectType(l);
19542 + yaffs_GetObjectName(l, name,
19543 + YAFFS_MAX_NAME_LENGTH + 1);
19544 + T(YAFFS_TRACE_OS,
19545 + (TSTR("yaffs_readdir: %s inode %d\n"),
19546 + name, yaffs_GetObjectInode(l)));
19548 + yaffs_GrossUnlock(dev);
19550 + if (filldir(dirent,
19556 + yaffs_GrossLock(dev);
19560 + yaffs_GrossLock(dev);
19565 + yaffs_SearchAdvance(sc);
19569 + yaffs_EndSearch(sc);
19570 + yaffs_DeviceToLC(dev)->readdirProcess = NULL;
19571 + yaffs_GrossUnlock(dev);
19579 + * File creation. Allocate an inode, and we're done..
19582 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
19583 +#define YCRED(x) x
19585 +#define YCRED(x) (x->cred)
19588 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19589 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19592 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19596 + struct inode *inode;
19598 + yaffs_Object *obj = NULL;
19599 + yaffs_Device *dev;
19601 + yaffs_Object *parent = yaffs_InodeToObject(dir);
19603 + int error = -ENOSPC;
19604 + uid_t uid = YCRED(current)->fsuid;
19605 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19607 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
19611 + T(YAFFS_TRACE_OS,
19612 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
19613 + parent->objectId, parent->variantType));
19615 + T(YAFFS_TRACE_OS,
19616 + (TSTR("yaffs_mknod: could not get parent object\n")));
19620 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
19621 + "mode %x dev %x\n"),
19622 + dentry->d_name.name, mode, rdev));
19624 + dev = parent->myDev;
19626 + yaffs_GrossLock(dev);
19628 + switch (mode & S_IFMT) {
19630 + /* Special (socket, fifo, device...) */
19631 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
19632 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19633 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19634 + gid, old_encode_dev(rdev));
19636 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19640 + case S_IFREG: /* file */
19641 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
19642 + obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
19645 + case S_IFDIR: /* directory */
19646 + T(YAFFS_TRACE_OS,
19647 + (TSTR("yaffs_mknod: making directory\n")));
19648 + obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
19651 + case S_IFLNK: /* symlink */
19652 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
19653 + obj = NULL; /* Do we ever get here? */
19657 + /* Can not call yaffs_get_inode() with gross lock held */
19658 + yaffs_GrossUnlock(dev);
19661 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
19662 + d_instantiate(dentry, inode);
19663 + update_dir_time(dir);
19664 + T(YAFFS_TRACE_OS,
19665 + (TSTR("yaffs_mknod created object %d count = %d\n"),
19666 + obj->objectId, atomic_read(&inode->i_count)));
19668 + yaffs_FillInodeFromObject(dir,parent);
19670 + T(YAFFS_TRACE_OS,
19671 + (TSTR("yaffs_mknod failed making object\n")));
19678 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
19681 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
19682 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
19686 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19687 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
19688 + struct nameidata *n)
19690 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
19693 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
19694 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
19697 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
19701 + yaffs_Device *dev;
19702 + yaffs_Object *obj;
19704 + T(YAFFS_TRACE_OS,
19705 + (TSTR("yaffs_unlink %d:%s\n"),
19706 + (int)(dir->i_ino),
19707 + dentry->d_name.name));
19708 + obj = yaffs_InodeToObject(dir);
19709 + dev = obj->myDev;
19711 + yaffs_GrossLock(dev);
19713 + retVal = yaffs_Unlink(obj, dentry->d_name.name);
19715 + if (retVal == YAFFS_OK) {
19716 + dentry->d_inode->i_nlink--;
19717 + dir->i_version++;
19718 + yaffs_GrossUnlock(dev);
19719 + mark_inode_dirty(dentry->d_inode);
19720 + update_dir_time(dir);
19723 + yaffs_GrossUnlock(dev);
19724 + return -ENOTEMPTY;
19728 + * Create a link...
19730 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
19731 + struct dentry *dentry)
19733 + struct inode *inode = old_dentry->d_inode;
19734 + yaffs_Object *obj = NULL;
19735 + yaffs_Object *link = NULL;
19736 + yaffs_Device *dev;
19738 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
19740 + obj = yaffs_InodeToObject(inode);
19741 + dev = obj->myDev;
19743 + yaffs_GrossLock(dev);
19745 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
19746 + link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
19750 + old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19751 + d_instantiate(dentry, old_dentry->d_inode);
19752 + atomic_inc(&old_dentry->d_inode->i_count);
19753 + T(YAFFS_TRACE_OS,
19754 + (TSTR("yaffs_link link count %d i_count %d\n"),
19755 + old_dentry->d_inode->i_nlink,
19756 + atomic_read(&old_dentry->d_inode->i_count)));
19759 + yaffs_GrossUnlock(dev);
19762 + update_dir_time(dir);
19769 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
19770 + const char *symname)
19772 + yaffs_Object *obj;
19773 + yaffs_Device *dev;
19774 + uid_t uid = YCRED(current)->fsuid;
19775 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19777 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
19779 + dev = yaffs_InodeToObject(dir)->myDev;
19780 + yaffs_GrossLock(dev);
19781 + obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
19782 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
19783 + yaffs_GrossUnlock(dev);
19786 + struct inode *inode;
19788 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
19789 + d_instantiate(dentry, inode);
19790 + update_dir_time(dir);
19791 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
19794 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
19800 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19801 +static int yaffs_sync_object(struct file *file, int datasync)
19803 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
19808 + yaffs_Object *obj;
19809 + yaffs_Device *dev;
19810 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19811 + struct dentry *dentry = file->f_path.dentry;
19814 + obj = yaffs_DentryToObject(dentry);
19816 + dev = obj->myDev;
19818 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
19819 + (TSTR("yaffs_sync_object\n")));
19820 + yaffs_GrossLock(dev);
19821 + yaffs_FlushFile(obj, 1, datasync);
19822 + yaffs_GrossUnlock(dev);
19827 + * The VFS layer already does all the dentry stuff for rename.
19829 + * NB: POSIX says you can rename an object over an old object of the same name
19831 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
19832 + struct inode *new_dir, struct dentry *new_dentry)
19834 + yaffs_Device *dev;
19835 + int retVal = YAFFS_FAIL;
19836 + yaffs_Object *target;
19838 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
19839 + dev = yaffs_InodeToObject(old_dir)->myDev;
19841 + yaffs_GrossLock(dev);
19843 + /* Check if the target is an existing directory that is not empty. */
19844 + target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
19845 + new_dentry->d_name.name);
19849 + if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
19850 + !ylist_empty(&target->variant.directoryVariant.children)) {
19852 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
19854 + retVal = YAFFS_FAIL;
19856 + /* Now does unlinking internally using shadowing mechanism */
19857 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n")));
19859 + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
19860 + old_dentry->d_name.name,
19861 + yaffs_InodeToObject(new_dir),
19862 + new_dentry->d_name.name);
19864 + yaffs_GrossUnlock(dev);
19866 + if (retVal == YAFFS_OK) {
19868 + new_dentry->d_inode->i_nlink--;
19869 + mark_inode_dirty(new_dentry->d_inode);
19872 + update_dir_time(old_dir);
19873 + if(old_dir != new_dir)
19874 + update_dir_time(new_dir);
19877 + return -ENOTEMPTY;
19881 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
19883 + struct inode *inode = dentry->d_inode;
19885 + yaffs_Device *dev;
19887 + T(YAFFS_TRACE_OS,
19888 + (TSTR("yaffs_setattr of object %d\n"),
19889 + yaffs_InodeToObject(inode)->objectId));
19891 + /* Fail if a requested resize >= 2GB */
19892 + if (attr->ia_valid & ATTR_SIZE &&
19893 + (attr->ia_size >> 31))
19897 + error = inode_change_ok(inode, attr);
19898 + if (error == 0) {
19901 + error = yaffs_vfs_setattr(inode, attr);
19902 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
19903 + if (attr->ia_valid & ATTR_SIZE){
19904 + yaffs_vfs_setsize(inode,attr->ia_size);
19905 + inode->i_blocks = (inode->i_size + 511) >> 9;
19908 + dev = yaffs_InodeToObject(inode)->myDev;
19909 + if (attr->ia_valid & ATTR_SIZE){
19910 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
19911 + (int)(attr->ia_size),(int)(attr->ia_size)));
19913 + yaffs_GrossLock(dev);
19914 + result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
19915 + if(result == YAFFS_OK) {
19920 + yaffs_GrossUnlock(dev);
19924 + T(YAFFS_TRACE_OS,
19925 + (TSTR("yaffs_setattr done returning %d\n"),error));
19930 +#ifdef CONFIG_YAFFS_XATTR
19931 +int yaffs_setxattr(struct dentry *dentry, const char *name,
19932 + const void *value, size_t size, int flags)
19934 + struct inode *inode = dentry->d_inode;
19936 + yaffs_Device *dev;
19937 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19939 + T(YAFFS_TRACE_OS,
19940 + (TSTR("yaffs_setxattr of object %d\n"),
19944 + if (error == 0) {
19946 + dev = obj->myDev;
19947 + yaffs_GrossLock(dev);
19948 + result = yaffs_SetXAttribute(obj, name, value, size, flags);
19949 + if(result == YAFFS_OK)
19951 + else if(result < 0)
19953 + yaffs_GrossUnlock(dev);
19956 + T(YAFFS_TRACE_OS,
19957 + (TSTR("yaffs_setxattr done returning %d\n"),error));
19963 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
19966 + struct inode *inode = dentry->d_inode;
19968 + yaffs_Device *dev;
19969 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19971 + T(YAFFS_TRACE_OS,
19972 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
19973 + name, obj->objectId));
19975 + if (error == 0) {
19976 + dev = obj->myDev;
19977 + yaffs_GrossLock(dev);
19978 + error = yaffs_GetXAttribute(obj, name, buff, size);
19979 + yaffs_GrossUnlock(dev);
19982 + T(YAFFS_TRACE_OS,
19983 + (TSTR("yaffs_getxattr done returning %d\n"),error));
19988 +int yaffs_removexattr(struct dentry *dentry, const char *name)
19990 + struct inode *inode = dentry->d_inode;
19992 + yaffs_Device *dev;
19993 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19995 + T(YAFFS_TRACE_OS,
19996 + (TSTR("yaffs_removexattr of object %d\n"),
20000 + if (error == 0) {
20002 + dev = obj->myDev;
20003 + yaffs_GrossLock(dev);
20004 + result = yaffs_RemoveXAttribute(obj, name);
20005 + if(result == YAFFS_OK)
20007 + else if(result < 0)
20009 + yaffs_GrossUnlock(dev);
20012 + T(YAFFS_TRACE_OS,
20013 + (TSTR("yaffs_removexattr done returning %d\n"),error));
20018 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
20020 + struct inode *inode = dentry->d_inode;
20022 + yaffs_Device *dev;
20023 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20025 + T(YAFFS_TRACE_OS,
20026 + (TSTR("yaffs_listxattr of object %d\n"),
20030 + if (error == 0) {
20031 + dev = obj->myDev;
20032 + yaffs_GrossLock(dev);
20033 + error = yaffs_ListXAttributes(obj, buff, size);
20034 + yaffs_GrossUnlock(dev);
20037 + T(YAFFS_TRACE_OS,
20038 + (TSTR("yaffs_listxattr done returning %d\n"),error));
20046 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20047 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
20049 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
20050 + struct super_block *sb = dentry->d_sb;
20051 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20052 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
20054 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20056 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
20058 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20061 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
20063 + yaffs_GrossLock(dev);
20065 + buf->f_type = YAFFS_MAGIC;
20066 + buf->f_bsize = sb->s_blocksize;
20067 + buf->f_namelen = 255;
20069 + if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
20070 + /* Do this if chunk size is not a power of 2 */
20072 + uint64_t bytesInDev;
20073 + uint64_t bytesFree;
20075 + bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) *
20076 + ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk));
20078 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
20079 + buf->f_blocks = bytesInDev;
20081 + bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
20082 + ((uint64_t)(dev->nDataBytesPerChunk));
20084 + do_div(bytesFree, sb->s_blocksize);
20086 + buf->f_bfree = bytesFree;
20088 + } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
20091 + (dev->param.endBlock - dev->param.startBlock + 1) *
20092 + dev->param.nChunksPerBlock /
20093 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20095 + yaffs_GetNumberOfFreeChunks(dev) /
20096 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20099 + (dev->param.endBlock - dev->param.startBlock + 1) *
20100 + dev->param.nChunksPerBlock *
20101 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20104 + yaffs_GetNumberOfFreeChunks(dev) *
20105 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20108 + buf->f_files = 0;
20109 + buf->f_ffree = 0;
20110 + buf->f_bavail = buf->f_bfree;
20112 + yaffs_GrossUnlock(dev);
20118 +static void yaffs_FlushInodes(struct super_block *sb)
20120 + struct inode *iptr;
20121 + yaffs_Object *obj;
20123 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
20124 + obj = yaffs_InodeToObject(iptr);
20126 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
20128 + yaffs_FlushFile(obj,1,0);
20134 +static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
20136 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20140 + yaffs_FlushInodes(sb);
20141 + yaffs_UpdateDirtyDirectories(dev);
20142 + yaffs_FlushEntireDeviceCache(dev);
20143 + if(do_checkpoint)
20144 + yaffs_CheckpointSave(dev);
20148 +static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
20150 + unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
20151 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20152 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
20154 + if(erasedChunks < dev->nFreeChunks)
20155 + scatteredFree = (dev->nFreeChunks - erasedChunks);
20157 + if(!context->bgRunning)
20159 + else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
20161 + else if(erasedChunks > dev->nFreeChunks/2)
20163 + else if(erasedChunks > dev->nFreeChunks/4)
20169 +static int yaffs_do_sync_fs(struct super_block *sb,
20170 + int request_checkpoint)
20173 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20174 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
20175 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
20176 + int do_checkpoint;
20178 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20179 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
20181 + sb->s_dirt ? "dirty" : "clean",
20182 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
20183 + oneshot_checkpoint ? " one-shot" : "" ));
20185 + yaffs_GrossLock(dev);
20186 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
20187 + oneshot_checkpoint) &&
20188 + !dev->isCheckpointed;
20190 + if (sb->s_dirt || do_checkpoint) {
20191 + yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
20193 + if(oneshot_checkpoint)
20194 + yaffs_auto_checkpoint &= ~4;
20196 + yaffs_GrossUnlock(dev);
20202 + * yaffs background thread functions .
20203 + * yaffs_BackgroundThread() the thread function
20204 + * yaffs_BackgroundStart() launches the background thread.
20205 + * yaffs_BackgroundStop() cleans up the background thread.
20208 + * The thread should only run after the yaffs is initialised
20209 + * The thread should be stopped before yaffs is unmounted.
20210 + * The thread should not do any writing while the fs is in read only.
20213 +#ifdef YAFFS_COMPILE_BACKGROUND
20215 +void yaffs_background_waker(unsigned long data)
20217 + wake_up_process((struct task_struct *)data);
20220 +static int yaffs_BackgroundThread(void *data)
20222 + yaffs_Device *dev = (yaffs_Device *)data;
20223 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20224 + unsigned long now = jiffies;
20225 + unsigned long next_dir_update = now;
20226 + unsigned long next_gc = now;
20227 + unsigned long expires;
20228 + unsigned int urgency;
20231 + struct timer_list timer;
20233 + T(YAFFS_TRACE_BACKGROUND,
20234 + (TSTR("yaffs_background starting for dev %p\n"),
20237 +#ifdef YAFFS_COMPILE_FREEZER
20240 + while(context->bgRunning){
20241 + T(YAFFS_TRACE_BACKGROUND,
20242 + (TSTR("yaffs_background\n")));
20244 + if(kthread_should_stop())
20247 +#ifdef YAFFS_COMPILE_FREEZER
20248 + if(try_to_freeze())
20251 + yaffs_GrossLock(dev);
20255 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
20256 + yaffs_UpdateDirtyDirectories(dev);
20257 + next_dir_update = now + HZ;
20260 + if(time_after(now,next_gc) && yaffs_bg_enable){
20261 + if(!dev->isCheckpointed){
20262 + urgency = yaffs_bg_gc_urgency(dev);
20263 + gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
20265 + next_gc = now + HZ/20+1;
20266 + else if(urgency > 0)
20267 + next_gc = now + HZ/10+1;
20269 + next_gc = now + HZ * 2;
20271 + * gc not running so set to next_dir_update
20272 + * to cut down on wake ups
20274 + next_gc = next_dir_update;
20276 + yaffs_GrossUnlock(dev);
20278 + expires = next_dir_update;
20279 + if (time_before(next_gc,expires))
20280 + expires = next_gc;
20281 + if(time_before(expires,now))
20282 + expires = now + HZ;
20284 + Y_INIT_TIMER(&timer);
20285 + timer.expires = expires+1;
20286 + timer.data = (unsigned long) current;
20287 + timer.function = yaffs_background_waker;
20289 + set_current_state(TASK_INTERRUPTIBLE);
20290 + add_timer(&timer);
20292 + del_timer_sync(&timer);
20301 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20304 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20306 + if(dev->readOnly)
20309 + context->bgRunning = 1;
20311 + context->bgThread = kthread_run(yaffs_BackgroundThread,
20312 + (void *)dev,"yaffs-bg-%d",context->mount_id);
20314 + if(IS_ERR(context->bgThread)){
20315 + retval = PTR_ERR(context->bgThread);
20316 + context->bgThread = NULL;
20317 + context->bgRunning = 0;
20322 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20324 + struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
20326 + ctxt->bgRunning = 0;
20328 + if( ctxt->bgThread){
20329 + kthread_stop(ctxt->bgThread);
20330 + ctxt->bgThread = NULL;
20334 +static int yaffs_BackgroundThread(void *data)
20339 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20344 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20350 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20351 +static void yaffs_write_super(struct super_block *sb)
20353 +static int yaffs_write_super(struct super_block *sb)
20356 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
20358 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20359 + (TSTR("yaffs_write_super%s\n"),
20360 + request_checkpoint ? " checkpt" : ""));
20362 + yaffs_do_sync_fs(sb, request_checkpoint);
20364 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
20370 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20371 +static int yaffs_sync_fs(struct super_block *sb, int wait)
20373 +static int yaffs_sync_fs(struct super_block *sb)
20376 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
20378 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
20379 + (TSTR("yaffs_sync_fs%s\n"),
20380 + request_checkpoint ? " checkpt" : ""));
20382 + yaffs_do_sync_fs(sb, request_checkpoint);
20387 +#ifdef YAFFS_USE_OWN_IGET
20389 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
20391 + struct inode *inode;
20392 + yaffs_Object *obj;
20393 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20395 + T(YAFFS_TRACE_OS,
20396 + (TSTR("yaffs_iget for %lu\n"), ino));
20398 + inode = iget_locked(sb, ino);
20400 + return ERR_PTR(-ENOMEM);
20401 + if (!(inode->i_state & I_NEW))
20404 + /* NB This is called as a side effect of other functions, but
20405 + * we had to release the lock to prevent deadlocks, so
20406 + * need to lock again.
20409 + yaffs_GrossLock(dev);
20411 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20413 + yaffs_FillInodeFromObject(inode, obj);
20415 + yaffs_GrossUnlock(dev);
20417 + unlock_new_inode(inode);
20423 +static void yaffs_read_inode(struct inode *inode)
20425 + /* NB This is called as a side effect of other functions, but
20426 + * we had to release the lock to prevent deadlocks, so
20427 + * need to lock again.
20430 + yaffs_Object *obj;
20431 + yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
20433 + T(YAFFS_TRACE_OS,
20434 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
20436 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20437 + yaffs_GrossLock(dev);
20439 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20441 + yaffs_FillInodeFromObject(inode, obj);
20443 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20444 + yaffs_GrossUnlock(dev);
20449 +static YLIST_HEAD(yaffs_context_list);
20450 +struct semaphore yaffs_context_lock;
20452 +static void yaffs_put_super(struct super_block *sb)
20454 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20456 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
20458 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20459 + (TSTR("Shutting down yaffs background thread\n")));
20460 + yaffs_BackgroundStop(dev);
20461 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20462 + (TSTR("yaffs background thread shut down\n")));
20464 + yaffs_GrossLock(dev);
20466 + yaffs_FlushSuperBlock(sb,1);
20468 + if (yaffs_DeviceToLC(dev)->putSuperFunc)
20469 + yaffs_DeviceToLC(dev)->putSuperFunc(sb);
20472 + yaffs_Deinitialise(dev);
20474 + yaffs_GrossUnlock(dev);
20476 + down(&yaffs_context_lock);
20477 + ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
20478 + up(&yaffs_context_lock);
20480 + if (yaffs_DeviceToLC(dev)->spareBuffer) {
20481 + YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
20482 + yaffs_DeviceToLC(dev)->spareBuffer = NULL;
20489 +static void yaffs_MTDPutSuper(struct super_block *sb)
20491 + struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
20496 + put_mtd_device(mtd);
20500 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
20502 + struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
20504 + T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
20511 + int skip_checkpoint_read;
20512 + int skip_checkpoint_write;
20515 + int tags_ecc_overridden;
20516 + int lazy_loading_enabled;
20517 + int lazy_loading_overridden;
20518 + int empty_lost_and_found;
20519 + int empty_lost_and_found_overridden;
20522 +#define MAX_OPT_LEN 30
20523 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
20525 + char cur_opt[MAX_OPT_LEN + 1];
20529 + /* Parse through the options which is a comma seperated list */
20531 + while (options_str && *options_str && !error) {
20532 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
20535 + while(*options_str == ',')
20538 + while (*options_str && *options_str != ',') {
20539 + if (p < MAX_OPT_LEN) {
20540 + cur_opt[p] = *options_str;
20546 + if (!strcmp(cur_opt, "inband-tags"))
20547 + options->inband_tags = 1;
20548 + else if (!strcmp(cur_opt, "tags-ecc-off")){
20549 + options->tags_ecc_on = 0;
20550 + options->tags_ecc_overridden=1;
20551 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
20552 + options->tags_ecc_on = 1;
20553 + options->tags_ecc_overridden = 1;
20554 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
20555 + options->lazy_loading_enabled = 0;
20556 + options->lazy_loading_overridden=1;
20557 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
20558 + options->lazy_loading_enabled = 1;
20559 + options->lazy_loading_overridden = 1;
20560 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
20561 + options->empty_lost_and_found = 0;
20562 + options->empty_lost_and_found_overridden=1;
20563 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
20564 + options->empty_lost_and_found = 1;
20565 + options->empty_lost_and_found_overridden=1;
20566 + } else if (!strcmp(cur_opt, "no-cache"))
20567 + options->no_cache = 1;
20568 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
20569 + options->skip_checkpoint_read = 1;
20570 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
20571 + options->skip_checkpoint_write = 1;
20572 + else if (!strcmp(cur_opt, "no-checkpoint")) {
20573 + options->skip_checkpoint_read = 1;
20574 + options->skip_checkpoint_write = 1;
20576 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
20585 +static struct super_block *yaffs_internal_read_super(int yaffsVersion,
20586 + struct super_block *sb,
20587 + void *data, int silent)
20590 + struct inode *inode = NULL;
20591 + struct dentry *root;
20592 + yaffs_Device *dev = 0;
20593 + char devname_buf[BDEVNAME_SIZE + 1];
20594 + struct mtd_info *mtd;
20596 + char *data_str = (char *)data;
20597 + struct yaffs_LinuxContext *context = NULL;
20598 + yaffs_DeviceParam *param;
20600 + int readOnly = 0;
20602 + yaffs_options options;
20604 + unsigned mount_id;
20606 + struct yaffs_LinuxContext *context_iterator;
20607 + struct ylist_head *l;
20609 + sb->s_magic = YAFFS_MAGIC;
20610 + sb->s_op = &yaffs_super_ops;
20611 + sb->s_flags |= MS_NOATIME;
20613 + readOnly =((sb->s_flags & MS_RDONLY) != 0);
20616 +#ifdef YAFFS_COMPILE_EXPORTFS
20617 + sb->s_export_op = &yaffs_export_ops;
20621 + printk(KERN_INFO "yaffs: sb is NULL\n");
20622 + else if (!sb->s_dev)
20623 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
20624 + else if (!yaffs_devname(sb, devname_buf))
20625 + printk(KERN_INFO "yaffs: devname is NULL\n");
20627 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
20629 + yaffs_devname(sb, devname_buf),
20630 + readOnly ? "ro" : "rw");
20635 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
20637 + memset(&options, 0, sizeof(options));
20639 + if (yaffs_parse_options(&options, data_str)) {
20640 + /* Option parsing failed */
20645 + sb->s_blocksize = PAGE_CACHE_SIZE;
20646 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
20648 + T(YAFFS_TRACE_OS,
20649 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
20650 + T(YAFFS_TRACE_OS,
20651 + (TSTR("yaffs_read_super: block size %d\n"),
20652 + (int)(sb->s_blocksize)));
20654 + T(YAFFS_TRACE_ALWAYS,
20655 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
20656 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
20657 + yaffs_devname(sb, devname_buf)));
20659 + /* Check it's an mtd device..... */
20660 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
20661 + return NULL; /* This isn't an mtd device */
20663 + /* Get the device */
20664 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
20666 + T(YAFFS_TRACE_ALWAYS,
20667 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
20668 + MINOR(sb->s_dev)));
20671 + /* Check it's NAND */
20672 + if (mtd->type != MTD_NANDFLASH) {
20673 + T(YAFFS_TRACE_ALWAYS,
20674 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
20679 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
20680 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
20681 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
20682 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
20683 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
20684 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
20685 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
20686 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
20687 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
20688 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
20689 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
20690 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
20692 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
20695 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
20697 + if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
20698 + T(YAFFS_TRACE_ALWAYS,
20699 + (TSTR("yaffs: auto selecting yaffs2\n")));
20700 + yaffsVersion = 2;
20703 + /* Added NCB 26/5/2006 for completeness */
20704 + if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
20705 + T(YAFFS_TRACE_ALWAYS,
20706 + (TSTR("yaffs: auto selecting yaffs1\n")));
20707 + yaffsVersion = 1;
20712 + if (yaffsVersion == 2) {
20713 + /* Check for version 2 style functions */
20714 + if (!mtd->erase ||
20715 + !mtd->block_isbad ||
20716 + !mtd->block_markbad ||
20719 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20720 + !mtd->read_oob || !mtd->write_oob) {
20722 + !mtd->write_ecc ||
20723 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20725 + T(YAFFS_TRACE_ALWAYS,
20726 + (TSTR("yaffs: MTD device does not support required "
20727 + "functions\n")));
20731 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
20732 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
20733 + !options.inband_tags) {
20734 + T(YAFFS_TRACE_ALWAYS,
20735 + (TSTR("yaffs: MTD device does not have the "
20736 + "right page sizes\n")));
20740 + /* Check for V1 style functions */
20741 + if (!mtd->erase ||
20744 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20745 + !mtd->read_oob || !mtd->write_oob) {
20747 + !mtd->write_ecc ||
20748 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20750 + T(YAFFS_TRACE_ALWAYS,
20751 + (TSTR("yaffs: MTD device does not support required "
20752 + "functions\n")));
20756 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
20757 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
20758 + T(YAFFS_TRACE_ALWAYS,
20759 + (TSTR("yaffs: MTD device does not support have the "
20760 + "right page sizes\n")));
20765 + /* OK, so if we got here, we have an MTD that's NAND and looks
20766 + * like it has the right capabilities
20767 + * Set the yaffs_Device up for mtd
20770 + if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
20772 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
20773 + sb->s_flags |= MS_RDONLY;
20776 + dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
20777 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
20779 + if(!dev || !context ){
20789 + /* Deep shit could not allocate device structure */
20790 + T(YAFFS_TRACE_ALWAYS,
20791 + (TSTR("yaffs_read_super: Failed trying to allocate "
20792 + "yaffs_Device. \n")));
20795 + memset(dev, 0, sizeof(yaffs_Device));
20796 + param = &(dev->param);
20798 + memset(context,0,sizeof(struct yaffs_LinuxContext));
20799 + dev->osContext = context;
20800 + YINIT_LIST_HEAD(&(context->contextList));
20801 + context->dev = dev;
20802 + context->superBlock = sb;
20804 + dev->readOnly = readOnly;
20806 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20807 + sb->s_fs_info = dev;
20809 + sb->u.generic_sbp = dev;
20812 + dev->driverContext = mtd;
20813 + param->name = mtd->name;
20815 + /* Set up the memory size parameters.... */
20817 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
20819 + param->startBlock = 0;
20820 + param->endBlock = nBlocks - 1;
20821 + param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
20822 + param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
20823 + param->nReservedBlocks = 5;
20824 + param->nShortOpCaches = (options.no_cache) ? 0 : 10;
20825 + param->inbandTags = options.inband_tags;
20827 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
20828 + param->disableLazyLoad = 1;
20830 +#ifdef CONFIG_YAFFS_XATTR
20831 + param->enableXattr = 1;
20833 + if(options.lazy_loading_overridden)
20834 + param->disableLazyLoad = !options.lazy_loading_enabled;
20836 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
20837 + param->noTagsECC = 1;
20840 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
20842 + param->deferDirectoryUpdate = 1;
20845 + if(options.tags_ecc_overridden)
20846 + param->noTagsECC = !options.tags_ecc_on;
20848 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
20849 + param->emptyLostAndFound = 1;
20852 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
20853 + param->refreshPeriod = 0;
20855 + param->refreshPeriod = 500;
20858 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
20859 + param->alwaysCheckErased = 1;
20862 + if(options.empty_lost_and_found_overridden)
20863 + param->emptyLostAndFound = options.empty_lost_and_found;
20865 + /* ... and the functions. */
20866 + if (yaffsVersion == 2) {
20867 + param->writeChunkWithTagsToNAND =
20868 + nandmtd2_WriteChunkWithTagsToNAND;
20869 + param->readChunkWithTagsFromNAND =
20870 + nandmtd2_ReadChunkWithTagsFromNAND;
20871 + param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
20872 + param->queryNANDBlock = nandmtd2_QueryNANDBlock;
20873 + yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
20874 + param->isYaffs2 = 1;
20875 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20876 + param->totalBytesPerChunk = mtd->writesize;
20877 + param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
20879 + param->totalBytesPerChunk = mtd->oobblock;
20880 + param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
20882 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
20884 + param->startBlock = 0;
20885 + param->endBlock = nBlocks - 1;
20887 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20888 + /* use the MTD interface in yaffs_mtdif1.c */
20889 + param->writeChunkWithTagsToNAND =
20890 + nandmtd1_WriteChunkWithTagsToNAND;
20891 + param->readChunkWithTagsFromNAND =
20892 + nandmtd1_ReadChunkWithTagsFromNAND;
20893 + param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
20894 + param->queryNANDBlock = nandmtd1_QueryNANDBlock;
20896 + param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
20897 + param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
20899 + param->isYaffs2 = 0;
20901 + /* ... and common functions */
20902 + param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
20903 + param->initialiseNAND = nandmtd_InitialiseNAND;
20905 + yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
20907 + param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
20908 + param->gcControl = yaffs_gc_control_callback;
20910 + yaffs_DeviceToLC(dev)->superBlock= sb;
20913 +#ifndef CONFIG_YAFFS_DOES_ECC
20914 + param->useNANDECC = 1;
20917 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
20918 + param->wideTnodesDisabled = 1;
20921 + param->skipCheckpointRead = options.skip_checkpoint_read;
20922 + param->skipCheckpointWrite = options.skip_checkpoint_write;
20924 + down(&yaffs_context_lock);
20925 + /* Get a mount id */
20927 + for(mount_id=0; ! found; mount_id++){
20929 + ylist_for_each(l,&yaffs_context_list){
20930 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
20931 + if(context_iterator->mount_id == mount_id)
20935 + context->mount_id = mount_id;
20937 + ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
20938 + up(&yaffs_context_lock);
20940 + /* Directory search handling...*/
20941 + YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
20942 + param->removeObjectCallback = yaffs_RemoveObjectCallback;
20944 + init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
20946 + yaffs_GrossLock(dev);
20948 + err = yaffs_GutsInitialise(dev);
20950 + T(YAFFS_TRACE_OS,
20951 + (TSTR("yaffs_read_super: guts initialised %s\n"),
20952 + (err == YAFFS_OK) ? "OK" : "FAILED"));
20954 + if(err == YAFFS_OK)
20955 + yaffs_BackgroundStart(dev);
20957 + if(!context->bgThread)
20958 + param->deferDirectoryUpdate = 0;
20961 + /* Release lock before yaffs_get_inode() */
20962 + yaffs_GrossUnlock(dev);
20964 + /* Create root inode */
20965 + if (err == YAFFS_OK)
20966 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
20967 + yaffs_Root(dev));
20972 + inode->i_op = &yaffs_dir_inode_operations;
20973 + inode->i_fop = &yaffs_dir_operations;
20975 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
20977 + root = d_alloc_root(inode);
20979 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
20985 + sb->s_root = root;
20986 + sb->s_dirt = !dev->isCheckpointed;
20987 + T(YAFFS_TRACE_ALWAYS,
20988 + (TSTR("yaffs_read_super: isCheckpointed %d\n"),
20989 + dev->isCheckpointed));
20991 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
20996 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20997 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
21000 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
21003 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21004 +static int yaffs_read_super(struct file_system_type *fs,
21005 + int flags, const char *dev_name,
21006 + void *data, struct vfsmount *mnt)
21009 + return get_sb_bdev(fs, flags, dev_name, data,
21010 + yaffs_internal_read_super_mtd, mnt);
21013 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
21014 + int flags, const char *dev_name,
21018 + return get_sb_bdev(fs, flags, dev_name, data,
21019 + yaffs_internal_read_super_mtd);
21023 +static struct file_system_type yaffs_fs_type = {
21024 + .owner = THIS_MODULE,
21026 + .get_sb = yaffs_read_super,
21027 + .kill_sb = kill_block_super,
21028 + .fs_flags = FS_REQUIRES_DEV,
21031 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
21034 + return yaffs_internal_read_super(1, sb, data, silent);
21037 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
21038 + FS_REQUIRES_DEV);
21042 +#ifdef CONFIG_YAFFS_YAFFS2
21044 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21045 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
21048 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
21051 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21052 +static int yaffs2_read_super(struct file_system_type *fs,
21053 + int flags, const char *dev_name, void *data,
21054 + struct vfsmount *mnt)
21056 + return get_sb_bdev(fs, flags, dev_name, data,
21057 + yaffs2_internal_read_super_mtd, mnt);
21060 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
21061 + int flags, const char *dev_name,
21065 + return get_sb_bdev(fs, flags, dev_name, data,
21066 + yaffs2_internal_read_super_mtd);
21070 +static struct file_system_type yaffs2_fs_type = {
21071 + .owner = THIS_MODULE,
21072 + .name = "yaffs2",
21073 + .get_sb = yaffs2_read_super,
21074 + .kill_sb = kill_block_super,
21075 + .fs_flags = FS_REQUIRES_DEV,
21078 +static struct super_block *yaffs2_read_super(struct super_block *sb,
21079 + void *data, int silent)
21081 + return yaffs_internal_read_super(2, sb, data, silent);
21084 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
21085 + FS_REQUIRES_DEV);
21088 +#endif /* CONFIG_YAFFS_YAFFS2 */
21090 +static struct proc_dir_entry *my_proc_entry;
21091 +static struct proc_dir_entry *debug_proc_entry;
21093 +static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
21095 + buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
21096 + buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
21097 + buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
21098 + buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
21099 + buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
21100 + buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
21101 + buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
21102 + buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
21103 + buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
21104 + buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
21105 + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
21106 + buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks);
21107 + buf += sprintf(buf, "alwaysCheckErased.. %d\n", dev->param.alwaysCheckErased);
21109 + buf += sprintf(buf, "\n");
21115 +static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
21117 + buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
21118 + buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
21119 + buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
21120 + buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
21121 + buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
21122 + buf += sprintf(buf, "\n");
21123 + buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
21124 + buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
21125 + buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
21126 + buf += sprintf(buf, "\n");
21127 + buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
21128 + buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
21129 + buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
21130 + buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
21131 + buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
21132 + buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
21133 + buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
21134 + buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks);
21135 + buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
21136 + buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
21137 + buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
21138 + buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
21139 + buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed);
21140 + buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed);
21141 + buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed);
21142 + buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits);
21143 + buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles);
21144 + buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles);
21145 + buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount);
21147 + sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions);
21152 +static int yaffs_proc_read(char *page,
21154 + off_t offset, int count, int *eof, void *data)
21156 + struct ylist_head *item;
21157 + char *buf = page;
21158 + int step = offset;
21161 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
21162 + * We use 'offset' (*ppos) to indicate where we are in devList.
21163 + * This also assumes the user has posted a read buffer large
21164 + * enough to hold the complete output; but that's life in /proc.
21167 + *(int *)start = 1;
21169 + /* Print header first */
21171 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
21172 + else if (step == 1)
21173 + buf += sprintf(buf,"\n");
21177 + down(&yaffs_context_lock);
21179 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21180 + ylist_for_each(item, &yaffs_context_list) {
21181 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21182 + yaffs_Device *dev = dc->dev;
21184 + if (n < (step & ~1)) {
21188 + if((step & 1)==0){
21189 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
21190 + buf = yaffs_dump_dev_part0(buf, dev);
21192 + buf = yaffs_dump_dev_part1(buf, dev);
21196 + up(&yaffs_context_lock);
21199 + return buf - page < count ? buf - page : count;
21202 +static int yaffs_stats_proc_read(char *page,
21204 + off_t offset, int count, int *eof, void *data)
21206 + struct ylist_head *item;
21207 + char *buf = page;
21210 + down(&yaffs_context_lock);
21212 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21213 + ylist_for_each(item, &yaffs_context_list) {
21214 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21215 + yaffs_Device *dev = dc->dev;
21217 + int erasedChunks;
21219 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
21221 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
21222 + n, dev->nFreeChunks, erasedChunks,
21223 + dev->backgroundGCs, dev->oldestDirtyGCs,
21224 + dev->nObjects, dev->nTnodes);
21226 + up(&yaffs_context_lock);
21229 + return buf - page < count ? buf - page : count;
21233 + * Set the verbosity of the warnings and error messages.
21235 + * Note that the names can only be a..z or _ with the current code.
21240 + unsigned mask_bitfield;
21241 +} mask_flags[] = {
21242 + {"allocate", YAFFS_TRACE_ALLOCATE},
21243 + {"always", YAFFS_TRACE_ALWAYS},
21244 + {"background", YAFFS_TRACE_BACKGROUND},
21245 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
21246 + {"buffers", YAFFS_TRACE_BUFFERS},
21247 + {"bug", YAFFS_TRACE_BUG},
21248 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
21249 + {"deletion", YAFFS_TRACE_DELETION},
21250 + {"erase", YAFFS_TRACE_ERASE},
21251 + {"error", YAFFS_TRACE_ERROR},
21252 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
21253 + {"gc", YAFFS_TRACE_GC},
21254 + {"lock", YAFFS_TRACE_LOCK},
21255 + {"mtd", YAFFS_TRACE_MTD},
21256 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
21257 + {"os", YAFFS_TRACE_OS},
21258 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
21259 + {"scan", YAFFS_TRACE_SCAN},
21260 + {"tracing", YAFFS_TRACE_TRACING},
21261 + {"sync", YAFFS_TRACE_SYNC},
21262 + {"write", YAFFS_TRACE_WRITE},
21264 + {"verify", YAFFS_TRACE_VERIFY},
21265 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
21266 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
21267 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
21269 + {"all", 0xffffffff},
21274 +#define MAX_MASK_NAME_LENGTH 40
21275 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
21276 + unsigned long count, void *data)
21278 + unsigned rg = 0, mask_bitfield;
21282 + char substring[MAX_MASK_NAME_LENGTH + 1];
21285 + int add, len = 0;
21288 + rg = yaffs_traceMask;
21290 + while (!done && (pos < count)) {
21292 + while ((pos < count) && isspace(buf[pos]))
21295 + switch (buf[pos]) {
21307 + mask_name = NULL;
21309 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
21311 + if (end > buf + pos) {
21312 + mask_name = "numeral";
21313 + len = end - (buf + pos);
21317 + for (x = buf + pos, i = 0;
21318 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
21319 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
21320 + substring[i] = *x;
21321 + substring[i] = '\0';
21323 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21324 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
21325 + mask_name = mask_flags[i].mask_name;
21326 + mask_bitfield = mask_flags[i].mask_bitfield;
21333 + if (mask_name != NULL) {
21337 + rg &= ~mask_bitfield;
21340 + rg |= mask_bitfield;
21343 + rg = mask_bitfield;
21346 + rg |= mask_bitfield;
21352 + yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
21354 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
21356 + if (rg & YAFFS_TRACE_ALWAYS) {
21357 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21359 + flag = ((rg & mask_flags[i].mask_bitfield) ==
21360 + mask_flags[i].mask_bitfield) ? '+' : '-';
21361 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
21369 +static int yaffs_proc_write(struct file *file, const char *buf,
21370 + unsigned long count, void *data)
21372 + return yaffs_proc_write_trace_options(file, buf, count, data);
21375 +/* Stuff to handle installation of file systems */
21376 +struct file_system_to_install {
21377 + struct file_system_type *fst;
21381 +static struct file_system_to_install fs_to_install[] = {
21382 + {&yaffs_fs_type, 0},
21383 + {&yaffs2_fs_type, 0},
21387 +static int __init init_yaffs_fs(void)
21390 + struct file_system_to_install *fsinst;
21392 + T(YAFFS_TRACE_ALWAYS,
21393 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
21395 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
21396 + T(YAFFS_TRACE_ALWAYS,
21397 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
21403 + init_MUTEX(&yaffs_context_lock);
21405 + /* Install the proc_fs entries */
21406 + my_proc_entry = create_proc_entry("yaffs",
21407 + S_IRUGO | S_IFREG,
21410 + if (my_proc_entry) {
21411 + my_proc_entry->write_proc = yaffs_proc_write;
21412 + my_proc_entry->read_proc = yaffs_proc_read;
21413 + my_proc_entry->data = NULL;
21417 + debug_proc_entry = create_proc_entry("yaffs_stats",
21418 + S_IRUGO | S_IFREG,
21421 + if (debug_proc_entry) {
21422 + debug_proc_entry->write_proc = NULL;
21423 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
21424 + debug_proc_entry->data = NULL;
21428 + /* Now add the file system entries */
21430 + fsinst = fs_to_install;
21432 + while (fsinst->fst && !error) {
21433 + error = register_filesystem(fsinst->fst);
21435 + fsinst->installed = 1;
21439 + /* Any errors? uninstall */
21441 + fsinst = fs_to_install;
21443 + while (fsinst->fst) {
21444 + if (fsinst->installed) {
21445 + unregister_filesystem(fsinst->fst);
21446 + fsinst->installed = 0;
21455 +static void __exit exit_yaffs_fs(void)
21458 + struct file_system_to_install *fsinst;
21460 + T(YAFFS_TRACE_ALWAYS,
21461 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
21463 + remove_proc_entry("yaffs", YPROC_ROOT);
21464 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
21466 + fsinst = fs_to_install;
21468 + while (fsinst->fst) {
21469 + if (fsinst->installed) {
21470 + unregister_filesystem(fsinst->fst);
21471 + fsinst->installed = 0;
21477 +module_init(init_yaffs_fs)
21478 +module_exit(exit_yaffs_fs)
21480 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
21481 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
21482 +MODULE_LICENSE("GPL");
21484 +++ b/fs/yaffs2/yaffs_yaffs1.c
21487 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21489 + * Copyright (C) 2002-2010 Aleph One Ltd.
21490 + * for Toby Churchill Ltd and Brightstar Engineering
21492 + * Created by Charles Manning <charles@aleph1.co.uk>
21494 + * This program is free software; you can redistribute it and/or modify
21495 + * it under the terms of the GNU General Public License version 2 as
21496 + * published by the Free Software Foundation.
21498 +#include "yaffs_yaffs1.h"
21499 +#include "yportenv.h"
21500 +#include "yaffs_trace.h"
21501 +#include "yaffs_bitmap.h"
21502 +#include "yaffs_getblockinfo.h"
21503 +#include "yaffs_nand.h"
21506 +int yaffs1_Scan(yaffs_Device *dev)
21508 + yaffs_ExtendedTags tags;
21510 + int blockIterator;
21511 + int startIterator;
21518 + yaffs_BlockState state;
21519 + yaffs_Object *hardList = NULL;
21520 + yaffs_BlockInfo *bi;
21521 + __u32 sequenceNumber;
21522 + yaffs_ObjectHeader *oh;
21523 + yaffs_Object *in;
21524 + yaffs_Object *parent;
21526 + int alloc_failed = 0;
21528 + struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
21535 + T(YAFFS_TRACE_SCAN,
21536 + (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
21537 + dev->internalStartBlock, dev->internalEndBlock));
21539 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
21541 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
21543 + /* Scan all the blocks to determine their state */
21544 + bi = dev->blockInfo;
21545 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
21546 + yaffs_ClearChunkBits(dev, blk);
21547 + bi->pagesInUse = 0;
21548 + bi->softDeletions = 0;
21550 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
21552 + bi->blockState = state;
21553 + bi->sequenceNumber = sequenceNumber;
21555 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
21556 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
21558 + T(YAFFS_TRACE_SCAN_DEBUG,
21559 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
21560 + state, sequenceNumber));
21562 + if (state == YAFFS_BLOCK_STATE_DEAD) {
21563 + T(YAFFS_TRACE_BAD_BLOCKS,
21564 + (TSTR("block %d is bad" TENDSTR), blk));
21565 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
21566 + T(YAFFS_TRACE_SCAN_DEBUG,
21567 + (TSTR("Block empty " TENDSTR)));
21568 + dev->nErasedBlocks++;
21569 + dev->nFreeChunks += dev->param.nChunksPerBlock;
21574 + startIterator = dev->internalStartBlock;
21575 + endIterator = dev->internalEndBlock;
21577 + /* For each block.... */
21578 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
21579 + blockIterator++) {
21585 + blk = blockIterator;
21587 + bi = yaffs_GetBlockInfo(dev, blk);
21588 + state = bi->blockState;
21592 + /* For each chunk in each block that needs scanning....*/
21593 + for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&
21594 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
21595 + /* Read the tags and decide what to do */
21596 + chunk = blk * dev->param.nChunksPerBlock + c;
21598 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
21601 + /* Let's have a good look at this chunk... */
21603 + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
21604 + /* YAFFS1 only...
21605 + * A deleted chunk
21608 + dev->nFreeChunks++;
21609 + /*T((" %d %d deleted\n",blk,c)); */
21610 + } else if (!tags.chunkUsed) {
21611 + /* An unassigned chunk in the block
21612 + * This means that either the block is empty or
21613 + * this is the one being allocated from
21617 + /* We're looking at the first chunk in the block so the block is unused */
21618 + state = YAFFS_BLOCK_STATE_EMPTY;
21619 + dev->nErasedBlocks++;
21621 + /* this is the block being allocated from */
21622 + T(YAFFS_TRACE_SCAN,
21624 + (" Allocating from %d %d" TENDSTR),
21626 + state = YAFFS_BLOCK_STATE_ALLOCATING;
21627 + dev->allocationBlock = blk;
21628 + dev->allocationPage = c;
21629 + dev->allocationBlockFinder = blk;
21630 + /* Set block finder here to encourage the allocator to go forth from here. */
21634 + dev->nFreeChunks += (dev->param.nChunksPerBlock - c);
21635 + } else if (tags.chunkId > 0) {
21636 + /* chunkId > 0 so it is a data chunk... */
21637 + unsigned int endpos;
21639 + yaffs_SetChunkBit(dev, blk, c);
21640 + bi->pagesInUse++;
21642 + in = yaffs_FindOrCreateObjectByNumber(dev,
21645 + YAFFS_OBJECT_TYPE_FILE);
21646 + /* PutChunkIntoFile checks for a clash (two data chunks with
21647 + * the same chunkId).
21651 + alloc_failed = 1;
21654 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
21655 + alloc_failed = 1;
21659 + (tags.chunkId - 1) * dev->nDataBytesPerChunk +
21662 + in->variantType == YAFFS_OBJECT_TYPE_FILE
21663 + && in->variant.fileVariant.scannedFileSize <
21665 + in->variant.fileVariant.
21666 + scannedFileSize = endpos;
21667 + if (!dev->param.useHeaderFileSize) {
21668 + in->variant.fileVariant.
21670 + in->variant.fileVariant.
21675 + /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
21677 + /* chunkId == 0, so it is an ObjectHeader.
21678 + * Thus, we read in the object header and make the object
21680 + yaffs_SetChunkBit(dev, blk, c);
21681 + bi->pagesInUse++;
21683 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
21687 + oh = (yaffs_ObjectHeader *) chunkData;
21689 + in = yaffs_FindObjectByNumber(dev,
21691 + if (in && in->variantType != oh->type) {
21692 + /* This should not happen, but somehow
21693 + * Wev'e ended up with an objectId that has been reused but not yet
21694 + * deleted, and worse still it has changed type. Delete the old object.
21697 + yaffs_DeleteObject(in);
21702 + in = yaffs_FindOrCreateObjectByNumber(dev,
21708 + alloc_failed = 1;
21710 + if (in && oh->shadowsObject > 0) {
21712 + struct yaffs_ShadowFixerStruct *fixer;
21713 + fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
21715 + fixer->next = shadowFixerList;
21716 + shadowFixerList = fixer;
21717 + fixer->objectId = tags.objectId;
21718 + fixer->shadowedId = oh->shadowsObject;
21719 + T(YAFFS_TRACE_SCAN,
21721 + (" Shadow fixer: %d shadows %d" TENDSTR),
21722 + fixer->objectId, fixer->shadowedId));
21728 + if (in && in->valid) {
21729 + /* We have already filled this one. We have a duplicate and need to resolve it. */
21731 + unsigned existingSerial = in->serial;
21732 + unsigned newSerial = tags.serialNumber;
21734 + if (((existingSerial + 1) & 3) == newSerial) {
21735 + /* Use new one - destroy the exisiting one */
21736 + yaffs_DeleteChunk(dev,
21741 + /* Use existing - destroy this one. */
21742 + yaffs_DeleteChunk(dev, chunk, 1,
21747 + if (in && !in->valid &&
21748 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
21749 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
21750 + /* We only load some info, don't fiddle with directory structure */
21752 + in->variantType = oh->type;
21754 + in->yst_mode = oh->yst_mode;
21755 +#ifdef CONFIG_YAFFS_WINCE
21756 + in->win_atime[0] = oh->win_atime[0];
21757 + in->win_ctime[0] = oh->win_ctime[0];
21758 + in->win_mtime[0] = oh->win_mtime[0];
21759 + in->win_atime[1] = oh->win_atime[1];
21760 + in->win_ctime[1] = oh->win_ctime[1];
21761 + in->win_mtime[1] = oh->win_mtime[1];
21763 + in->yst_uid = oh->yst_uid;
21764 + in->yst_gid = oh->yst_gid;
21765 + in->yst_atime = oh->yst_atime;
21766 + in->yst_mtime = oh->yst_mtime;
21767 + in->yst_ctime = oh->yst_ctime;
21768 + in->yst_rdev = oh->yst_rdev;
21770 + in->hdrChunk = chunk;
21771 + in->serial = tags.serialNumber;
21773 + } else if (in && !in->valid) {
21774 + /* we need to load this info */
21777 + in->variantType = oh->type;
21779 + in->yst_mode = oh->yst_mode;
21780 +#ifdef CONFIG_YAFFS_WINCE
21781 + in->win_atime[0] = oh->win_atime[0];
21782 + in->win_ctime[0] = oh->win_ctime[0];
21783 + in->win_mtime[0] = oh->win_mtime[0];
21784 + in->win_atime[1] = oh->win_atime[1];
21785 + in->win_ctime[1] = oh->win_ctime[1];
21786 + in->win_mtime[1] = oh->win_mtime[1];
21788 + in->yst_uid = oh->yst_uid;
21789 + in->yst_gid = oh->yst_gid;
21790 + in->yst_atime = oh->yst_atime;
21791 + in->yst_mtime = oh->yst_mtime;
21792 + in->yst_ctime = oh->yst_ctime;
21793 + in->yst_rdev = oh->yst_rdev;
21795 + in->hdrChunk = chunk;
21796 + in->serial = tags.serialNumber;
21798 + yaffs_SetObjectNameFromOH(in, oh);
21801 + /* directory stuff...
21802 + * hook up to parent
21806 + yaffs_FindOrCreateObjectByNumber
21807 + (dev, oh->parentObjectId,
21808 + YAFFS_OBJECT_TYPE_DIRECTORY);
21810 + alloc_failed = 1;
21811 + if (parent && parent->variantType ==
21812 + YAFFS_OBJECT_TYPE_UNKNOWN) {
21813 + /* Set up as a directory */
21814 + parent->variantType =
21815 + YAFFS_OBJECT_TYPE_DIRECTORY;
21816 + YINIT_LIST_HEAD(&parent->variant.
21817 + directoryVariant.
21819 + } else if (!parent || parent->variantType !=
21820 + YAFFS_OBJECT_TYPE_DIRECTORY) {
21821 + /* Hoosterman, another problem....
21822 + * We're trying to use a non-directory as a directory
21825 + T(YAFFS_TRACE_ERROR,
21827 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
21829 + parent = dev->lostNFoundDir;
21832 + yaffs_AddObjectToDirectory(parent, in);
21834 + if (0 && (parent == dev->deletedDir ||
21835 + parent == dev->unlinkedDir)) {
21836 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
21837 + dev->nDeletedFiles++;
21839 + /* Note re hardlinks.
21840 + * Since we might scan a hardlink before its equivalent object is scanned
21841 + * we put them all in a list.
21842 + * After scanning is complete, we should have all the objects, so we run through this
21843 + * list and fix up all the chains.
21846 + switch (in->variantType) {
21847 + case YAFFS_OBJECT_TYPE_UNKNOWN:
21848 + /* Todo got a problem */
21850 + case YAFFS_OBJECT_TYPE_FILE:
21851 + if (dev->param.useHeaderFileSize)
21853 + in->variant.fileVariant.
21858 + case YAFFS_OBJECT_TYPE_HARDLINK:
21859 + in->variant.hardLinkVariant.
21860 + equivalentObjectId =
21861 + oh->equivalentObjectId;
21862 + in->hardLinks.next =
21863 + (struct ylist_head *)
21867 + case YAFFS_OBJECT_TYPE_DIRECTORY:
21870 + case YAFFS_OBJECT_TYPE_SPECIAL:
21873 + case YAFFS_OBJECT_TYPE_SYMLINK:
21874 + in->variant.symLinkVariant.alias =
21875 + yaffs_CloneString(oh->alias);
21876 + if (!in->variant.symLinkVariant.alias)
21877 + alloc_failed = 1;
21885 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
21886 + /* If we got this far while scanning, then the block is fully allocated.*/
21887 + state = YAFFS_BLOCK_STATE_FULL;
21890 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
21891 + /* If the block was partially allocated then treat it as fully allocated.*/
21892 + state = YAFFS_BLOCK_STATE_FULL;
21893 + dev->allocationBlock = -1;
21896 + bi->blockState = state;
21898 + /* Now let's see if it was dirty */
21899 + if (bi->pagesInUse == 0 &&
21900 + !bi->hasShrinkHeader &&
21901 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
21902 + yaffs_BlockBecameDirty(dev, blk);
21908 + /* Ok, we've done all the scanning.
21909 + * Fix up the hard link chains.
21910 + * We should now have scanned all the objects, now it's time to add these
21914 + yaffs_HardlinkFixup(dev, hardList);
21916 + /* Fix up any shadowed objects */
21918 + struct yaffs_ShadowFixerStruct *fixer;
21919 + yaffs_Object *obj;
21921 + while (shadowFixerList) {
21922 + fixer = shadowFixerList;
21923 + shadowFixerList = fixer->next;
21924 + /* Complete the rename transaction by deleting the shadowed object
21925 + * then setting the object header to unshadowed.
21927 + obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
21929 + yaffs_DeleteObject(obj);
21931 + obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
21934 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
21940 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
21942 + if (alloc_failed)
21943 + return YAFFS_FAIL;
21945 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
21952 +++ b/fs/yaffs2/yaffs_yaffs1.h
21955 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
21957 + * Copyright (C) 2002-2010 Aleph One Ltd.
21958 + * for Toby Churchill Ltd and Brightstar Engineering
21960 + * Created by Charles Manning <charles@aleph1.co.uk>
21962 + * This program is free software; you can redistribute it and/or modify
21963 + * it under the terms of the GNU Lesser General Public License version 2.1 as
21964 + * published by the Free Software Foundation.
21966 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
21969 +#ifndef __YAFFS_YAFFS1_H__
21970 +#define __YAFFS_YAFFS1_H__
21972 +#include "yaffs_guts.h"
21973 +int yaffs1_Scan(yaffs_Device *dev);
21977 +++ b/fs/yaffs2/yaffs_yaffs2.c
21980 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21982 + * Copyright (C) 2002-2010 Aleph One Ltd.
21983 + * for Toby Churchill Ltd and Brightstar Engineering
21985 + * Created by Charles Manning <charles@aleph1.co.uk>
21987 + * This program is free software; you can redistribute it and/or modify
21988 + * it under the terms of the GNU General Public License version 2 as
21989 + * published by the Free Software Foundation.
21993 +#include "yaffs_guts.h"
21994 +#include "yaffs_trace.h"
21995 +#include "yaffs_yaffs2.h"
21996 +#include "yaffs_checkptrw.h"
21997 +#include "yaffs_bitmap.h"
21998 +#include "yaffs_qsort.h"
21999 +#include "yaffs_nand.h"
22000 +#include "yaffs_getblockinfo.h"
22001 +#include "yaffs_verify.h"
22004 + * Checkpoints are really no benefit on very small partitions.
22006 + * To save space on small partitions don't bother with checkpoints unless
22007 + * the partition is at least this big.
22009 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
22011 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
22015 + * Oldest Dirty Sequence Number handling.
22018 +/* yaffs2_CalcOldestDirtySequence()
22019 + * yaffs2_FindOldestDirtySequence()
22020 + * Calculate the oldest dirty sequence number if we don't know it.
22022 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
22026 + unsigned blockNo = 0;
22027 + yaffs_BlockInfo *b;
22029 + if(!dev->param.isYaffs2)
22032 + /* Find the oldest dirty sequence number. */
22033 + seq = dev->sequenceNumber + 1;
22034 + b = dev->blockInfo;
22035 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
22036 + if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
22037 + (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock &&
22038 + b->sequenceNumber < seq) {
22039 + seq = b->sequenceNumber;
22046 + dev->oldestDirtySequence = seq;
22047 + dev->oldestDirtyBlock = blockNo;
22053 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
22055 + if(!dev->param.isYaffs2)
22058 + if(!dev->oldestDirtySequence)
22059 + yaffs2_CalcOldestDirtySequence(dev);
22063 + * yaffs_ClearOldestDirtySequence()
22064 + * Called when a block is erased or marked bad. (ie. when its sequenceNumber
22065 + * becomes invalid). If the value matches the oldest then we clear
22066 + * dev->oldestDirtySequence to force its recomputation.
22068 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
22071 + if(!dev->param.isYaffs2)
22074 + if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
22075 + dev->oldestDirtySequence = 0;
22076 + dev->oldestDirtyBlock = 0;
22081 + * yaffs2_UpdateOldestDirtySequence()
22082 + * Update the oldest dirty sequence number whenever we dirty a block.
22083 + * Only do this if the oldestDirtySequence is actually being tracked.
22085 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
22087 + if(!dev->param.isYaffs2)
22090 + if(dev->oldestDirtySequence){
22091 + if(dev->oldestDirtySequence > bi->sequenceNumber){
22092 + dev->oldestDirtySequence = bi->sequenceNumber;
22093 + dev->oldestDirtyBlock = blockNo;
22098 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
22099 + yaffs_BlockInfo *bi)
22102 + if (!dev->param.isYaffs2)
22103 + return 1; /* disqualification only applies to yaffs2. */
22105 + if (!bi->hasShrinkHeader)
22106 + return 1; /* can gc */
22108 + yaffs2_FindOldestDirtySequence(dev);
22110 + /* Can't do gc of this block if there are any blocks older than this one that have
22111 + * discarded pages.
22113 + return (bi->sequenceNumber <= dev->oldestDirtySequence);
22117 + * yaffs2_FindRefreshBlock()
22118 + * periodically finds the oldest full block by sequence number for refreshing.
22119 + * Only for yaffs2.
22121 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
22125 + __u32 oldest = 0;
22126 + __u32 oldestSequence = 0;
22128 + yaffs_BlockInfo *bi;
22130 + if(!dev->param.isYaffs2)
22134 + * If refresh period < 10 then refreshing is disabled.
22136 + if(dev->param.refreshPeriod < 10)
22140 + * Fix broken values.
22142 + if(dev->refreshSkip > dev->param.refreshPeriod)
22143 + dev->refreshSkip = dev->param.refreshPeriod;
22145 + if(dev->refreshSkip > 0)
22149 + * Refresh skip is now zero.
22150 + * We'll do a refresh this time around....
22151 + * Update the refresh skip and find the oldest block.
22153 + dev->refreshSkip = dev->param.refreshPeriod;
22154 + dev->refreshCount++;
22155 + bi = dev->blockInfo;
22156 + for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
22158 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
22161 + bi->sequenceNumber < oldestSequence){
22163 + oldestSequence = bi->sequenceNumber;
22169 + if (oldest > 0) {
22170 + T(YAFFS_TRACE_GC,
22171 + (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
22172 + dev->refreshCount, oldest, oldestSequence));
22178 +int yaffs2_CheckpointRequired(yaffs_Device *dev)
22182 + if(!dev->param.isYaffs2)
22185 + nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
22187 + return !dev->param.skipCheckpointWrite &&
22188 + !dev->readOnly &&
22189 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
22192 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
22196 + if(!dev->param.isYaffs2)
22199 + if (!dev->nCheckpointBlocksRequired &&
22200 + yaffs2_CheckpointRequired(dev)){
22201 + /* Not a valid value so recalculate */
22204 + int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
22206 + nBytes += sizeof(yaffs_CheckpointValidity);
22207 + nBytes += sizeof(yaffs_CheckpointDevice);
22208 + nBytes += devBlocks * sizeof(yaffs_BlockInfo);
22209 + nBytes += devBlocks * dev->chunkBitmapStride;
22210 + nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
22211 + nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
22212 + nBytes += sizeof(yaffs_CheckpointValidity);
22213 + nBytes += sizeof(__u32); /* checksum*/
22215 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
22217 + nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
22219 + dev->nCheckpointBlocksRequired = nBlocks;
22222 + retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
22228 +/*--------------------- Checkpointing --------------------*/
22231 +static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
22233 + yaffs_CheckpointValidity cp;
22235 + memset(&cp, 0, sizeof(cp));
22237 + cp.structType = sizeof(cp);
22238 + cp.magic = YAFFS_MAGIC;
22239 + cp.version = YAFFS_CHECKPOINT_VERSION;
22240 + cp.head = (head) ? 1 : 0;
22242 + return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
22246 +static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
22248 + yaffs_CheckpointValidity cp;
22251 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22254 + ok = (cp.structType == sizeof(cp)) &&
22255 + (cp.magic == YAFFS_MAGIC) &&
22256 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
22257 + (cp.head == ((head) ? 1 : 0));
22258 + return ok ? 1 : 0;
22261 +static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
22262 + yaffs_Device *dev)
22264 + cp->nErasedBlocks = dev->nErasedBlocks;
22265 + cp->allocationBlock = dev->allocationBlock;
22266 + cp->allocationPage = dev->allocationPage;
22267 + cp->nFreeChunks = dev->nFreeChunks;
22269 + cp->nDeletedFiles = dev->nDeletedFiles;
22270 + cp->nUnlinkedFiles = dev->nUnlinkedFiles;
22271 + cp->nBackgroundDeletions = dev->nBackgroundDeletions;
22272 + cp->sequenceNumber = dev->sequenceNumber;
22276 +static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
22277 + yaffs_CheckpointDevice *cp)
22279 + dev->nErasedBlocks = cp->nErasedBlocks;
22280 + dev->allocationBlock = cp->allocationBlock;
22281 + dev->allocationPage = cp->allocationPage;
22282 + dev->nFreeChunks = cp->nFreeChunks;
22284 + dev->nDeletedFiles = cp->nDeletedFiles;
22285 + dev->nUnlinkedFiles = cp->nUnlinkedFiles;
22286 + dev->nBackgroundDeletions = cp->nBackgroundDeletions;
22287 + dev->sequenceNumber = cp->sequenceNumber;
22291 +static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
22293 + yaffs_CheckpointDevice cp;
22295 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22299 + /* Write device runtime values*/
22300 + yaffs2_DeviceToCheckpointDevice(&cp, dev);
22301 + cp.structType = sizeof(cp);
22303 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22305 + /* Write block info */
22307 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22308 + ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
22311 + /* Write chunk bits */
22313 + nBytes = nBlocks * dev->chunkBitmapStride;
22314 + ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
22316 + return ok ? 1 : 0;
22320 +static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
22322 + yaffs_CheckpointDevice cp;
22324 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22328 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22332 + if (cp.structType != sizeof(cp))
22336 + yaffs2_CheckpointDeviceToDevice(dev, &cp);
22338 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22340 + ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
22344 + nBytes = nBlocks * dev->chunkBitmapStride;
22346 + ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
22348 + return ok ? 1 : 0;
22351 +static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
22352 + yaffs_Object *obj)
22355 + cp->objectId = obj->objectId;
22356 + cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
22357 + cp->hdrChunk = obj->hdrChunk;
22358 + cp->variantType = obj->variantType;
22359 + cp->deleted = obj->deleted;
22360 + cp->softDeleted = obj->softDeleted;
22361 + cp->unlinked = obj->unlinked;
22362 + cp->fake = obj->fake;
22363 + cp->renameAllowed = obj->renameAllowed;
22364 + cp->unlinkAllowed = obj->unlinkAllowed;
22365 + cp->serial = obj->serial;
22366 + cp->nDataChunks = obj->nDataChunks;
22368 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22369 + cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
22370 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22371 + cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
22374 +static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
22377 + yaffs_Object *parent;
22379 + if (obj->variantType != cp->variantType) {
22380 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
22381 + TCONT("chunk %d does not match existing object type %d")
22382 + TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
22383 + obj->variantType));
22387 + obj->objectId = cp->objectId;
22389 + if (cp->parentId)
22390 + parent = yaffs_FindOrCreateObjectByNumber(
22393 + YAFFS_OBJECT_TYPE_DIRECTORY);
22398 + if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
22399 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
22400 + TCONT(" chunk %d Parent type, %d, not directory")
22402 + cp->objectId, cp->parentId, cp->variantType,
22403 + cp->hdrChunk, parent->variantType));
22406 + yaffs_AddObjectToDirectory(parent, obj);
22409 + obj->hdrChunk = cp->hdrChunk;
22410 + obj->variantType = cp->variantType;
22411 + obj->deleted = cp->deleted;
22412 + obj->softDeleted = cp->softDeleted;
22413 + obj->unlinked = cp->unlinked;
22414 + obj->fake = cp->fake;
22415 + obj->renameAllowed = cp->renameAllowed;
22416 + obj->unlinkAllowed = cp->unlinkAllowed;
22417 + obj->serial = cp->serial;
22418 + obj->nDataChunks = cp->nDataChunks;
22420 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22421 + obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
22422 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22423 + obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
22425 + if (obj->hdrChunk > 0)
22426 + obj->lazyLoaded = 1;
22432 +static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
22433 + __u32 level, int chunkOffset)
22436 + yaffs_Device *dev = in->myDev;
22442 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
22443 + if (tn->internal[i]) {
22444 + ok = yaffs2_CheckpointTnodeWorker(in,
22447 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
22450 + } else if (level == 0) {
22451 + __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
22452 + ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
22454 + ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22462 +static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
22464 + __u32 endMarker = ~0;
22467 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22468 + ok = yaffs2_CheckpointTnodeWorker(obj,
22469 + obj->variant.fileVariant.top,
22470 + obj->variant.fileVariant.topLevel,
22473 + ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
22474 + sizeof(endMarker));
22477 + return ok ? 1 : 0;
22480 +static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
22484 + yaffs_Device *dev = obj->myDev;
22485 + yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
22489 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22491 + while (ok && (~baseChunk)) {
22493 + /* Read level 0 tnode */
22496 + tn = yaffs_GetTnode(dev);
22498 + ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22503 + ok = yaffs_AddOrFindLevel0Tnode(dev,
22509 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22513 + T(YAFFS_TRACE_CHECKPOINT, (
22514 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
22515 + nread, baseChunk, ok));
22517 + return ok ? 1 : 0;
22521 +static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
22523 + yaffs_Object *obj;
22524 + yaffs_CheckpointObject cp;
22527 + struct ylist_head *lh;
22530 + /* Iterate through the objects in each hash entry,
22531 + * dumping them to the checkpointing stream.
22534 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
22535 + ylist_for_each(lh, &dev->objectBucket[i].list) {
22537 + obj = ylist_entry(lh, yaffs_Object, hashLink);
22538 + if (!obj->deferedFree) {
22539 + yaffs2_ObjectToCheckpointObject(&cp, obj);
22540 + cp.structType = sizeof(cp);
22542 + T(YAFFS_TRACE_CHECKPOINT, (
22543 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
22544 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
22546 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22548 + if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22549 + ok = yaffs2_WriteCheckpointTnodes(obj);
22555 + /* Dump end of list */
22556 + memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
22557 + cp.structType = sizeof(cp);
22560 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22562 + return ok ? 1 : 0;
22565 +static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
22567 + yaffs_Object *obj;
22568 + yaffs_CheckpointObject cp;
22571 + yaffs_Object *hardList = NULL;
22573 + while (ok && !done) {
22574 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22575 + if (cp.structType != sizeof(cp)) {
22576 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
22577 + cp.structType, (int)sizeof(cp), ok));
22581 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
22582 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
22584 + if (ok && cp.objectId == ~0)
22587 + obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
22589 + ok = yaffs2_CheckpointObjectToObject(obj, &cp);
22592 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22593 + ok = yaffs2_ReadCheckpointTnodes(obj);
22594 + } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
22595 + obj->hardLinks.next =
22596 + (struct ylist_head *) hardList;
22605 + yaffs_HardlinkFixup(dev, hardList);
22607 + return ok ? 1 : 0;
22610 +static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
22612 + __u32 checkpointSum;
22615 + yaffs2_GetCheckpointSum(dev, &checkpointSum);
22617 + ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
22625 +static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
22627 + __u32 checkpointSum0;
22628 + __u32 checkpointSum1;
22631 + yaffs2_GetCheckpointSum(dev, &checkpointSum0);
22633 + ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
22638 + if (checkpointSum0 != checkpointSum1)
22645 +static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
22649 + if (!yaffs2_CheckpointRequired(dev)) {
22650 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
22655 + ok = yaffs2_CheckpointOpen(dev, 1);
22658 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22659 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
22662 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
22663 + ok = yaffs2_WriteCheckpointDevice(dev);
22666 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
22667 + ok = yaffs2_WriteCheckpointObjects(dev);
22670 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22671 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
22675 + ok = yaffs2_WriteCheckpointSum(dev);
22677 + if (!yaffs2_CheckpointClose(dev))
22681 + dev->isCheckpointed = 1;
22683 + dev->isCheckpointed = 0;
22685 + return dev->isCheckpointed;
22688 +static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
22692 + if(!dev->param.isYaffs2)
22695 + if (ok && dev->param.skipCheckpointRead) {
22696 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
22701 + ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
22704 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22705 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
22708 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
22709 + ok = yaffs2_ReadCheckpointDevice(dev);
22712 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
22713 + ok = yaffs2_ReadCheckpointObjects(dev);
22716 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22717 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
22721 + ok = yaffs2_ReadCheckpointSum(dev);
22722 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
22725 + if (!yaffs2_CheckpointClose(dev))
22729 + dev->isCheckpointed = 1;
22731 + dev->isCheckpointed = 0;
22733 + return ok ? 1 : 0;
22737 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
22739 + if (dev->isCheckpointed ||
22740 + dev->blocksInCheckpoint > 0) {
22741 + dev->isCheckpointed = 0;
22742 + yaffs2_CheckpointInvalidateStream(dev);
22744 + if (dev->param.markSuperBlockDirty)
22745 + dev->param.markSuperBlockDirty(dev);
22749 +int yaffs_CheckpointSave(yaffs_Device *dev)
22752 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22754 + yaffs_VerifyObjects(dev);
22755 + yaffs_VerifyBlocks(dev);
22756 + yaffs_VerifyFreeChunks(dev);
22758 + if (!dev->isCheckpointed) {
22759 + yaffs2_InvalidateCheckpoint(dev);
22760 + yaffs2_WriteCheckpointData(dev);
22763 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22765 + return dev->isCheckpointed;
22768 +int yaffs2_CheckpointRestore(yaffs_Device *dev)
22771 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22773 + retval = yaffs2_ReadCheckpointData(dev);
22775 + if (dev->isCheckpointed) {
22776 + yaffs_VerifyObjects(dev);
22777 + yaffs_VerifyBlocks(dev);
22778 + yaffs_VerifyFreeChunks(dev);
22781 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22786 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
22788 + /* if newsSize > oldFileSize.
22789 + * We're going to be writing a hole.
22790 + * If the hole is small then write zeros otherwise write a start of hole marker.
22794 + loff_t oldFileSize;
22797 + int result = YAFFS_OK;
22798 + yaffs_Device *dev = NULL;
22800 + __u8 *localBuffer = NULL;
22802 + int smallIncreaseOk = 0;
22805 + return YAFFS_FAIL;
22807 + if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
22808 + return YAFFS_FAIL;
22810 + dev = obj->myDev;
22812 + /* Bail out if not yaffs2 mode */
22813 + if(!dev->param.isYaffs2)
22816 + oldFileSize = obj->variant.fileVariant.fileSize;
22818 + if (newSize <= oldFileSize)
22821 + increase = newSize - oldFileSize;
22823 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
22824 + yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
22830 + localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
22833 + /* fill hole with zero bytes */
22834 + int pos = oldFileSize;
22837 + memset(localBuffer,0,dev->nDataBytesPerChunk);
22838 + smallIncreaseOk = 1;
22840 + while(increase > 0 && smallIncreaseOk){
22841 + thisWrite = increase;
22842 + if(thisWrite > dev->nDataBytesPerChunk)
22843 + thisWrite = dev->nDataBytesPerChunk;
22844 + written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
22845 + if(written == thisWrite){
22846 + pos += thisWrite;
22847 + increase -= thisWrite;
22849 + smallIncreaseOk = 0;
22852 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
22854 + /* If we were out of space then reverse any chunks we've added */
22855 + if(!smallIncreaseOk)
22856 + yaffs_ResizeDown(obj, oldFileSize);
22859 + if (!smallIncreaseOk &&
22861 + obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
22862 + obj->parent->objectId != YAFFS_OBJECTID_DELETED){
22863 + /* Write a hole start header with the old file size */
22864 + yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
22875 +} yaffs_BlockIndex;
22878 +static int yaffs2_ybicmp(const void *a, const void *b)
22880 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
22881 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
22882 + register int ablock = ((yaffs_BlockIndex *)a)->block;
22883 + register int bblock = ((yaffs_BlockIndex *)b)->block;
22884 + if (aseq == bseq)
22885 + return ablock - bblock;
22887 + return aseq - bseq;
22890 +int yaffs2_ScanBackwards(yaffs_Device *dev)
22892 + yaffs_ExtendedTags tags;
22894 + int blockIterator;
22895 + int startIterator;
22897 + int nBlocksToScan = 0;
22903 + yaffs_BlockState state;
22904 + yaffs_Object *hardList = NULL;
22905 + yaffs_BlockInfo *bi;
22906 + __u32 sequenceNumber;
22907 + yaffs_ObjectHeader *oh;
22908 + yaffs_Object *in;
22909 + yaffs_Object *parent;
22910 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
22916 + int foundChunksInBlock;
22917 + int equivalentObjectId;
22918 + int alloc_failed = 0;
22921 + yaffs_BlockIndex *blockIndex = NULL;
22922 + int altBlockIndex = 0;
22924 + T(YAFFS_TRACE_SCAN,
22926 + ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
22927 + TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
22930 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
22932 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
22934 + if (!blockIndex) {
22935 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
22936 + altBlockIndex = 1;
22939 + if (!blockIndex) {
22940 + T(YAFFS_TRACE_SCAN,
22941 + (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
22942 + return YAFFS_FAIL;
22945 + dev->blocksInCheckpoint = 0;
22947 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
22949 + /* Scan all the blocks to determine their state */
22950 + bi = dev->blockInfo;
22951 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
22952 + yaffs_ClearChunkBits(dev, blk);
22953 + bi->pagesInUse = 0;
22954 + bi->softDeletions = 0;
22956 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
22958 + bi->blockState = state;
22959 + bi->sequenceNumber = sequenceNumber;
22961 + if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
22962 + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
22963 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
22964 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
22966 + T(YAFFS_TRACE_SCAN_DEBUG,
22967 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
22968 + state, sequenceNumber));
22971 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
22972 + dev->blocksInCheckpoint++;
22974 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
22975 + T(YAFFS_TRACE_BAD_BLOCKS,
22976 + (TSTR("block %d is bad" TENDSTR), blk));
22977 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
22978 + T(YAFFS_TRACE_SCAN_DEBUG,
22979 + (TSTR("Block empty " TENDSTR)));
22980 + dev->nErasedBlocks++;
22981 + dev->nFreeChunks += dev->param.nChunksPerBlock;
22982 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
22984 + /* Determine the highest sequence number */
22985 + if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
22986 + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
22988 + blockIndex[nBlocksToScan].seq = sequenceNumber;
22989 + blockIndex[nBlocksToScan].block = blk;
22993 + if (sequenceNumber >= dev->sequenceNumber)
22994 + dev->sequenceNumber = sequenceNumber;
22996 + /* TODO: Nasty sequence number! */
22997 + T(YAFFS_TRACE_SCAN,
22999 + ("Block scanning block %d has bad sequence number %d"
23000 + TENDSTR), blk, sequenceNumber));
23007 + T(YAFFS_TRACE_SCAN,
23008 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
23014 + /* Sort the blocks by sequence number*/
23015 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
23019 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
23021 + /* Now scan the blocks looking at the data. */
23022 + startIterator = 0;
23023 + endIterator = nBlocksToScan - 1;
23024 + T(YAFFS_TRACE_SCAN_DEBUG,
23025 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
23027 + /* For each block.... backwards */
23028 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
23029 + blockIterator--) {
23030 + /* Cooperative multitasking! This loop can run for so
23031 + long that watchdog timers expire. */
23034 + /* get the block to scan in the correct order */
23035 + blk = blockIndex[blockIterator].block;
23037 + bi = yaffs_GetBlockInfo(dev, blk);
23040 + state = bi->blockState;
23044 + /* For each chunk in each block that needs scanning.... */
23045 + foundChunksInBlock = 0;
23046 + for (c = dev->param.nChunksPerBlock - 1;
23047 + !alloc_failed && c >= 0 &&
23048 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23049 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
23050 + /* Scan backwards...
23051 + * Read the tags and decide what to do
23054 + chunk = blk * dev->param.nChunksPerBlock + c;
23056 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
23059 + /* Let's have a good look at this chunk... */
23061 + if (!tags.chunkUsed) {
23062 + /* An unassigned chunk in the block.
23063 + * If there are used chunks after this one, then
23064 + * it is a chunk that was skipped due to failing the erased
23065 + * check. Just skip it so that it can be deleted.
23066 + * But, more typically, We get here when this is an unallocated
23067 + * chunk and his means that either the block is empty or
23068 + * this is the one being allocated from
23071 + if (foundChunksInBlock) {
23072 + /* This is a chunk that was skipped due to failing the erased check */
23073 + } else if (c == 0) {
23074 + /* We're looking at the first chunk in the block so the block is unused */
23075 + state = YAFFS_BLOCK_STATE_EMPTY;
23076 + dev->nErasedBlocks++;
23078 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23079 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
23080 + if (dev->sequenceNumber == bi->sequenceNumber) {
23081 + /* this is the block being allocated from */
23083 + T(YAFFS_TRACE_SCAN,
23085 + (" Allocating from %d %d"
23086 + TENDSTR), blk, c));
23088 + state = YAFFS_BLOCK_STATE_ALLOCATING;
23089 + dev->allocationBlock = blk;
23090 + dev->allocationPage = c;
23091 + dev->allocationBlockFinder = blk;
23093 + /* This is a partially written block that is not
23094 + * the current allocation block.
23097 + T(YAFFS_TRACE_SCAN,
23098 + (TSTR("Partially written block %d detected" TENDSTR),
23104 + dev->nFreeChunks++;
23106 + } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
23107 + T(YAFFS_TRACE_SCAN,
23108 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
23111 + dev->nFreeChunks++;
23113 + } else if (tags.objectId > YAFFS_MAX_OBJECT_ID ||
23114 + tags.chunkId > YAFFS_MAX_CHUNK_ID ||
23115 + (tags.chunkId > 0 && tags.byteCount > dev->nDataBytesPerChunk) ||
23116 + tags.sequenceNumber != bi->sequenceNumber ) {
23117 + T(YAFFS_TRACE_SCAN,
23118 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunkId = %d, byteCount = %d, ignored"TENDSTR),
23119 + blk, c,tags.objectId, tags.chunkId, tags.byteCount));
23121 + dev->nFreeChunks++;
23123 + } else if (tags.chunkId > 0) {
23124 + /* chunkId > 0 so it is a data chunk... */
23125 + unsigned int endpos;
23126 + __u32 chunkBase =
23127 + (tags.chunkId - 1) * dev->nDataBytesPerChunk;
23129 + foundChunksInBlock = 1;
23132 + yaffs_SetChunkBit(dev, blk, c);
23133 + bi->pagesInUse++;
23135 + in = yaffs_FindOrCreateObjectByNumber(dev,
23138 + YAFFS_OBJECT_TYPE_FILE);
23140 + /* Out of memory */
23141 + alloc_failed = 1;
23145 + in->variantType == YAFFS_OBJECT_TYPE_FILE
23146 + && chunkBase < in->variant.fileVariant.shrinkSize) {
23147 + /* This has not been invalidated by a resize */
23148 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
23149 + alloc_failed = 1;
23152 + /* File size is calculated by looking at the data chunks if we have not
23153 + * seen an object header yet. Stop this practice once we find an object header.
23155 + endpos = chunkBase + tags.byteCount;
23157 + if (!in->valid && /* have not got an object header yet */
23158 + in->variant.fileVariant.scannedFileSize < endpos) {
23159 + in->variant.fileVariant.scannedFileSize = endpos;
23160 + in->variant.fileVariant.fileSize = endpos;
23164 + /* This chunk has been invalidated by a resize, or a past file deletion
23165 + * so delete the chunk*/
23166 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23170 + /* chunkId == 0, so it is an ObjectHeader.
23171 + * Thus, we read in the object header and make the object
23173 + foundChunksInBlock = 1;
23175 + yaffs_SetChunkBit(dev, blk, c);
23176 + bi->pagesInUse++;
23181 + if (tags.extraHeaderInfoAvailable) {
23182 + in = yaffs_FindOrCreateObjectByNumber(dev,
23184 + tags.extraObjectType);
23186 + alloc_failed = 1;
23190 + (!in->valid && dev->param.disableLazyLoad) ||
23191 + tags.extraShadows ||
23193 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23194 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
23196 + /* If we don't have valid info then we need to read the chunk
23197 + * TODO In future we can probably defer reading the chunk and
23198 + * living with invalid data until needed.
23201 + result = yaffs_ReadChunkWithTagsFromNAND(dev,
23206 + oh = (yaffs_ObjectHeader *) chunkData;
23208 + if (dev->param.inbandTags) {
23209 + /* Fix up the header if they got corrupted by inband tags */
23210 + oh->shadowsObject = oh->inbandShadowsObject;
23211 + oh->isShrink = oh->inbandIsShrink;
23215 + in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
23217 + alloc_failed = 1;
23223 + /* TODO Hoosterman we have a problem! */
23224 + T(YAFFS_TRACE_ERROR,
23226 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
23227 + TENDSTR), tags.objectId, chunk));
23232 + /* We have already filled this one.
23233 + * We have a duplicate that will be discarded, but
23234 + * we first have to suck out resize info if it is a file.
23237 + if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
23239 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
23240 + (tags.extraHeaderInfoAvailable &&
23241 + tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
23243 + (oh) ? oh->fileSize : tags.
23245 + __u32 parentObjectId =
23247 + parentObjectId : tags.
23248 + extraParentObjectId;
23252 + (oh) ? oh->isShrink : tags.
23253 + extraIsShrinkHeader;
23255 + /* If it is deleted (unlinked at start also means deleted)
23256 + * we treat the file size as being zeroed at this point.
23258 + if (parentObjectId ==
23259 + YAFFS_OBJECTID_DELETED
23260 + || parentObjectId ==
23261 + YAFFS_OBJECTID_UNLINKED) {
23266 + if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
23267 + in->variant.fileVariant.shrinkSize = thisSize;
23270 + bi->hasShrinkHeader = 1;
23273 + /* Use existing - destroy this one. */
23274 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23278 + if (!in->valid && in->variantType !=
23279 + (oh ? oh->type : tags.extraObjectType))
23280 + T(YAFFS_TRACE_ERROR, (
23281 + TSTR("yaffs tragedy: Bad object type, "
23282 + TCONT("%d != %d, for object %d at chunk ")
23283 + TCONT("%d during scan")
23285 + oh->type : tags.extraObjectType,
23286 + in->variantType, tags.objectId,
23289 + if (!in->valid &&
23290 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23292 + YAFFS_OBJECTID_LOSTNFOUND)) {
23293 + /* We only load some info, don't fiddle with directory structure */
23298 + in->yst_mode = oh->yst_mode;
23299 +#ifdef CONFIG_YAFFS_WINCE
23300 + in->win_atime[0] = oh->win_atime[0];
23301 + in->win_ctime[0] = oh->win_ctime[0];
23302 + in->win_mtime[0] = oh->win_mtime[0];
23303 + in->win_atime[1] = oh->win_atime[1];
23304 + in->win_ctime[1] = oh->win_ctime[1];
23305 + in->win_mtime[1] = oh->win_mtime[1];
23307 + in->yst_uid = oh->yst_uid;
23308 + in->yst_gid = oh->yst_gid;
23309 + in->yst_atime = oh->yst_atime;
23310 + in->yst_mtime = oh->yst_mtime;
23311 + in->yst_ctime = oh->yst_ctime;
23312 + in->yst_rdev = oh->yst_rdev;
23314 + in->lazyLoaded = 0;
23318 + in->lazyLoaded = 1;
23320 + in->hdrChunk = chunk;
23322 + } else if (!in->valid) {
23323 + /* we need to load this info */
23326 + in->hdrChunk = chunk;
23329 + in->variantType = oh->type;
23331 + in->yst_mode = oh->yst_mode;
23332 +#ifdef CONFIG_YAFFS_WINCE
23333 + in->win_atime[0] = oh->win_atime[0];
23334 + in->win_ctime[0] = oh->win_ctime[0];
23335 + in->win_mtime[0] = oh->win_mtime[0];
23336 + in->win_atime[1] = oh->win_atime[1];
23337 + in->win_ctime[1] = oh->win_ctime[1];
23338 + in->win_mtime[1] = oh->win_mtime[1];
23340 + in->yst_uid = oh->yst_uid;
23341 + in->yst_gid = oh->yst_gid;
23342 + in->yst_atime = oh->yst_atime;
23343 + in->yst_mtime = oh->yst_mtime;
23344 + in->yst_ctime = oh->yst_ctime;
23345 + in->yst_rdev = oh->yst_rdev;
23348 + if (oh->shadowsObject > 0)
23349 + yaffs_HandleShadowedObject(dev,
23356 + yaffs_SetObjectNameFromOH(in, oh);
23358 + yaffs_FindOrCreateObjectByNumber
23359 + (dev, oh->parentObjectId,
23360 + YAFFS_OBJECT_TYPE_DIRECTORY);
23362 + fileSize = oh->fileSize;
23363 + isShrink = oh->isShrink;
23364 + equivalentObjectId = oh->equivalentObjectId;
23367 + in->variantType = tags.extraObjectType;
23369 + yaffs_FindOrCreateObjectByNumber
23370 + (dev, tags.extraParentObjectId,
23371 + YAFFS_OBJECT_TYPE_DIRECTORY);
23372 + fileSize = tags.extraFileLength;
23373 + isShrink = tags.extraIsShrinkHeader;
23374 + equivalentObjectId = tags.extraEquivalentObjectId;
23375 + in->lazyLoaded = 1;
23381 + alloc_failed = 1;
23383 + /* directory stuff...
23384 + * hook up to parent
23387 + if (parent && parent->variantType ==
23388 + YAFFS_OBJECT_TYPE_UNKNOWN) {
23389 + /* Set up as a directory */
23390 + parent->variantType =
23391 + YAFFS_OBJECT_TYPE_DIRECTORY;
23392 + YINIT_LIST_HEAD(&parent->variant.
23393 + directoryVariant.
23395 + } else if (!parent || parent->variantType !=
23396 + YAFFS_OBJECT_TYPE_DIRECTORY) {
23397 + /* Hoosterman, another problem....
23398 + * We're trying to use a non-directory as a directory
23401 + T(YAFFS_TRACE_ERROR,
23403 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
23405 + parent = dev->lostNFoundDir;
23408 + yaffs_AddObjectToDirectory(parent, in);
23410 + itsUnlinked = (parent == dev->deletedDir) ||
23411 + (parent == dev->unlinkedDir);
23414 + /* Mark the block as having a shrinkHeader */
23415 + bi->hasShrinkHeader = 1;
23418 + /* Note re hardlinks.
23419 + * Since we might scan a hardlink before its equivalent object is scanned
23420 + * we put them all in a list.
23421 + * After scanning is complete, we should have all the objects, so we run
23422 + * through this list and fix up all the chains.
23425 + switch (in->variantType) {
23426 + case YAFFS_OBJECT_TYPE_UNKNOWN:
23427 + /* Todo got a problem */
23429 + case YAFFS_OBJECT_TYPE_FILE:
23431 + if (in->variant.fileVariant.
23432 + scannedFileSize < fileSize) {
23433 + /* This covers the case where the file size is greater
23434 + * than where the data is
23435 + * This will happen if the file is resized to be larger
23436 + * than its current data extents.
23438 + in->variant.fileVariant.fileSize = fileSize;
23439 + in->variant.fileVariant.scannedFileSize = fileSize;
23442 + if (in->variant.fileVariant.shrinkSize > fileSize)
23443 + in->variant.fileVariant.shrinkSize = fileSize;
23447 + case YAFFS_OBJECT_TYPE_HARDLINK:
23448 + if (!itsUnlinked) {
23449 + in->variant.hardLinkVariant.equivalentObjectId =
23450 + equivalentObjectId;
23451 + in->hardLinks.next =
23452 + (struct ylist_head *) hardList;
23456 + case YAFFS_OBJECT_TYPE_DIRECTORY:
23459 + case YAFFS_OBJECT_TYPE_SPECIAL:
23462 + case YAFFS_OBJECT_TYPE_SYMLINK:
23464 + in->variant.symLinkVariant.alias =
23465 + yaffs_CloneString(oh->alias);
23466 + if (!in->variant.symLinkVariant.alias)
23467 + alloc_failed = 1;
23476 + } /* End of scanning for each chunk */
23478 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
23479 + /* If we got this far while scanning, then the block is fully allocated. */
23480 + state = YAFFS_BLOCK_STATE_FULL;
23484 + bi->blockState = state;
23486 + /* Now let's see if it was dirty */
23487 + if (bi->pagesInUse == 0 &&
23488 + !bi->hasShrinkHeader &&
23489 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
23490 + yaffs_BlockBecameDirty(dev, blk);
23495 + yaffs_SkipRestOfBlock(dev);
23497 + if (altBlockIndex)
23498 + YFREE_ALT(blockIndex);
23500 + YFREE(blockIndex);
23502 + /* Ok, we've done all the scanning.
23503 + * Fix up the hard link chains.
23504 + * We should now have scanned all the objects, now it's time to add these
23507 + yaffs_HardlinkFixup(dev, hardList);
23510 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
23512 + if (alloc_failed)
23513 + return YAFFS_FAIL;
23515 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
23520 +++ b/fs/yaffs2/yaffs_yaffs2.h
23523 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
23525 + * Copyright (C) 2002-2010 Aleph One Ltd.
23526 + * for Toby Churchill Ltd and Brightstar Engineering
23528 + * Created by Charles Manning <charles@aleph1.co.uk>
23530 + * This program is free software; you can redistribute it and/or modify
23531 + * it under the terms of the GNU General Public License version 2 as
23532 + * published by the Free Software Foundation.
23535 +#ifndef __YAFFS_YAFFS2_H__
23536 +#define __YAFFS_YAFFS2_H__
23538 +#include "yaffs_guts.h"
23540 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev);
23541 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev);
23542 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi);
23543 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi);
23544 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi);
23545 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev);
23546 +int yaffs2_CheckpointRequired(yaffs_Device *dev);
23547 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev);
23550 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
23551 +int yaffs2_CheckpointSave(yaffs_Device *dev);
23552 +int yaffs2_CheckpointRestore(yaffs_Device *dev);
23554 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
23555 +int yaffs2_ScanBackwards(yaffs_Device *dev);
23558 --- a/fs/yaffs2/yportenv.h
23559 +++ b/fs/yaffs2/yportenv.h
23562 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
23564 - * Copyright (C) 2002-2007 Aleph One Ltd.
23565 + * Copyright (C) 2002-2010 Aleph One Ltd.
23566 * for Toby Churchill Ltd and Brightstar Engineering
23568 * Created by Charles Manning <charles@aleph1.co.uk>
23569 @@ -41,12 +41,14 @@
23570 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
23571 #include <linux/config.h>
23574 #include <linux/kernel.h>
23575 #include <linux/mm.h>
23576 #include <linux/sched.h>
23577 #include <linux/string.h>
23578 #include <linux/slab.h>
23579 #include <linux/vmalloc.h>
23580 +#include <linux/xattr.h>
23583 #define YUCHAR unsigned char
23584 @@ -55,11 +57,11 @@
23585 #define yaffs_strcpy(a, b) strcpy(a, b)
23586 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23587 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
23588 -#define yaffs_strlen(s) strlen(s)
23589 +#define yaffs_strnlen(s,m) strnlen(s,m)
23590 #define yaffs_sprintf sprintf
23591 #define yaffs_toupper(a) toupper(a)
23593 -#define Y_INLINE inline
23594 +#define Y_INLINE __inline__
23596 #define YAFFS_LOSTNFOUND_NAME "lost+found"
23597 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23598 @@ -71,11 +73,11 @@
23599 #define YFREE_ALT(x) vfree(x)
23600 #define YMALLOC_DMA(x) YMALLOC(x)
23602 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
23603 #define YYIELD() schedule()
23604 +#define Y_DUMP_STACK() dump_stack()
23606 -#define YAFFS_ROOT_MODE 0666
23607 -#define YAFFS_LOSTNFOUND_MODE 0666
23608 +#define YAFFS_ROOT_MODE 0755
23609 +#define YAFFS_LOSTNFOUND_MODE 0700
23611 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23612 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
23613 @@ -89,15 +91,10 @@
23614 #define yaffs_strcmp(a, b) strcmp(a, b)
23616 #define TENDSTR "\n"
23617 -#define TSTR(x) KERN_WARNING x
23618 +#define TSTR(x) KERN_DEBUG x
23620 #define TOUT(p) printk p
23622 -#define yaffs_trace(mask, fmt, args...) \
23623 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
23624 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
23627 #define compile_time_assertion(assertion) \
23628 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
23630 @@ -116,7 +113,6 @@
23632 #include "string.h"
23634 -#include "devextras.h"
23636 #define YMALLOC(x) malloc(x)
23637 #define YFREE(x) free(x)
23638 @@ -129,7 +125,7 @@
23639 #define yaffs_strcat(a, b) strcat(a, b)
23640 #define yaffs_strcpy(a, b) strcpy(a, b)
23641 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23642 -#define yaffs_strlen(s) strlen(s)
23643 +#define yaffs_strnlen(s,m) strnlen(s,m)
23644 #define yaffs_sprintf sprintf
23645 #define yaffs_toupper(a) toupper(a)
23647 @@ -146,8 +142,8 @@
23648 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23649 /* #define YPRINTF(x) printf x */
23651 -#define YAFFS_ROOT_MODE 0666
23652 -#define YAFFS_LOSTNFOUND_MODE 0666
23653 +#define YAFFS_ROOT_MODE 0755
23654 +#define YAFFS_LOSTNFOUND_MODE 0700
23656 #define yaffs_SumCompare(x, y) ((x) == (y))
23657 #define yaffs_strcmp(a, b) strcmp(a, b)
23658 @@ -158,46 +154,180 @@
23662 -/* see yaffs_fs.c */
23663 -extern unsigned int yaffs_traceMask;
23664 -extern unsigned int yaffs_wr_attempts;
23665 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
23669 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
23671 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
23674 +#define O_RDONLY 00
23678 +#define O_WRONLY 01
23686 +#define O_CREAT 0100
23690 +#define O_EXCL 0200
23694 +#define O_TRUNC 01000
23698 +#define O_APPEND 02000
23702 +#define SEEK_SET 0
23706 +#define SEEK_CUR 1
23710 +#define SEEK_END 2
23750 +#define ENODATA 61
23754 +#define ENOTEMPTY 39
23757 +#ifndef ENAMETOOLONG
23758 +#define ENAMETOOLONG 36
23770 +#define ENOTDIR 20
23781 +#define S_IFMT 0170000
23785 +#define S_IFLNK 0120000
23788 -#define YAFFS_TRACE_OS 0x00000002
23789 -#define YAFFS_TRACE_ALLOCATE 0x00000004
23790 -#define YAFFS_TRACE_SCAN 0x00000008
23791 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
23792 -#define YAFFS_TRACE_ERASE 0x00000020
23793 -#define YAFFS_TRACE_GC 0x00000040
23794 -#define YAFFS_TRACE_WRITE 0x00000080
23795 -#define YAFFS_TRACE_TRACING 0x00000100
23796 -#define YAFFS_TRACE_DELETION 0x00000200
23797 -#define YAFFS_TRACE_BUFFERS 0x00000400
23798 -#define YAFFS_TRACE_NANDACCESS 0x00000800
23799 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
23800 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
23801 -#define YAFFS_TRACE_MTD 0x00004000
23802 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
23804 -#define YAFFS_TRACE_VERIFY 0x00010000
23805 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
23806 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
23807 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
23810 -#define YAFFS_TRACE_ERROR 0x40000000
23811 -#define YAFFS_TRACE_BUG 0x80000000
23812 -#define YAFFS_TRACE_ALWAYS 0xF0000000
23814 +#define S_IFDIR 0040000
23818 +#define S_IFREG 0100000
23822 +#define S_IREAD 0000400
23826 +#define S_IWRITE 0000200
23829 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
23831 +#define S_IEXEC 0000100
23834 +#ifndef XATTR_CREATE
23835 +#define XATTR_CREATE 1
23838 +#ifndef XATTR_REPLACE
23839 +#define XATTR_REPLACE 2
23850 +#include <errno.h>
23851 +#include <sys/stat.h>
23852 +#include <fcntl.h>
23857 +#ifndef Y_DUMP_STACK
23858 +#define Y_DUMP_STACK() do { } while (0)
23862 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
23863 +#define YBUG() do {\
23864 + T(YAFFS_TRACE_BUG,\
23865 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\