1 diff -Nrup linux-2.6.36-rc8/fs/Kconfig linux-2.6.36-rc8.new/fs/Kconfig
2 --- linux-2.6.36-rc8/fs/Kconfig 2010-10-20 13:11:25.295000294 +0300
3 +++ linux-2.6.36-rc8.new/fs/Kconfig 2010-10-20 13:28:15.952000294 +0300
4 @@ -44,7 +44,6 @@ source "fs/gfs2/Kconfig"
5 source "fs/ocfs2/Kconfig"
6 source "fs/btrfs/Kconfig"
7 source "fs/nilfs2/Kconfig"
8 -source "fs/yaffs2/Kconfig"
12 @@ -175,6 +174,10 @@ source "fs/hfsplus/Kconfig"
13 source "fs/befs/Kconfig"
14 source "fs/bfs/Kconfig"
15 source "fs/efs/Kconfig"
18 +source "fs/yaffs2/Kconfig"
20 source "fs/jffs2/Kconfig"
21 # UBIFS File system configuration
22 source "fs/ubifs/Kconfig"
23 diff -Nrup linux-2.6.36-rc8/fs/Makefile linux-2.6.36-rc8.new/fs/Makefile
24 --- linux-2.6.36-rc8/fs/Makefile 2010-10-20 13:11:25.295000294 +0300
25 +++ linux-2.6.36-rc8.new/fs/Makefile 2010-10-20 13:28:15.953000294 +0300
26 @@ -127,5 +127,6 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/
27 obj-$(CONFIG_GFS2_FS) += gfs2/
28 obj-$(CONFIG_EXOFS_FS) += exofs/
29 obj-$(CONFIG_CEPH_FS) += ceph/
30 -obj-$(CONFIG_YAFFS_FS) += yaffs2/
33 +obj-$(CONFIG_YAFFS_FS) += yaffs2/
34 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/devextras.h linux-2.6.36-rc8.new/fs/yaffs2/devextras.h
35 --- linux-2.6.36-rc8/fs/yaffs2/devextras.h 2010-10-20 13:17:58.937000294 +0300
36 +++ linux-2.6.36-rc8.new/fs/yaffs2/devextras.h 2010-10-20 13:28:16.050000294 +0300
39 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
41 - * Copyright (C) 2002-2007 Aleph One Ltd.
42 + * Copyright (C) 2002-2010 Aleph One Ltd.
43 * for Toby Churchill Ltd and Brightstar Engineering
45 * Created by Charles Manning <charles@aleph1.co.uk>
50 +#include "yportenv.h"
52 #if !(defined __KERNEL__)
54 /* Definition of types */
55 @@ -33,103 +35,6 @@ typedef unsigned __u32;
60 - * This is a simple doubly linked list implementation that matches the
61 - * way the Linux kernel doubly linked list implementation works.
65 - struct ylist_head *next; /* next in chain */
66 - struct ylist_head *prev; /* previous in chain */
70 -/* Initialise a static list */
71 -#define YLIST_HEAD(name) \
72 -struct ylist_head name = { &(name), &(name)}
76 -/* Initialise a list head to an empty list */
77 -#define YINIT_LIST_HEAD(p) \
84 -/* Add an element to a list */
85 -static __inline__ void ylist_add(struct ylist_head *newEntry,
86 - struct ylist_head *list)
88 - struct ylist_head *listNext = list->next;
90 - list->next = newEntry;
91 - newEntry->prev = list;
92 - newEntry->next = listNext;
93 - listNext->prev = newEntry;
97 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
98 - struct ylist_head *list)
100 - struct ylist_head *listPrev = list->prev;
102 - list->prev = newEntry;
103 - newEntry->next = list;
104 - newEntry->prev = listPrev;
105 - listPrev->next = newEntry;
110 -/* Take an element out of its current list, with or without
111 - * reinitialising the links.of the entry*/
112 -static __inline__ void ylist_del(struct ylist_head *entry)
114 - struct ylist_head *listNext = entry->next;
115 - struct ylist_head *listPrev = entry->prev;
117 - listNext->prev = listPrev;
118 - listPrev->next = listNext;
122 -static __inline__ void ylist_del_init(struct ylist_head *entry)
125 - entry->next = entry->prev = entry;
129 -/* Test if the list is empty */
130 -static __inline__ int ylist_empty(struct ylist_head *entry)
132 - return (entry->next == entry);
136 -/* ylist_entry takes a pointer to a list entry and offsets it to that
137 - * we can find a pointer to the object it is embedded in.
141 -#define ylist_entry(entry, type, member) \
142 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
145 -/* ylist_for_each and list_for_each_safe iterate over lists.
146 - * ylist_for_each_safe uses temporary storage to make the list delete safe
149 -#define ylist_for_each(itervar, list) \
150 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
152 -#define ylist_for_each_safe(itervar, saveVar, list) \
153 - for (itervar = (list)->next, saveVar = (list)->next->next; \
154 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
157 #if !(defined __KERNEL__)
159 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/Kconfig linux-2.6.36-rc8.new/fs/yaffs2/Kconfig
160 --- linux-2.6.36-rc8/fs/yaffs2/Kconfig 2010-10-20 13:17:58.937000294 +0300
161 +++ linux-2.6.36-rc8.new/fs/yaffs2/Kconfig 2010-10-20 13:28:15.993000294 +0300
162 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
166 -config YAFFS_DISABLE_LAZY_LOAD
167 - bool "Disable lazy loading"
168 - depends on YAFFS_YAFFS2
169 +config YAFFS_DISABLE_TAGS_ECC
170 + bool "Disable YAFFS from doing ECC on tags by default"
171 + depends on YAFFS_FS && YAFFS_YAFFS2
174 - "Lazy loading" defers loading file details until they are
175 - required. This saves mount time, but makes the first look-up
178 - Lazy loading will only happen if enabled by this option being 'n'
179 - and if the appropriate tags are available, else yaffs2 will
180 - automatically fall back to immediate loading and do the right
183 - Lazy laoding will be required by checkpointing.
185 - Setting this to 'y' will disable lazy loading.
186 + This defaults Yaffs to using its own ECC calculations on tags instead of
187 + just relying on the MTD.
188 + This behavior can also be overridden with tags_ecc_on and
189 + tags_ecc_off mount options.
193 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
194 but makes look-ups faster.
198 +config YAFFS_EMPTY_LOST_AND_FOUND
199 + bool "Empty lost and found on boot"
200 + depends on YAFFS_FS
203 + If this is enabled then the contents of lost and found is
204 + automatically dumped at mount.
208 +config YAFFS_DISABLE_BLOCK_REFRESHING
209 + bool "Disable yaffs2 block refreshing"
210 + depends on YAFFS_FS
213 + If this is set, then block refreshing is disabled.
214 + Block refreshing infrequently refreshes the oldest block in
215 + a yaffs2 file system. This mechanism helps to refresh flash to
216 + mitigate against data loss. This is particularly useful for MLC.
220 +config YAFFS_DISABLE_BACKGROUND
221 + bool "Disable yaffs2 background processing"
222 + depends on YAFFS_FS
225 + If this is set, then background processing is disabled.
226 + Background processing makes many foreground activities faster.
231 + bool "Enable yaffs2 xattr support"
232 + depends on YAFFS_FS
235 + If this is set then yaffs2 will provide xattr support.
239 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/Makefile linux-2.6.36-rc8.new/fs/yaffs2/Makefile
240 --- linux-2.6.36-rc8/fs/yaffs2/Makefile 2010-10-20 13:17:58.937000294 +0300
241 +++ linux-2.6.36-rc8.new/fs/yaffs2/Makefile 2010-10-20 13:28:15.989000294 +0300
244 obj-$(CONFIG_YAFFS_FS) += yaffs.o
246 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
247 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
248 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
249 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
250 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
251 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
252 +yaffs-y += yaffs_nameval.o
253 +yaffs-y += yaffs_allocator.o
254 +yaffs-y += yaffs_yaffs1.o
255 +yaffs-y += yaffs_yaffs2.o
256 +yaffs-y += yaffs_bitmap.o
257 +yaffs-y += yaffs_verify.o
259 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/moduleconfig.h linux-2.6.36-rc8.new/fs/yaffs2/moduleconfig.h
260 --- linux-2.6.36-rc8/fs/yaffs2/moduleconfig.h 2010-10-20 13:17:58.938000294 +0300
261 +++ linux-2.6.36-rc8.new/fs/yaffs2/moduleconfig.h 2010-10-20 13:28:16.055000294 +0300
264 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
266 - * Copyright (C) 2002-2007 Aleph One Ltd.
267 + * Copyright (C) 2002-2010 Aleph One Ltd.
268 * for Toby Churchill Ltd and Brightstar Engineering
270 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
272 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
273 /* #define CONFIG_YAFFS_DOES_ECC */
275 +/* Default: Selected */
276 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
277 +#define CONFIG_YAFFS_DOES_TAGS_ECC
279 /* Default: Not selected */
280 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
281 /* CONFIG_YAFFS_DOES_ECC is set */
282 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
284 -/* Default: Selected */
285 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
286 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
287 +/* Default: Not selected */
288 +/* Meaning: Always test whether chunks are erased before writing to them.
289 + Use during mtd debugging and init. */
290 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
292 +/* Default: Not Selected */
293 +/* Meaning: At mount automatically empty all files from lost and found. */
294 +/* This is done to fix an old problem where rmdir was not checking for an */
295 +/* empty directory. This can also be achieved with a mount option. */
296 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
298 /* Default: Selected */
299 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
300 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
303 -/* Meaning: set the count of blocks to reserve for checkpointing */
304 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
305 +/* Default: Unselected */
306 +/* Meaning: Select to disable block refreshing. */
307 +/* Block Refreshing periodically rewrites the oldest block. */
308 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
310 +/* Default: Unselected */
311 +/* Meaning: Select to disable background processing */
312 +/* #define CONFIG_DISABLE_BACKGROUND */
315 +/* Default: Selected */
316 +/* Meaning: Enable XATTR support */
317 +#define CONFIG_YAFFS_XATTR
320 -Older-style on-NAND data format has a "pageStatus" byte to record
321 +Older-style on-NAND data format has a "page_status" byte to record
322 chunk/page state. This byte is zeroed when the page is discarded.
323 Choose this option if you have existing on-NAND data in this format
324 that you need to continue to support. New data written also uses the
325 @@ -57,7 +78,7 @@ adjusted to use the older-style format.
326 MTD versions in yaffs_mtdif1.c.
328 /* Default: Not selected */
329 -/* Meaning: Use older-style on-NAND data format with pageStatus byte */
330 +/* Meaning: Use older-style on-NAND data format with page_status byte */
331 /* #define CONFIG_YAFFS_9BYTE_TAGS */
333 #endif /* YAFFS_OUT_OF_TREE */
334 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.c
335 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.c 1970-01-01 02:00:00.000000000 +0200
336 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.c 2010-10-20 13:28:15.998000294 +0300
339 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
341 + * Copyright (C) 2002-2010 Aleph One Ltd.
342 + * for Toby Churchill Ltd and Brightstar Engineering
344 + * Created by Charles Manning <charles@aleph1.co.uk>
346 + * This program is free software; you can redistribute it and/or modify
347 + * it under the terms of the GNU Lesser General Public License version 2.1 as
348 + * published by the Free Software Foundation.
350 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
354 +#include "yaffs_allocator.h"
355 +#include "yaffs_guts.h"
356 +#include "yaffs_trace.h"
357 +#include "yportenv.h"
359 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
361 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
366 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
371 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
373 + return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
376 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
382 +void yaffs_init_raw_objs(yaffs_dev_t *dev)
387 +void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
392 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
395 + return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
399 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
408 +struct yaffs_tnode_list {
409 + struct yaffs_tnode_list *next;
410 + yaffs_tnode_t *tnodes;
413 +typedef struct yaffs_tnode_list yaffs_tnodelist_t;
415 +struct yaffs_obj_tList_struct {
416 + yaffs_obj_t *objects;
417 + struct yaffs_obj_tList_struct *next;
420 +typedef struct yaffs_obj_tList_struct yaffs_obj_tList;
423 +struct yaffs_AllocatorStruct {
424 + int n_tnodesCreated;
425 + yaffs_tnode_t *freeTnodes;
427 + yaffs_tnodelist_t *allocatedTnodeList;
430 + yaffs_obj_t *freeObjects;
433 + yaffs_obj_tList *allocatedObjectList;
436 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
439 +static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
442 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
444 + yaffs_tnodelist_t *tmp;
451 + while (allocator->allocatedTnodeList) {
452 + tmp = allocator->allocatedTnodeList->next;
454 + YFREE(allocator->allocatedTnodeList->tnodes);
455 + YFREE(allocator->allocatedTnodeList);
456 + allocator->allocatedTnodeList = tmp;
460 + allocator->freeTnodes = NULL;
461 + allocator->nFreeTnodes = 0;
462 + allocator->n_tnodesCreated = 0;
465 +static void yaffs_init_raw_tnodes(yaffs_dev_t *dev)
467 + yaffs_Allocator *allocator = dev->allocator;
470 + allocator->allocatedTnodeList = NULL;
471 + allocator->freeTnodes = NULL;
472 + allocator->nFreeTnodes = 0;
473 + allocator->n_tnodesCreated = 0;
478 +static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes)
480 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
482 + yaffs_tnode_t *newTnodes;
484 + yaffs_tnode_t *curr;
485 + yaffs_tnode_t *next;
486 + yaffs_tnodelist_t *tnl;
497 + /* make these things */
499 + newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
500 + mem = (__u8 *)newTnodes;
503 + T(YAFFS_TRACE_ERROR,
504 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
508 + /* New hookup for wide tnodes */
509 + for (i = 0; i < n_tnodes - 1; i++) {
510 + curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
511 + next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
512 + curr->internal[0] = next;
515 + curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
516 + curr->internal[0] = allocator->freeTnodes;
517 + allocator->freeTnodes = (yaffs_tnode_t *)mem;
519 + allocator->nFreeTnodes += n_tnodes;
520 + allocator->n_tnodesCreated += n_tnodes;
522 + /* Now add this bunch of tnodes to a list for freeing up.
523 + * NB If we can't add this to the management list it isn't fatal
524 + * but it just means we can't free this bunch of tnodes later.
527 + tnl = YMALLOC(sizeof(yaffs_tnodelist_t));
529 + T(YAFFS_TRACE_ERROR,
531 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
534 + tnl->tnodes = newTnodes;
535 + tnl->next = allocator->allocatedTnodeList;
536 + allocator->allocatedTnodeList = tnl;
539 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
545 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
547 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
548 + yaffs_tnode_t *tn = NULL;
555 + /* If there are none left make more */
556 + if (!allocator->freeTnodes)
557 + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
559 + if (allocator->freeTnodes) {
560 + tn = allocator->freeTnodes;
561 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
562 + allocator->nFreeTnodes--;
568 +/* FreeTnode frees up a tnode and puts it back on the free list */
569 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
571 + yaffs_Allocator *allocator = dev->allocator;
579 + tn->internal[0] = allocator->freeTnodes;
580 + allocator->freeTnodes = tn;
581 + allocator->nFreeTnodes++;
583 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
588 +static void yaffs_init_raw_objs(yaffs_dev_t *dev)
590 + yaffs_Allocator *allocator = dev->allocator;
593 + allocator->allocatedObjectList = NULL;
594 + allocator->freeObjects = NULL;
595 + allocator->nFreeObjects = 0;
600 +static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
602 + yaffs_Allocator *allocator = dev->allocator;
603 + yaffs_obj_tList *tmp;
610 + while (allocator->allocatedObjectList) {
611 + tmp = allocator->allocatedObjectList->next;
612 + YFREE(allocator->allocatedObjectList->objects);
613 + YFREE(allocator->allocatedObjectList);
615 + allocator->allocatedObjectList = tmp;
618 + allocator->freeObjects = NULL;
619 + allocator->nFreeObjects = 0;
620 + allocator->n_objCreated = 0;
624 +static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
626 + yaffs_Allocator *allocator = dev->allocator;
629 + yaffs_obj_t *newObjects;
630 + yaffs_obj_tList *list;
640 + /* make these things */
641 + newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
642 + list = YMALLOC(sizeof(yaffs_obj_tList));
644 + if (!newObjects || !list) {
653 + T(YAFFS_TRACE_ALLOCATE,
654 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
658 + /* Hook them into the free list */
659 + for (i = 0; i < n_obj - 1; i++) {
660 + newObjects[i].siblings.next =
661 + (struct ylist_head *)(&newObjects[i + 1]);
664 + newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
665 + allocator->freeObjects = newObjects;
666 + allocator->nFreeObjects += n_obj;
667 + allocator->n_objCreated += n_obj;
669 + /* Now add this bunch of Objects to a list for freeing up. */
671 + list->objects = newObjects;
672 + list->next = allocator->allocatedObjectList;
673 + allocator->allocatedObjectList = list;
678 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
680 + yaffs_obj_t *obj = NULL;
681 + yaffs_Allocator *allocator = dev->allocator;
688 + /* If there are none left make more */
689 + if (!allocator->freeObjects)
690 + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
692 + if (allocator->freeObjects) {
693 + obj = allocator->freeObjects;
694 + allocator->freeObjects =
695 + (yaffs_obj_t *) (allocator->freeObjects->siblings.next);
696 + allocator->nFreeObjects--;
703 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
706 + yaffs_Allocator *allocator = dev->allocator;
711 + /* Link into the free list. */
712 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
713 + allocator->freeObjects = obj;
714 + allocator->nFreeObjects++;
718 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
720 + if(dev->allocator){
721 + yaffs_deinit_raw_tnodes(dev);
722 + yaffs_deinit_raw_objs(dev);
724 + YFREE(dev->allocator);
725 + dev->allocator=NULL;
730 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
732 + yaffs_Allocator *allocator;
734 + if(!dev->allocator){
735 + allocator = YMALLOC(sizeof(yaffs_Allocator));
737 + dev->allocator = allocator;
738 + yaffs_init_raw_tnodes(dev);
739 + yaffs_init_raw_objs(dev);
747 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.h
748 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.h 1970-01-01 02:00:00.000000000 +0200
749 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.h 2010-10-20 13:28:16.058000294 +0300
752 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
754 + * Copyright (C) 2002-2010 Aleph One Ltd.
755 + * for Toby Churchill Ltd and Brightstar Engineering
757 + * Created by Charles Manning <charles@aleph1.co.uk>
759 + * This program is free software; you can redistribute it and/or modify
760 + * it under the terms of the GNU Lesser General Public License version 2.1 as
761 + * published by the Free Software Foundation.
763 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
766 +#ifndef __YAFFS_ALLOCATOR_H__
767 +#define __YAFFS_ALLOCATOR_H__
769 +#include "yaffs_guts.h"
771 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev);
772 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev);
774 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev);
775 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn);
777 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev);
778 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj);
781 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.c
782 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.c 1970-01-01 02:00:00.000000000 +0200
783 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.c 2010-10-20 13:28:15.998000294 +0300
786 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
788 + * Copyright (C) 2002-2010 Aleph One Ltd.
789 + * for Toby Churchill Ltd and Brightstar Engineering
791 + * Created by Charles Manning <charles@aleph1.co.uk>
793 + * This program is free software; you can redistribute it and/or modify
794 + * it under the terms of the GNU General Public License version 2 as
795 + * published by the Free Software Foundation.
798 +#include "yaffs_bitmap.h"
799 +#include "yaffs_trace.h"
801 + * Chunk bitmap manipulations
804 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_dev_t *dev, int blk)
806 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
807 + T(YAFFS_TRACE_ERROR,
808 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
812 + return dev->chunk_bits +
813 + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
816 +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk)
818 + if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
819 + chunk < 0 || chunk >= dev->param.chunks_per_block) {
820 + T(YAFFS_TRACE_ERROR,
821 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
827 +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk)
829 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
831 + memset(blkBits, 0, dev->chunk_bit_stride);
834 +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
836 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
838 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
840 + blkBits[chunk / 8] &= ~(1 << (chunk & 7));
843 +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
845 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
847 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
849 + blkBits[chunk / 8] |= (1 << (chunk & 7));
852 +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
854 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
855 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
857 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
860 +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk)
862 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
864 + for (i = 0; i < dev->chunk_bit_stride; i++) {
872 +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk)
874 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
877 + for (i = 0; i < dev->chunk_bit_stride; i++) {
890 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.h
891 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.h 1970-01-01 02:00:00.000000000 +0200
892 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.h 2010-10-20 13:28:16.058000294 +0300
895 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
897 + * Copyright (C) 2002-2010 Aleph One Ltd.
898 + * for Toby Churchill Ltd and Brightstar Engineering
900 + * Created by Charles Manning <charles@aleph1.co.uk>
902 + * This program is free software; you can redistribute it and/or modify
903 + * it under the terms of the GNU General Public License version 2 as
904 + * published by the Free Software Foundation.
908 + * Chunk bitmap manipulations
911 +#ifndef __YAFFS_BITMAP_H__
912 +#define __YAFFS_BITMAP_H__
914 +#include "yaffs_guts.h"
916 +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk);
917 +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk);
918 +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
919 +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
920 +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
921 +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk);
922 +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk);
925 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.c
926 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.c 2010-10-20 13:17:58.941000294 +0300
927 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.c 2010-10-20 13:28:15.999000294 +0300
930 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
932 - * Copyright (C) 2002-2007 Aleph One Ltd.
933 + * Copyright (C) 2002-2010 Aleph One Ltd.
934 * for Toby Churchill Ltd and Brightstar Engineering
936 * Created by Charles Manning <charles@aleph1.co.uk>
938 * published by the Free Software Foundation.
941 -const char *yaffs_checkptrw_c_version =
942 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
945 #include "yaffs_checkptrw.h"
946 #include "yaffs_getblockinfo.h"
948 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
949 +static int yaffs2_checkpt_space_ok(yaffs_dev_t *dev)
951 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
952 + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
954 T(YAFFS_TRACE_CHECKPOINT,
955 (TSTR("checkpt blocks available = %d" TENDSTR),
956 @@ -30,53 +26,56 @@ static int yaffs_CheckpointSpaceOk(yaffs
960 -static int yaffs_CheckpointErase(yaffs_Device *dev)
961 +static int yaffs_checkpt_erase(yaffs_dev_t *dev)
965 - if (!dev->eraseBlockInNAND)
966 + if (!dev->param.erase_fn)
968 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
969 - dev->internalStartBlock, dev->internalEndBlock));
970 + dev->internal_start_block, dev->internal_end_block));
972 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
973 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
974 - if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
975 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
976 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
977 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
978 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
979 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
980 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
981 - dev->nErasedBlocks++;
982 - dev->nFreeChunks += dev->nChunksPerBlock;
986 + if (dev->param.erase_fn(dev, i - dev->block_offset /* realign */)) {
987 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
988 + dev->n_erased_blocks++;
989 + dev->n_free_chunks += dev->param.chunks_per_block;
991 - dev->markNANDBlockBad(dev, i);
992 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
993 + dev->param.bad_block_fn(dev, i);
994 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
999 - dev->blocksInCheckpoint = 0;
1000 + dev->blocks_in_checkpt = 0;
1006 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
1007 +static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
1010 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
1011 + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
1012 T(YAFFS_TRACE_CHECKPOINT,
1013 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
1014 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
1015 + dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block));
1017 - if (dev->checkpointNextBlock >= 0 &&
1018 - dev->checkpointNextBlock <= dev->internalEndBlock &&
1019 + if (dev->checkpt_next_block >= 0 &&
1020 + dev->checkpt_next_block <= dev->internal_end_block &&
1021 blocksAvailable > 0) {
1023 - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
1024 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
1025 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
1026 - dev->checkpointNextBlock = i + 1;
1027 - dev->checkpointCurrentBlock = i;
1028 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
1029 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
1030 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
1031 + dev->checkpt_next_block = i + 1;
1032 + dev->checkpt_cur_block = i;
1033 T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
1036 @@ -84,34 +83,34 @@ static void yaffs_CheckpointFindNextEras
1038 T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
1040 - dev->checkpointNextBlock = -1;
1041 - dev->checkpointCurrentBlock = -1;
1042 + dev->checkpt_next_block = -1;
1043 + dev->checkpt_cur_block = -1;
1046 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
1047 +static void yaffs2_checkpt_find_block(yaffs_dev_t *dev)
1050 - yaffs_ExtendedTags tags;
1051 + yaffs_ext_tags tags;
1053 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
1054 - dev->blocksInCheckpoint, dev->checkpointNextBlock));
1055 + dev->blocks_in_checkpt, dev->checkpt_next_block));
1057 - if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
1058 - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
1059 - int chunk = i * dev->nChunksPerBlock;
1060 - int realignedChunk = chunk - dev->chunkOffset;
1061 + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
1062 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
1063 + int chunk = i * dev->param.chunks_per_block;
1064 + int realignedChunk = chunk - dev->chunk_offset;
1066 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
1067 + dev->param.read_chunk_tags_fn(dev, realignedChunk,
1069 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
1070 - i, tags.objectId, tags.sequenceNumber, tags.eccResult));
1071 + i, tags.obj_id, tags.seq_number, tags.ecc_result));
1073 - if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1074 + if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1075 /* Right kind of block */
1076 - dev->checkpointNextBlock = tags.objectId;
1077 - dev->checkpointCurrentBlock = i;
1078 - dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
1079 - dev->blocksInCheckpoint++;
1080 + dev->checkpt_next_block = tags.obj_id;
1081 + dev->checkpt_cur_block = i;
1082 + dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
1083 + dev->blocks_in_checkpt++;
1084 T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
1087 @@ -119,122 +118,127 @@ static void yaffs_CheckpointFindNextChec
1089 T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
1091 - dev->checkpointNextBlock = -1;
1092 - dev->checkpointCurrentBlock = -1;
1093 + dev->checkpt_next_block = -1;
1094 + dev->checkpt_cur_block = -1;
1098 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
1099 +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
1103 + dev->checkpt_open_write = forWriting;
1105 /* Got the functions we need? */
1106 - if (!dev->writeChunkWithTagsToNAND ||
1107 - !dev->readChunkWithTagsFromNAND ||
1108 - !dev->eraseBlockInNAND ||
1109 - !dev->markNANDBlockBad)
1110 + if (!dev->param.write_chunk_tags_fn ||
1111 + !dev->param.read_chunk_tags_fn ||
1112 + !dev->param.erase_fn ||
1113 + !dev->param.bad_block_fn)
1116 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
1117 + if (forWriting && !yaffs2_checkpt_space_ok(dev))
1120 - if (!dev->checkpointBuffer)
1121 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1122 - if (!dev->checkpointBuffer)
1123 + if (!dev->checkpt_buffer)
1124 + dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
1125 + if (!dev->checkpt_buffer)
1129 - dev->checkpointPageSequence = 0;
1131 - dev->checkpointOpenForWrite = forWriting;
1133 - dev->checkpointByteCount = 0;
1134 - dev->checkpointSum = 0;
1135 - dev->checkpointXor = 0;
1136 - dev->checkpointCurrentBlock = -1;
1137 - dev->checkpointCurrentChunk = -1;
1138 - dev->checkpointNextBlock = dev->internalStartBlock;
1139 + dev->checkpt_page_seq = 0;
1140 + dev->checkpt_byte_count = 0;
1141 + dev->checkpt_sum = 0;
1142 + dev->checkpt_xor = 0;
1143 + dev->checkpt_cur_block = -1;
1144 + dev->checkpt_cur_chunk = -1;
1145 + dev->checkpt_next_block = dev->internal_start_block;
1147 /* Erase all the blocks in the checkpoint area */
1149 - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1150 - dev->checkpointByteOffset = 0;
1151 - return yaffs_CheckpointErase(dev);
1152 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1153 + dev->checkpt_byte_offs = 0;
1154 + return yaffs_checkpt_erase(dev);
1157 /* Set to a value that will kick off a read */
1158 - dev->checkpointByteOffset = dev->nDataBytesPerChunk;
1159 + dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
1160 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
1161 * going to be way more than we need */
1162 - dev->blocksInCheckpoint = 0;
1163 - dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1164 - dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1165 - for (i = 0; i < dev->checkpointMaxBlocks; i++)
1166 - dev->checkpointBlockList[i] = -1;
1167 + dev->blocks_in_checkpt = 0;
1168 + dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2;
1169 + dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
1170 + if(!dev->checkpt_block_list)
1173 + for (i = 0; i < dev->checkpt_max_blocks; i++)
1174 + dev->checkpt_block_list[i] = -1;
1180 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1181 +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum)
1184 - compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1185 + compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
1186 *sum = compositeSum;
1190 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1191 +static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
1196 - yaffs_ExtendedTags tags;
1197 + yaffs_ext_tags tags;
1199 - if (dev->checkpointCurrentBlock < 0) {
1200 - yaffs_CheckpointFindNextErasedBlock(dev);
1201 - dev->checkpointCurrentChunk = 0;
1202 + if (dev->checkpt_cur_block < 0) {
1203 + yaffs2_checkpt_find_erased_block(dev);
1204 + dev->checkpt_cur_chunk = 0;
1207 - if (dev->checkpointCurrentBlock < 0)
1208 + if (dev->checkpt_cur_block < 0)
1211 - tags.chunkDeleted = 0;
1212 - tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
1213 - tags.chunkId = dev->checkpointPageSequence + 1;
1214 - tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1215 - tags.byteCount = dev->nDataBytesPerChunk;
1216 - if (dev->checkpointCurrentChunk == 0) {
1217 + tags.is_deleted = 0;
1218 + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
1219 + tags.chunk_id = dev->checkpt_page_seq + 1;
1220 + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1221 + tags.n_bytes = dev->data_bytes_per_chunk;
1222 + if (dev->checkpt_cur_chunk == 0) {
1223 /* First chunk we write for the block? Set block state to
1225 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
1226 - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1227 - dev->blocksInCheckpoint++;
1228 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block);
1229 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1230 + dev->blocks_in_checkpt++;
1233 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1234 + chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk;
1237 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1238 - chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
1239 + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id));
1241 - realignedChunk = chunk - dev->chunkOffset;
1242 + realignedChunk = chunk - dev->chunk_offset;
1244 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1245 - dev->checkpointBuffer, &tags);
1246 - dev->checkpointByteOffset = 0;
1247 - dev->checkpointPageSequence++;
1248 - dev->checkpointCurrentChunk++;
1249 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1250 - dev->checkpointCurrentChunk = 0;
1251 - dev->checkpointCurrentBlock = -1;
1252 + dev->n_page_writes++;
1254 + dev->param.write_chunk_tags_fn(dev, realignedChunk,
1255 + dev->checkpt_buffer, &tags);
1256 + dev->checkpt_byte_offs = 0;
1257 + dev->checkpt_page_seq++;
1258 + dev->checkpt_cur_chunk++;
1259 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
1260 + dev->checkpt_cur_chunk = 0;
1261 + dev->checkpt_cur_block = -1;
1263 - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1264 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1270 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1271 +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes)
1275 @@ -244,36 +248,36 @@ int yaffs_CheckpointWrite(yaffs_Device *
1279 - if (!dev->checkpointBuffer)
1280 + if (!dev->checkpt_buffer)
1283 - if (!dev->checkpointOpenForWrite)
1284 + if (!dev->checkpt_open_write)
1287 - while (i < nBytes && ok) {
1288 - dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
1289 - dev->checkpointSum += *dataBytes;
1290 - dev->checkpointXor ^= *dataBytes;
1291 + while (i < n_bytes && ok) {
1292 + dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes;
1293 + dev->checkpt_sum += *dataBytes;
1294 + dev->checkpt_xor ^= *dataBytes;
1296 - dev->checkpointByteOffset++;
1297 + dev->checkpt_byte_offs++;
1300 - dev->checkpointByteCount++;
1301 + dev->checkpt_byte_count++;
1304 - if (dev->checkpointByteOffset < 0 ||
1305 - dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1306 - ok = yaffs_CheckpointFlushBuffer(dev);
1307 + if (dev->checkpt_byte_offs < 0 ||
1308 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
1309 + ok = yaffs2_checkpt_flush_buffer(dev);
1315 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1316 +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes)
1320 - yaffs_ExtendedTags tags;
1321 + yaffs_ext_tags tags;
1325 @@ -281,113 +285,116 @@ int yaffs_CheckpointRead(yaffs_Device *d
1327 __u8 *dataBytes = (__u8 *)data;
1329 - if (!dev->checkpointBuffer)
1330 + if (!dev->checkpt_buffer)
1333 - if (dev->checkpointOpenForWrite)
1334 + if (dev->checkpt_open_write)
1337 - while (i < nBytes && ok) {
1338 + while (i < n_bytes && ok) {
1341 - if (dev->checkpointByteOffset < 0 ||
1342 - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1343 + if (dev->checkpt_byte_offs < 0 ||
1344 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
1346 - if (dev->checkpointCurrentBlock < 0) {
1347 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1348 - dev->checkpointCurrentChunk = 0;
1349 + if (dev->checkpt_cur_block < 0) {
1350 + yaffs2_checkpt_find_block(dev);
1351 + dev->checkpt_cur_chunk = 0;
1354 - if (dev->checkpointCurrentBlock < 0)
1355 + if (dev->checkpt_cur_block < 0)
1358 - chunk = dev->checkpointCurrentBlock *
1359 - dev->nChunksPerBlock +
1360 - dev->checkpointCurrentChunk;
1362 - realignedChunk = chunk - dev->chunkOffset;
1363 + chunk = dev->checkpt_cur_block *
1364 + dev->param.chunks_per_block +
1365 + dev->checkpt_cur_chunk;
1367 + realignedChunk = chunk - dev->chunk_offset;
1369 + dev->n_page_reads++;
1371 /* read in the next chunk */
1372 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1373 - dev->readChunkWithTagsFromNAND(dev,
1374 + dev->param.read_chunk_tags_fn(dev,
1376 - dev->checkpointBuffer,
1377 + dev->checkpt_buffer,
1380 - if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
1381 - tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
1382 - tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1383 + if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
1384 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
1385 + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1388 - dev->checkpointByteOffset = 0;
1389 - dev->checkpointPageSequence++;
1390 - dev->checkpointCurrentChunk++;
1391 + dev->checkpt_byte_offs = 0;
1392 + dev->checkpt_page_seq++;
1393 + dev->checkpt_cur_chunk++;
1395 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1396 - dev->checkpointCurrentBlock = -1;
1397 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
1398 + dev->checkpt_cur_block = -1;
1403 - *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
1404 - dev->checkpointSum += *dataBytes;
1405 - dev->checkpointXor ^= *dataBytes;
1406 - dev->checkpointByteOffset++;
1407 + *dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
1408 + dev->checkpt_sum += *dataBytes;
1409 + dev->checkpt_xor ^= *dataBytes;
1410 + dev->checkpt_byte_offs++;
1413 - dev->checkpointByteCount++;
1414 + dev->checkpt_byte_count++;
1421 -int yaffs_CheckpointClose(yaffs_Device *dev)
1422 +int yaffs_checkpt_close(yaffs_dev_t *dev)
1425 - if (dev->checkpointOpenForWrite) {
1426 - if (dev->checkpointByteOffset != 0)
1427 - yaffs_CheckpointFlushBuffer(dev);
1429 + if (dev->checkpt_open_write) {
1430 + if (dev->checkpt_byte_offs != 0)
1431 + yaffs2_checkpt_flush_buffer(dev);
1432 + } else if(dev->checkpt_block_list){
1434 - for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1435 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1436 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1437 - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1438 + for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) {
1439 + int blk = dev->checkpt_block_list[i];
1440 + yaffs_block_info_t *bi = NULL;
1441 + if( dev->internal_start_block <= blk && blk <= dev->internal_end_block)
1442 + bi = yaffs_get_block_info(dev, blk);
1443 + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
1444 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1446 /* Todo this looks odd... */
1449 - YFREE(dev->checkpointBlockList);
1450 - dev->checkpointBlockList = NULL;
1451 + YFREE(dev->checkpt_block_list);
1452 + dev->checkpt_block_list = NULL;
1455 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1456 - dev->nErasedBlocks -= dev->blocksInCheckpoint;
1457 + dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block;
1458 + dev->n_erased_blocks -= dev->blocks_in_checkpt;
1461 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
1462 - dev->checkpointByteCount));
1463 + dev->checkpt_byte_count));
1465 - if (dev->checkpointBuffer) {
1466 + if (dev->checkpt_buffer) {
1467 /* free the buffer */
1468 - YFREE(dev->checkpointBuffer);
1469 - dev->checkpointBuffer = NULL;
1470 + YFREE(dev->checkpt_buffer);
1471 + dev->checkpt_buffer = NULL;
1477 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1478 +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev)
1480 - /* Erase the first checksum block */
1482 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1483 + /* Erase the checkpoint data */
1485 - if (!yaffs_CheckpointSpaceOk(dev))
1487 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1488 + dev->blocks_in_checkpt));
1490 - return yaffs_CheckpointErase(dev);
1491 + return yaffs_checkpt_erase(dev);
1495 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.h
1496 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.h 2010-10-20 13:17:58.941000294 +0300
1497 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.h 2010-10-20 13:28:16.058000294 +0300
1500 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1502 - * Copyright (C) 2002-2007 Aleph One Ltd.
1503 + * Copyright (C) 2002-2010 Aleph One Ltd.
1504 * for Toby Churchill Ltd and Brightstar Engineering
1506 * Created by Charles Manning <charles@aleph1.co.uk>
1509 #include "yaffs_guts.h"
1511 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1512 +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting);
1514 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1515 +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes);
1517 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1518 +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes);
1520 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1521 +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum);
1523 -int yaffs_CheckpointClose(yaffs_Device *dev);
1524 +int yaffs_checkpt_close(yaffs_dev_t *dev);
1526 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1527 +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev);
1532 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.c
1533 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.c 2010-10-20 13:17:58.942000294 +0300
1534 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.c 2010-10-20 13:28:16.025000294 +0300
1537 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1539 - * Copyright (C) 2002-2007 Aleph One Ltd.
1540 + * Copyright (C) 2002-2010 Aleph One Ltd.
1541 * for Toby Churchill Ltd and Brightstar Engineering
1543 * Created by Charles Manning <charles@aleph1.co.uk>
1545 * this bytes influence on the line parity.
1548 -const char *yaffs_ecc_c_version =
1549 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1551 #include "yportenv.h"
1553 #include "yaffs_ecc.h"
1554 @@ -72,7 +69,7 @@ static const unsigned char column_parity
1556 /* Count the bits in an unsigned char or a U32 */
1558 -static int yaffs_CountBits(unsigned char x)
1559 +static int yaffs_count_bits(unsigned char x)
1563 @@ -83,7 +80,7 @@ static int yaffs_CountBits(unsigned char
1567 -static int yaffs_CountBits32(unsigned x)
1568 +static int yaffs_count_bits32(unsigned x)
1572 @@ -95,7 +92,7 @@ static int yaffs_CountBits32(unsigned x)
1575 /* Calculate the ECC for a 256-byte block of data */
1576 -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
1577 +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
1581 @@ -166,7 +163,7 @@ void yaffs_ECCCalculate(const unsigned c
1583 /* Correct the ECC on a 256 byte block of data */
1585 -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1586 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1587 const unsigned char *test_ecc)
1589 unsigned char d0, d1, d2; /* deltas */
1590 @@ -226,9 +223,9 @@ int yaffs_ECCCorrect(unsigned char *data
1591 return 1; /* Corrected the error */
1594 - if ((yaffs_CountBits(d0) +
1595 - yaffs_CountBits(d1) +
1596 - yaffs_CountBits(d2)) == 1) {
1597 + if ((yaffs_count_bits(d0) +
1598 + yaffs_count_bits(d1) +
1599 + yaffs_count_bits(d2)) == 1) {
1600 /* Reccoverable error in ecc */
1602 read_ecc[0] = test_ecc[0];
1603 @@ -248,7 +245,7 @@ int yaffs_ECCCorrect(unsigned char *data
1605 * ECCxxxOther does ECC calcs on arbitrary n bytes of data
1607 -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1608 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1609 yaffs_ECCOther *eccOther)
1612 @@ -258,7 +255,7 @@ void yaffs_ECCCalculateOther(const unsig
1613 unsigned line_parity_prime = 0;
1616 - for (i = 0; i < nBytes; i++) {
1617 + for (i = 0; i < n_bytes; i++) {
1618 b = column_parity_table[*data++];
1621 @@ -275,7 +272,7 @@ void yaffs_ECCCalculateOther(const unsig
1622 eccOther->lineParityPrime = line_parity_prime;
1625 -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1626 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1627 yaffs_ECCOther *read_ecc,
1628 const yaffs_ECCOther *test_ecc)
1630 @@ -304,7 +301,7 @@ int yaffs_ECCCorrectOther(unsigned char
1634 - if (lDelta >= nBytes)
1635 + if (lDelta >= n_bytes)
1638 data[lDelta] ^= (1 << bit);
1639 @@ -312,8 +309,8 @@ int yaffs_ECCCorrectOther(unsigned char
1640 return 1; /* corrected */
1643 - if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
1644 - yaffs_CountBits(cDelta)) == 1) {
1645 + if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) +
1646 + yaffs_count_bits(cDelta)) == 1) {
1647 /* Reccoverable error in ecc */
1649 *read_ecc = *test_ecc;
1650 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.h
1651 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.h 2010-10-20 13:17:58.942000294 +0300
1652 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.h 2010-10-20 13:28:16.058000294 +0300
1655 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1657 - * Copyright (C) 2002-2007 Aleph One Ltd.
1658 + * Copyright (C) 2002-2010 Aleph One Ltd.
1659 * for Toby Churchill Ltd and Brightstar Engineering
1661 * Created by Charles Manning <charles@aleph1.co.uk>
1662 @@ -32,13 +32,13 @@ typedef struct {
1663 unsigned lineParityPrime;
1666 -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
1667 -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1668 +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
1669 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1670 const unsigned char *test_ecc);
1672 -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1673 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1674 yaffs_ECCOther *ecc);
1675 -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1676 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1677 yaffs_ECCOther *read_ecc,
1678 const yaffs_ECCOther *test_ecc);
1680 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_fs.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_fs.c
1681 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_fs.c 2010-10-20 13:17:58.944000294 +0300
1682 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_fs.c 1970-01-01 02:00:00.000000000 +0200
1685 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1687 - * Copyright (C) 2002-2009 Aleph One Ltd.
1688 - * for Toby Churchill Ltd and Brightstar Engineering
1690 - * Created by Charles Manning <charles@aleph1.co.uk>
1691 - * Acknowledgements:
1692 - * Luc van OostenRyck for numerous patches.
1693 - * Nick Bane for numerous patches.
1694 - * Nick Bane for 2.5/2.6 integration.
1695 - * Andras Toth for mknod rdev issue.
1696 - * Michael Fischer for finding the problem with inode inconsistency.
1697 - * Some code bodily lifted from JFFS
1699 - * This program is free software; you can redistribute it and/or modify
1700 - * it under the terms of the GNU General Public License version 2 as
1701 - * published by the Free Software Foundation.
1706 - * This is the file system front-end to YAFFS that hooks it up to
1710 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1712 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1714 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1717 -const char *yaffs_fs_c_version =
1718 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1719 -extern const char *yaffs_guts_c_version;
1721 -#include <linux/version.h>
1722 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1723 -#include <linux/config.h>
1725 -#include <linux/kernel.h>
1726 -#include <linux/module.h>
1727 -#include <linux/slab.h>
1728 -#include <linux/init.h>
1729 -#include <linux/fs.h>
1730 -#include <linux/proc_fs.h>
1731 -#include <linux/smp_lock.h>
1732 -#include <linux/pagemap.h>
1733 -#include <linux/mtd/mtd.h>
1734 -#include <linux/interrupt.h>
1735 -#include <linux/string.h>
1736 -#include <linux/ctype.h>
1738 -#include "asm/div64.h"
1740 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1742 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1743 -#include <linux/statfs.h>
1744 -#define UnlockPage(p) unlock_page(p)
1745 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1747 -/* FIXME: use sb->s_id instead ? */
1748 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1752 -#include <linux/locks.h>
1753 -#define BDEVNAME_SIZE 0
1754 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1756 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1757 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1763 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1764 -#define YPROC_ROOT (&proc_root)
1766 -#define YPROC_ROOT NULL
1769 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1770 -#define WRITE_SIZE_STR "writesize"
1771 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1773 -#define WRITE_SIZE_STR "oobblock"
1774 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1777 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1778 -#define YAFFS_USE_WRITE_BEGIN_END 1
1780 -#define YAFFS_USE_WRITE_BEGIN_END 0
1783 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1784 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1786 - uint64_t result = partition_size;
1787 - do_div(result, block_size);
1788 - return (uint32_t)result;
1791 -#define YCALCBLOCKS(s, b) ((s)/(b))
1794 -#include <linux/uaccess.h>
1796 -#include "yportenv.h"
1797 -#include "yaffs_guts.h"
1799 -#include <linux/mtd/mtd.h>
1800 -#include "yaffs_mtdif.h"
1801 -#include "yaffs_mtdif1.h"
1802 -#include "yaffs_mtdif2.h"
1804 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1805 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1806 -unsigned int yaffs_auto_checkpoint = 1;
1808 -/* Module Parameters */
1809 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1810 -module_param(yaffs_traceMask, uint, 0644);
1811 -module_param(yaffs_wr_attempts, uint, 0644);
1812 -module_param(yaffs_auto_checkpoint, uint, 0644);
1814 -MODULE_PARM(yaffs_traceMask, "i");
1815 -MODULE_PARM(yaffs_wr_attempts, "i");
1816 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1819 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1820 -/* use iget and read_inode */
1821 -#define Y_IGET(sb, inum) iget((sb), (inum))
1822 -static void yaffs_read_inode(struct inode *inode);
1825 -/* Call local equivalent */
1826 -#define YAFFS_USE_OWN_IGET
1827 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1829 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1832 -/*#define T(x) printk x */
1834 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1835 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1837 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1840 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1841 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1843 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1844 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1846 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1849 -static void yaffs_put_super(struct super_block *sb);
1851 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1853 -static ssize_t yaffs_hold_space(struct file *f);
1854 -static void yaffs_release_space(struct file *f);
1856 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1857 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1859 -static int yaffs_file_flush(struct file *file);
1862 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1865 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1867 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1868 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1869 - struct nameidata *n);
1870 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1871 - struct nameidata *n);
1873 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1874 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1876 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1877 - struct dentry *dentry);
1878 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1879 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1880 - const char *symname);
1881 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1883 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1884 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1887 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1890 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1891 - struct inode *new_dir, struct dentry *new_dentry);
1892 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1894 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1895 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1896 -static void yaffs_write_super(struct super_block *sb);
1898 -static int yaffs_sync_fs(struct super_block *sb);
1899 -static int yaffs_write_super(struct super_block *sb);
1902 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1903 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1904 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1905 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1907 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1910 -#ifdef YAFFS_HAS_PUT_INODE
1911 -static void yaffs_put_inode(struct inode *inode);
1914 -static void yaffs_delete_inode(struct inode *);
1915 -static void yaffs_clear_inode(struct inode *);
1917 -static int yaffs_readpage(struct file *file, struct page *page);
1918 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1919 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1921 -static int yaffs_writepage(struct page *page);
1925 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1926 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1927 - loff_t pos, unsigned len, unsigned flags,
1928 - struct page **pagep, void **fsdata);
1929 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1930 - loff_t pos, unsigned len, unsigned copied,
1931 - struct page *pg, void *fsdadata);
1933 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1934 - unsigned offset, unsigned to);
1935 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1940 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1942 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1943 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1945 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1948 -static struct address_space_operations yaffs_file_address_operations = {
1949 - .readpage = yaffs_readpage,
1950 - .writepage = yaffs_writepage,
1951 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1952 - .write_begin = yaffs_write_begin,
1953 - .write_end = yaffs_write_end,
1955 - .prepare_write = yaffs_prepare_write,
1956 - .commit_write = yaffs_commit_write,
1960 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1961 -static const struct file_operations yaffs_file_operations = {
1962 - .read = do_sync_read,
1963 - .write = do_sync_write,
1964 - .aio_read = generic_file_aio_read,
1965 - .aio_write = generic_file_aio_write,
1966 - .mmap = generic_file_mmap,
1967 - .flush = yaffs_file_flush,
1968 - .fsync = yaffs_sync_object,
1969 - .splice_read = generic_file_splice_read,
1970 - .splice_write = generic_file_splice_write,
1971 - .llseek = generic_file_llseek,
1974 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1976 -static const struct file_operations yaffs_file_operations = {
1977 - .read = do_sync_read,
1978 - .write = do_sync_write,
1979 - .aio_read = generic_file_aio_read,
1980 - .aio_write = generic_file_aio_write,
1981 - .mmap = generic_file_mmap,
1982 - .flush = yaffs_file_flush,
1983 - .fsync = yaffs_sync_object,
1984 - .sendfile = generic_file_sendfile,
1989 -static const struct file_operations yaffs_file_operations = {
1990 - .read = generic_file_read,
1991 - .write = generic_file_write,
1992 - .mmap = generic_file_mmap,
1993 - .flush = yaffs_file_flush,
1994 - .fsync = yaffs_sync_object,
1995 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1996 - .sendfile = generic_file_sendfile,
2001 -static const struct inode_operations yaffs_file_inode_operations = {
2002 - .setattr = yaffs_setattr,
2005 -static const struct inode_operations yaffs_symlink_inode_operations = {
2006 - .readlink = yaffs_readlink,
2007 - .follow_link = yaffs_follow_link,
2008 - .setattr = yaffs_setattr,
2011 -static const struct inode_operations yaffs_dir_inode_operations = {
2012 - .create = yaffs_create,
2013 - .lookup = yaffs_lookup,
2014 - .link = yaffs_link,
2015 - .unlink = yaffs_unlink,
2016 - .symlink = yaffs_symlink,
2017 - .mkdir = yaffs_mkdir,
2018 - .rmdir = yaffs_unlink,
2019 - .mknod = yaffs_mknod,
2020 - .rename = yaffs_rename,
2021 - .setattr = yaffs_setattr,
2024 -static const struct file_operations yaffs_dir_operations = {
2025 - .read = generic_read_dir,
2026 - .readdir = yaffs_readdir,
2027 - .fsync = yaffs_sync_object,
2030 -static const struct super_operations yaffs_super_ops = {
2031 - .statfs = yaffs_statfs,
2033 -#ifndef YAFFS_USE_OWN_IGET
2034 - .read_inode = yaffs_read_inode,
2036 -#ifdef YAFFS_HAS_PUT_INODE
2037 - .put_inode = yaffs_put_inode,
2039 - .put_super = yaffs_put_super,
2040 - .delete_inode = yaffs_delete_inode,
2041 - .clear_inode = yaffs_clear_inode,
2042 - .sync_fs = yaffs_sync_fs,
2043 - .write_super = yaffs_write_super,
2046 -static void yaffs_GrossLock(yaffs_Device *dev)
2048 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
2049 - down(&dev->grossLock);
2050 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
2053 -static void yaffs_GrossUnlock(yaffs_Device *dev)
2055 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
2056 - up(&dev->grossLock);
2059 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
2062 - unsigned char *alias;
2065 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2067 - yaffs_GrossLock(dev);
2069 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
2071 - yaffs_GrossUnlock(dev);
2076 - ret = vfs_readlink(dentry, buffer, buflen, alias);
2081 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2082 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
2084 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
2087 - unsigned char *alias;
2089 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2091 - yaffs_GrossLock(dev);
2093 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
2095 - yaffs_GrossUnlock(dev);
2102 - ret = vfs_follow_link(nd, alias);
2105 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2106 - return ERR_PTR(ret);
2112 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2113 - yaffs_Object *obj);
2116 - * Lookup is used to find objects in the fs
2118 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2120 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
2121 - struct nameidata *n)
2123 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
2126 - yaffs_Object *obj;
2127 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
2129 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
2131 - yaffs_GrossLock(dev);
2134 - ("yaffs_lookup for %d:%s\n",
2135 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
2137 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
2138 - dentry->d_name.name);
2140 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
2142 - /* Can't hold gross lock when calling yaffs_get_inode() */
2143 - yaffs_GrossUnlock(dev);
2147 - ("yaffs_lookup found %d\n", obj->objectId));
2149 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2153 - ("yaffs_loookup dentry \n"));
2154 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
2155 - * d_add even if NULL inode */
2157 - /*dget(dentry); // try to solve directory bug */
2158 - d_add(dentry, inode);
2160 - /* return dentry; */
2166 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
2170 -/* added NCB for 2.5/6 compatability - forces add even if inode is
2171 - * NULL which creates dentry hash */
2172 - d_add(dentry, inode);
2178 -#ifdef YAFFS_HAS_PUT_INODE
2180 -/* For now put inode is just for debugging
2181 - * Put inode is called when the inode **structure** is put.
2183 -static void yaffs_put_inode(struct inode *inode)
2186 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
2187 - atomic_read(&inode->i_count)));
2192 -/* clear is called to tell the fs to release any per-inode data it holds */
2193 -static void yaffs_clear_inode(struct inode *inode)
2195 - yaffs_Object *obj;
2196 - yaffs_Device *dev;
2198 - obj = yaffs_InodeToObject(inode);
2201 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
2202 - atomic_read(&inode->i_count),
2203 - obj ? "object exists" : "null object"));
2207 - yaffs_GrossLock(dev);
2209 - /* Clear the association between the inode and
2210 - * the yaffs_Object.
2212 - obj->myInode = NULL;
2213 - yaffs_InodeToObjectLV(inode) = NULL;
2215 - /* If the object freeing was deferred, then the real
2216 - * free happens now.
2217 - * This should fix the inode inconsistency problem.
2220 - yaffs_HandleDeferedFree(obj);
2222 - yaffs_GrossUnlock(dev);
2227 -/* delete is called when the link count is zero and the inode
2228 - * is put (ie. nobody wants to know about it anymore, time to
2229 - * delete the file).
2230 - * NB Must call clear_inode()
2232 -static void yaffs_delete_inode(struct inode *inode)
2234 - yaffs_Object *obj = yaffs_InodeToObject(inode);
2235 - yaffs_Device *dev;
2238 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
2239 - atomic_read(&inode->i_count),
2240 - obj ? "object exists" : "null object"));
2244 - yaffs_GrossLock(dev);
2245 - yaffs_DeleteObject(obj);
2246 - yaffs_GrossUnlock(dev);
2248 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2249 - truncate_inode_pages(&inode->i_data, 0);
2251 - clear_inode(inode);
2254 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2255 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
2257 -static int yaffs_file_flush(struct file *file)
2260 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
2262 - yaffs_Device *dev = obj->myDev;
2265 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
2266 - obj->dirty ? "dirty" : "clean"));
2268 - yaffs_GrossLock(dev);
2270 - yaffs_FlushFile(obj, 1);
2272 - yaffs_GrossUnlock(dev);
2277 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
2279 - /* Lifted from jffs2 */
2281 - yaffs_Object *obj;
2282 - unsigned char *pg_buf;
2285 - yaffs_Device *dev;
2287 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
2288 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
2289 - (unsigned)PAGE_CACHE_SIZE));
2291 - obj = yaffs_DentryToObject(f->f_dentry);
2295 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2296 - BUG_ON(!PageLocked(pg));
2298 - if (!PageLocked(pg))
2302 - pg_buf = kmap(pg);
2303 - /* FIXME: Can kmap fail? */
2305 - yaffs_GrossLock(dev);
2307 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
2308 - pg->index << PAGE_CACHE_SHIFT,
2311 - yaffs_GrossUnlock(dev);
2317 - ClearPageUptodate(pg);
2320 - SetPageUptodate(pg);
2321 - ClearPageError(pg);
2324 - flush_dcache_page(pg);
2327 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
2331 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
2333 - int ret = yaffs_readpage_nolock(f, pg);
2338 -static int yaffs_readpage(struct file *f, struct page *pg)
2340 - return yaffs_readpage_unlock(f, pg);
2343 -/* writepage inspired by/stolen from smbfs */
2345 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2346 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
2348 -static int yaffs_writepage(struct page *page)
2351 - struct address_space *mapping = page->mapping;
2352 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
2353 - struct inode *inode;
2354 - unsigned long end_index;
2356 - yaffs_Object *obj;
2362 - inode = mapping->host;
2366 - if (offset > inode->i_size) {
2368 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
2369 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
2370 - (unsigned)inode->i_size));
2372 - (" -> don't care!!\n"));
2373 - unlock_page(page);
2377 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
2380 - if (page->index < end_index)
2381 - nBytes = PAGE_CACHE_SIZE;
2383 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
2387 - buffer = kmap(page);
2389 - obj = yaffs_InodeToObject(inode);
2390 - yaffs_GrossLock(obj->myDev);
2393 - ("yaffs_writepage at %08x, size %08x\n",
2394 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
2396 - ("writepag0: obj = %05x, ino = %05x\n",
2397 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2399 - nWritten = yaffs_WriteDataToFile(obj, buffer,
2400 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
2403 - ("writepag1: obj = %05x, ino = %05x\n",
2404 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2406 - yaffs_GrossUnlock(obj->myDev);
2409 - SetPageUptodate(page);
2413 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2417 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2418 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2419 - loff_t pos, unsigned len, unsigned flags,
2420 - struct page **pagep, void **fsdata)
2422 - struct page *pg = NULL;
2423 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2424 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2425 - uint32_t to = offset + len;
2428 - int space_held = 0;
2430 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2432 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2433 - pg = grab_cache_page_write_begin(mapping, index, flags);
2435 - pg = __grab_cache_page(mapping, index);
2443 - /* Get fs space */
2444 - space_held = yaffs_hold_space(filp);
2446 - if (!space_held) {
2451 - /* Update page if required */
2453 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2454 - ret = yaffs_readpage_nolock(filp, pg);
2459 - /* Happy path return */
2460 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2465 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2467 - yaffs_release_space(filp);
2470 - page_cache_release(pg);
2477 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2478 - unsigned offset, unsigned to)
2480 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2482 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2483 - return yaffs_readpage_nolock(f, pg);
2488 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2489 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2490 - loff_t pos, unsigned len, unsigned copied,
2491 - struct page *pg, void *fsdadata)
2495 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2498 - addr = kva + offset_into_page;
2501 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2503 - (int)pos, copied));
2505 - ret = yaffs_file_write(filp, addr, copied, &pos);
2507 - if (ret != copied) {
2509 - ("yaffs_write_end not same size ret %d copied %d\n",
2512 - ClearPageUptodate(pg);
2514 - SetPageUptodate(pg);
2519 - yaffs_release_space(filp);
2521 - page_cache_release(pg);
2526 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2531 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2532 - int nBytes = to - offset;
2535 - unsigned spos = pos;
2539 - addr = kva + offset;
2541 - saddr = (unsigned) addr;
2544 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2545 - saddr, spos, nBytes));
2547 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2549 - if (nWritten != nBytes) {
2551 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2552 - nWritten, nBytes));
2554 - ClearPageUptodate(pg);
2556 - SetPageUptodate(pg);
2562 - ("yaffs_commit_write returning %d\n",
2563 - nWritten == nBytes ? 0 : nWritten));
2565 - return nWritten == nBytes ? 0 : nWritten;
2570 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2572 - if (inode && obj) {
2575 - /* Check mode against the variant type and attempt to repair if broken. */
2576 - __u32 mode = obj->yst_mode;
2577 - switch (obj->variantType) {
2578 - case YAFFS_OBJECT_TYPE_FILE:
2579 - if (!S_ISREG(mode)) {
2580 - obj->yst_mode &= ~S_IFMT;
2581 - obj->yst_mode |= S_IFREG;
2585 - case YAFFS_OBJECT_TYPE_SYMLINK:
2586 - if (!S_ISLNK(mode)) {
2587 - obj->yst_mode &= ~S_IFMT;
2588 - obj->yst_mode |= S_IFLNK;
2592 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2593 - if (!S_ISDIR(mode)) {
2594 - obj->yst_mode &= ~S_IFMT;
2595 - obj->yst_mode |= S_IFDIR;
2599 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2600 - case YAFFS_OBJECT_TYPE_HARDLINK:
2601 - case YAFFS_OBJECT_TYPE_SPECIAL:
2607 - inode->i_flags |= S_NOATIME;
2609 - inode->i_ino = obj->objectId;
2610 - inode->i_mode = obj->yst_mode;
2611 - inode->i_uid = obj->yst_uid;
2612 - inode->i_gid = obj->yst_gid;
2613 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2614 - inode->i_blksize = inode->i_sb->s_blocksize;
2616 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2618 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2619 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2620 - inode->i_atime.tv_nsec = 0;
2621 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2622 - inode->i_mtime.tv_nsec = 0;
2623 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2624 - inode->i_ctime.tv_nsec = 0;
2626 - inode->i_rdev = obj->yst_rdev;
2627 - inode->i_atime = obj->yst_atime;
2628 - inode->i_mtime = obj->yst_mtime;
2629 - inode->i_ctime = obj->yst_ctime;
2631 - inode->i_size = yaffs_GetObjectFileLength(obj);
2632 - inode->i_blocks = (inode->i_size + 511) >> 9;
2634 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2637 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2638 - inode->i_mode, inode->i_uid, inode->i_gid,
2639 - (int)inode->i_size, atomic_read(&inode->i_count)));
2641 - switch (obj->yst_mode & S_IFMT) {
2642 - default: /* fifo, device or socket */
2643 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2644 - init_special_inode(inode, obj->yst_mode,
2645 - old_decode_dev(obj->yst_rdev));
2647 - init_special_inode(inode, obj->yst_mode,
2648 - (dev_t) (obj->yst_rdev));
2651 - case S_IFREG: /* file */
2652 - inode->i_op = &yaffs_file_inode_operations;
2653 - inode->i_fop = &yaffs_file_operations;
2654 - inode->i_mapping->a_ops =
2655 - &yaffs_file_address_operations;
2657 - case S_IFDIR: /* directory */
2658 - inode->i_op = &yaffs_dir_inode_operations;
2659 - inode->i_fop = &yaffs_dir_operations;
2661 - case S_IFLNK: /* symlink */
2662 - inode->i_op = &yaffs_symlink_inode_operations;
2666 - yaffs_InodeToObjectLV(inode) = obj;
2668 - obj->myInode = inode;
2672 - ("yaffs_FileInode invalid parameters\n"));
2677 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2678 - yaffs_Object *obj)
2680 - struct inode *inode;
2684 - ("yaffs_get_inode for NULL super_block!!\n"));
2691 - ("yaffs_get_inode for NULL object!!\n"));
2697 - ("yaffs_get_inode for object %d\n", obj->objectId));
2699 - inode = Y_IGET(sb, obj->objectId);
2700 - if (IS_ERR(inode))
2703 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2704 - /* iget also increments the inode's i_count */
2705 - /* NB You can't be holding grossLock or deadlock will happen! */
2710 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2713 - yaffs_Object *obj;
2714 - int nWritten, ipos;
2715 - struct inode *inode;
2716 - yaffs_Device *dev;
2718 - obj = yaffs_DentryToObject(f->f_dentry);
2722 - yaffs_GrossLock(dev);
2724 - inode = f->f_dentry->d_inode;
2726 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2727 - ipos = inode->i_size;
2733 - ("yaffs_file_write: hey obj is null!\n"));
2736 - ("yaffs_file_write about to write writing %zu bytes"
2737 - "to object %d at %d\n",
2738 - n, obj->objectId, ipos));
2740 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2743 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2744 - n, nWritten, ipos));
2746 - if (nWritten > 0) {
2749 - if (ipos > inode->i_size) {
2750 - inode->i_size = ipos;
2751 - inode->i_blocks = (ipos + 511) >> 9;
2754 - ("yaffs_file_write size updated to %d bytes, "
2756 - ipos, (int)(inode->i_blocks)));
2760 - yaffs_GrossUnlock(dev);
2761 - return nWritten == 0 ? -ENOSPC : nWritten;
2764 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2765 -/* For now we just assume few parallel writes and check against a small number. */
2766 -/* Todo: need to do this with a counter to handle parallel reads better */
2768 -static ssize_t yaffs_hold_space(struct file *f)
2770 - yaffs_Object *obj;
2771 - yaffs_Device *dev;
2776 - obj = yaffs_DentryToObject(f->f_dentry);
2780 - yaffs_GrossLock(dev);
2782 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2784 - yaffs_GrossUnlock(dev);
2786 - return (nFreeChunks > 20) ? 1 : 0;
2789 -static void yaffs_release_space(struct file *f)
2791 - yaffs_Object *obj;
2792 - yaffs_Device *dev;
2795 - obj = yaffs_DentryToObject(f->f_dentry);
2799 - yaffs_GrossLock(dev);
2802 - yaffs_GrossUnlock(dev);
2805 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2807 - yaffs_Object *obj;
2808 - yaffs_Device *dev;
2809 - struct inode *inode = f->f_dentry->d_inode;
2810 - unsigned long offset, curoffs;
2811 - struct ylist_head *i;
2814 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2816 - obj = yaffs_DentryToObject(f->f_dentry);
2819 - yaffs_GrossLock(dev);
2821 - offset = f->f_pos;
2823 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2825 - if (offset == 0) {
2827 - ("yaffs_readdir: entry . ino %d \n",
2828 - (int)inode->i_ino));
2829 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2834 - if (offset == 1) {
2836 - ("yaffs_readdir: entry .. ino %d \n",
2837 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2838 - if (filldir(dirent, "..", 2, offset,
2839 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2847 - /* If the directory has changed since the open or last call to
2848 - readdir, rewind to after the 2 canned entries. */
2850 - if (f->f_version != inode->i_version) {
2852 - f->f_pos = offset;
2853 - f->f_version = inode->i_version;
2856 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2858 - if (curoffs >= offset) {
2859 - l = ylist_entry(i, yaffs_Object, siblings);
2861 - yaffs_GetObjectName(l, name,
2862 - YAFFS_MAX_NAME_LENGTH + 1);
2864 - ("yaffs_readdir: %s inode %d\n", name,
2865 - yaffs_GetObjectInode(l)));
2867 - if (filldir(dirent,
2871 - yaffs_GetObjectInode(l),
2872 - yaffs_GetObjectType(l)) < 0)
2882 - yaffs_GrossUnlock(dev);
2888 - * File creation. Allocate an inode, and we're done..
2891 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2894 -#define YCRED(x) (x->cred)
2897 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2898 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2901 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2905 - struct inode *inode;
2907 - yaffs_Object *obj = NULL;
2908 - yaffs_Device *dev;
2910 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2912 - int error = -ENOSPC;
2913 - uid_t uid = YCRED(current)->fsuid;
2914 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2916 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2921 - ("yaffs_mknod: parent object %d type %d\n",
2922 - parent->objectId, parent->variantType));
2925 - ("yaffs_mknod: could not get parent object\n"));
2929 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2930 - "mode %x dev %x\n",
2931 - dentry->d_name.name, mode, rdev));
2933 - dev = parent->myDev;
2935 - yaffs_GrossLock(dev);
2937 - switch (mode & S_IFMT) {
2939 - /* Special (socket, fifo, device...) */
2940 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2941 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2942 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2943 - gid, old_encode_dev(rdev));
2945 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2949 - case S_IFREG: /* file */
2950 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2951 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2954 - case S_IFDIR: /* directory */
2956 - ("yaffs_mknod: making directory\n"));
2957 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2960 - case S_IFLNK: /* symlink */
2961 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2962 - obj = NULL; /* Do we ever get here? */
2966 - /* Can not call yaffs_get_inode() with gross lock held */
2967 - yaffs_GrossUnlock(dev);
2970 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2971 - d_instantiate(dentry, inode);
2973 - ("yaffs_mknod created object %d count = %d\n",
2974 - obj->objectId, atomic_read(&inode->i_count)));
2978 - ("yaffs_mknod failed making object\n"));
2985 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2988 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2989 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2993 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2994 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2995 - struct nameidata *n)
2997 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
3000 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
3001 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
3004 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
3008 - yaffs_Device *dev;
3011 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
3012 - dentry->d_name.name));
3014 - dev = yaffs_InodeToObject(dir)->myDev;
3016 - yaffs_GrossLock(dev);
3018 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
3020 - if (retVal == YAFFS_OK) {
3021 - dentry->d_inode->i_nlink--;
3023 - yaffs_GrossUnlock(dev);
3024 - mark_inode_dirty(dentry->d_inode);
3027 - yaffs_GrossUnlock(dev);
3028 - return -ENOTEMPTY;
3032 - * Create a link...
3034 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
3035 - struct dentry *dentry)
3037 - struct inode *inode = old_dentry->d_inode;
3038 - yaffs_Object *obj = NULL;
3039 - yaffs_Object *link = NULL;
3040 - yaffs_Device *dev;
3042 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
3044 - obj = yaffs_InodeToObject(inode);
3047 - yaffs_GrossLock(dev);
3049 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
3050 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
3054 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
3055 - d_instantiate(dentry, old_dentry->d_inode);
3056 - atomic_inc(&old_dentry->d_inode->i_count);
3058 - ("yaffs_link link count %d i_count %d\n",
3059 - old_dentry->d_inode->i_nlink,
3060 - atomic_read(&old_dentry->d_inode->i_count)));
3063 - yaffs_GrossUnlock(dev);
3071 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
3072 - const char *symname)
3074 - yaffs_Object *obj;
3075 - yaffs_Device *dev;
3076 - uid_t uid = YCRED(current)->fsuid;
3077 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
3079 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
3081 - dev = yaffs_InodeToObject(dir)->myDev;
3082 - yaffs_GrossLock(dev);
3083 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
3084 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
3085 - yaffs_GrossUnlock(dev);
3088 - struct inode *inode;
3090 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
3091 - d_instantiate(dentry, inode);
3092 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
3095 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
3101 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
3105 - yaffs_Object *obj;
3106 - yaffs_Device *dev;
3108 - obj = yaffs_DentryToObject(dentry);
3112 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
3113 - yaffs_GrossLock(dev);
3114 - yaffs_FlushFile(obj, 1);
3115 - yaffs_GrossUnlock(dev);
3120 - * The VFS layer already does all the dentry stuff for rename.
3122 - * NB: POSIX says you can rename an object over an old object of the same name
3124 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
3125 - struct inode *new_dir, struct dentry *new_dentry)
3127 - yaffs_Device *dev;
3128 - int retVal = YAFFS_FAIL;
3129 - yaffs_Object *target;
3131 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
3132 - dev = yaffs_InodeToObject(old_dir)->myDev;
3134 - yaffs_GrossLock(dev);
3136 - /* Check if the target is an existing directory that is not empty. */
3137 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
3138 - new_dentry->d_name.name);
3142 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
3143 - !ylist_empty(&target->variant.directoryVariant.children)) {
3145 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
3147 - retVal = YAFFS_FAIL;
3149 - /* Now does unlinking internally using shadowing mechanism */
3150 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
3152 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
3153 - old_dentry->d_name.name,
3154 - yaffs_InodeToObject(new_dir),
3155 - new_dentry->d_name.name);
3157 - yaffs_GrossUnlock(dev);
3159 - if (retVal == YAFFS_OK) {
3161 - new_dentry->d_inode->i_nlink--;
3162 - mark_inode_dirty(new_dentry->d_inode);
3167 - return -ENOTEMPTY;
3171 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
3173 - struct inode *inode = dentry->d_inode;
3175 - yaffs_Device *dev;
3178 - ("yaffs_setattr of object %d\n",
3179 - yaffs_InodeToObject(inode)->objectId));
3181 - error = inode_change_ok(inode, attr);
3183 - dev = yaffs_InodeToObject(inode)->myDev;
3184 - yaffs_GrossLock(dev);
3185 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
3191 - yaffs_GrossUnlock(dev);
3193 - error = inode_setattr(inode, attr);
3198 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3199 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
3201 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
3202 - struct super_block *sb = dentry->d_sb;
3203 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3204 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
3206 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3208 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
3210 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3213 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
3215 - yaffs_GrossLock(dev);
3217 - buf->f_type = YAFFS_MAGIC;
3218 - buf->f_bsize = sb->s_blocksize;
3219 - buf->f_namelen = 255;
3221 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
3222 - /* Do this if chunk size is not a power of 2 */
3224 - uint64_t bytesInDev;
3225 - uint64_t bytesFree;
3227 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
3228 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
3230 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
3231 - buf->f_blocks = bytesInDev;
3233 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
3234 - ((uint64_t)(dev->nDataBytesPerChunk));
3236 - do_div(bytesFree, sb->s_blocksize);
3238 - buf->f_bfree = bytesFree;
3240 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
3243 - (dev->endBlock - dev->startBlock + 1) *
3244 - dev->nChunksPerBlock /
3245 - (sb->s_blocksize / dev->nDataBytesPerChunk);
3247 - yaffs_GetNumberOfFreeChunks(dev) /
3248 - (sb->s_blocksize / dev->nDataBytesPerChunk);
3251 - (dev->endBlock - dev->startBlock + 1) *
3252 - dev->nChunksPerBlock *
3253 - (dev->nDataBytesPerChunk / sb->s_blocksize);
3256 - yaffs_GetNumberOfFreeChunks(dev) *
3257 - (dev->nDataBytesPerChunk / sb->s_blocksize);
3262 - buf->f_bavail = buf->f_bfree;
3264 - yaffs_GrossUnlock(dev);
3269 -static int yaffs_do_sync_fs(struct super_block *sb)
3272 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3273 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
3276 - yaffs_GrossLock(dev);
3279 - yaffs_FlushEntireDeviceCache(dev);
3280 - yaffs_CheckpointSave(dev);
3283 - yaffs_GrossUnlock(dev);
3291 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3292 -static void yaffs_write_super(struct super_block *sb)
3294 -static int yaffs_write_super(struct super_block *sb)
3298 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
3299 - if (yaffs_auto_checkpoint >= 2)
3300 - yaffs_do_sync_fs(sb);
3301 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
3307 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3308 -static int yaffs_sync_fs(struct super_block *sb, int wait)
3310 -static int yaffs_sync_fs(struct super_block *sb)
3313 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
3315 - if (yaffs_auto_checkpoint >= 1)
3316 - yaffs_do_sync_fs(sb);
3321 -#ifdef YAFFS_USE_OWN_IGET
3323 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
3325 - struct inode *inode;
3326 - yaffs_Object *obj;
3327 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3330 - ("yaffs_iget for %lu\n", ino));
3332 - inode = iget_locked(sb, ino);
3334 - return ERR_PTR(-ENOMEM);
3335 - if (!(inode->i_state & I_NEW))
3338 - /* NB This is called as a side effect of other functions, but
3339 - * we had to release the lock to prevent deadlocks, so
3340 - * need to lock again.
3343 - yaffs_GrossLock(dev);
3345 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
3347 - yaffs_FillInodeFromObject(inode, obj);
3349 - yaffs_GrossUnlock(dev);
3351 - unlock_new_inode(inode);
3357 -static void yaffs_read_inode(struct inode *inode)
3359 - /* NB This is called as a side effect of other functions, but
3360 - * we had to release the lock to prevent deadlocks, so
3361 - * need to lock again.
3364 - yaffs_Object *obj;
3365 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
3368 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
3370 - yaffs_GrossLock(dev);
3372 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
3374 - yaffs_FillInodeFromObject(inode, obj);
3376 - yaffs_GrossUnlock(dev);
3381 -static YLIST_HEAD(yaffs_dev_list);
3383 -#if 0 /* not used */
3384 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
3386 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3388 - if (*flags & MS_RDONLY) {
3389 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3392 - ("yaffs_remount_fs: %s: RO\n", dev->name));
3394 - yaffs_GrossLock(dev);
3396 - yaffs_FlushEntireDeviceCache(dev);
3398 - yaffs_CheckpointSave(dev);
3403 - yaffs_GrossUnlock(dev);
3406 - ("yaffs_remount_fs: %s: RW\n", dev->name));
3413 -static void yaffs_put_super(struct super_block *sb)
3415 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3417 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3419 - yaffs_GrossLock(dev);
3421 - yaffs_FlushEntireDeviceCache(dev);
3423 - yaffs_CheckpointSave(dev);
3425 - if (dev->putSuperFunc)
3426 - dev->putSuperFunc(sb);
3428 - yaffs_Deinitialise(dev);
3430 - yaffs_GrossUnlock(dev);
3432 - /* we assume this is protected by lock_kernel() in mount/umount */
3433 - ylist_del(&dev->devList);
3435 - if (dev->spareBuffer) {
3436 - YFREE(dev->spareBuffer);
3437 - dev->spareBuffer = NULL;
3444 -static void yaffs_MTDPutSuper(struct super_block *sb)
3446 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3451 - put_mtd_device(mtd);
3455 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3457 - struct super_block *sb = (struct super_block *)vsb;
3459 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3466 - int skip_checkpoint_read;
3467 - int skip_checkpoint_write;
3471 -#define MAX_OPT_LEN 20
3472 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3474 - char cur_opt[MAX_OPT_LEN + 1];
3478 - /* Parse through the options which is a comma seperated list */
3480 - while (options_str && *options_str && !error) {
3481 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3484 - while (*options_str && *options_str != ',') {
3485 - if (p < MAX_OPT_LEN) {
3486 - cur_opt[p] = *options_str;
3492 - if (!strcmp(cur_opt, "inband-tags"))
3493 - options->inband_tags = 1;
3494 - else if (!strcmp(cur_opt, "no-cache"))
3495 - options->no_cache = 1;
3496 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3497 - options->skip_checkpoint_read = 1;
3498 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3499 - options->skip_checkpoint_write = 1;
3500 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3501 - options->skip_checkpoint_read = 1;
3502 - options->skip_checkpoint_write = 1;
3504 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3513 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3514 - struct super_block *sb,
3515 - void *data, int silent)
3518 - struct inode *inode = NULL;
3519 - struct dentry *root;
3520 - yaffs_Device *dev = 0;
3521 - char devname_buf[BDEVNAME_SIZE + 1];
3522 - struct mtd_info *mtd;
3524 - char *data_str = (char *)data;
3526 - yaffs_options options;
3528 - sb->s_magic = YAFFS_MAGIC;
3529 - sb->s_op = &yaffs_super_ops;
3530 - sb->s_flags |= MS_NOATIME;
3533 - printk(KERN_INFO "yaffs: sb is NULL\n");
3534 - else if (!sb->s_dev)
3535 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3536 - else if (!yaffs_devname(sb, devname_buf))
3537 - printk(KERN_INFO "yaffs: devname is NULL\n");
3539 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3541 - yaffs_devname(sb, devname_buf));
3546 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3548 - memset(&options, 0, sizeof(options));
3550 - if (yaffs_parse_options(&options, data_str)) {
3551 - /* Option parsing failed */
3556 - sb->s_blocksize = PAGE_CACHE_SIZE;
3557 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3558 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3560 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3562 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3564 - ("yaffs: Write verification disabled. All guarantees "
3565 - "null and void\n"));
3568 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3570 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3571 - yaffs_devname(sb, devname_buf)));
3573 - /* Check it's an mtd device..... */
3574 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3575 - return NULL; /* This isn't an mtd device */
3577 - /* Get the device */
3578 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3580 - T(YAFFS_TRACE_ALWAYS,
3581 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3582 - MINOR(sb->s_dev)));
3585 - /* Check it's NAND */
3586 - if (mtd->type != MTD_NANDFLASH) {
3587 - T(YAFFS_TRACE_ALWAYS,
3588 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3592 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3593 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3594 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3595 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3596 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3597 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3598 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3599 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3600 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3601 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3602 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3603 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3605 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3608 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3610 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3611 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3615 - /* Added NCB 26/5/2006 for completeness */
3616 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3617 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3623 - if (yaffsVersion == 2) {
3624 - /* Check for version 2 style functions */
3625 - if (!mtd->erase ||
3626 - !mtd->block_isbad ||
3627 - !mtd->block_markbad ||
3630 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3631 - !mtd->read_oob || !mtd->write_oob) {
3633 - !mtd->write_ecc ||
3634 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3636 - T(YAFFS_TRACE_ALWAYS,
3637 - ("yaffs: MTD device does not support required "
3642 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3643 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3644 - !options.inband_tags) {
3645 - T(YAFFS_TRACE_ALWAYS,
3646 - ("yaffs: MTD device does not have the "
3647 - "right page sizes\n"));
3651 - /* Check for V1 style functions */
3652 - if (!mtd->erase ||
3655 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3656 - !mtd->read_oob || !mtd->write_oob) {
3658 - !mtd->write_ecc ||
3659 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3661 - T(YAFFS_TRACE_ALWAYS,
3662 - ("yaffs: MTD device does not support required "
3667 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3668 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3669 - T(YAFFS_TRACE_ALWAYS,
3670 - ("yaffs: MTD device does not support have the "
3671 - "right page sizes\n"));
3676 - /* OK, so if we got here, we have an MTD that's NAND and looks
3677 - * like it has the right capabilities
3678 - * Set the yaffs_Device up for mtd
3681 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3682 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3684 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3687 - /* Deep shit could not allocate device structure */
3688 - T(YAFFS_TRACE_ALWAYS,
3689 - ("yaffs_read_super: Failed trying to allocate "
3690 - "yaffs_Device. \n"));
3694 - memset(dev, 0, sizeof(yaffs_Device));
3695 - dev->genericDevice = mtd;
3696 - dev->name = mtd->name;
3698 - /* Set up the memory size parameters.... */
3700 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3702 - dev->startBlock = 0;
3703 - dev->endBlock = nBlocks - 1;
3704 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3705 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3706 - dev->nReservedBlocks = 5;
3707 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3708 - dev->inbandTags = options.inband_tags;
3710 - /* ... and the functions. */
3711 - if (yaffsVersion == 2) {
3712 - dev->writeChunkWithTagsToNAND =
3713 - nandmtd2_WriteChunkWithTagsToNAND;
3714 - dev->readChunkWithTagsFromNAND =
3715 - nandmtd2_ReadChunkWithTagsFromNAND;
3716 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3717 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3718 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3719 - dev->isYaffs2 = 1;
3720 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3721 - dev->totalBytesPerChunk = mtd->writesize;
3722 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3724 - dev->totalBytesPerChunk = mtd->oobblock;
3725 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3727 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3729 - dev->startBlock = 0;
3730 - dev->endBlock = nBlocks - 1;
3732 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3733 - /* use the MTD interface in yaffs_mtdif1.c */
3734 - dev->writeChunkWithTagsToNAND =
3735 - nandmtd1_WriteChunkWithTagsToNAND;
3736 - dev->readChunkWithTagsFromNAND =
3737 - nandmtd1_ReadChunkWithTagsFromNAND;
3738 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3739 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3741 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3742 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3744 - dev->isYaffs2 = 0;
3746 - /* ... and common functions */
3747 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3748 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3750 - dev->putSuperFunc = yaffs_MTDPutSuper;
3752 - dev->superBlock = (void *)sb;
3753 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3756 -#ifndef CONFIG_YAFFS_DOES_ECC
3757 - dev->useNANDECC = 1;
3760 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3761 - dev->wideTnodesDisabled = 1;
3764 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3765 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3767 - /* we assume this is protected by lock_kernel() in mount/umount */
3768 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3770 - init_MUTEX(&dev->grossLock);
3772 - yaffs_GrossLock(dev);
3774 - err = yaffs_GutsInitialise(dev);
3777 - ("yaffs_read_super: guts initialised %s\n",
3778 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3780 - /* Release lock before yaffs_get_inode() */
3781 - yaffs_GrossUnlock(dev);
3783 - /* Create root inode */
3784 - if (err == YAFFS_OK)
3785 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3791 - inode->i_op = &yaffs_dir_inode_operations;
3792 - inode->i_fop = &yaffs_dir_operations;
3794 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3796 - root = d_alloc_root(inode);
3798 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3804 - sb->s_root = root;
3805 - sb->s_dirt = !dev->isCheckpointed;
3806 - T(YAFFS_TRACE_ALWAYS,
3807 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3809 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3814 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3815 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3818 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3821 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3822 -static int yaffs_read_super(struct file_system_type *fs,
3823 - int flags, const char *dev_name,
3824 - void *data, struct vfsmount *mnt)
3827 - return get_sb_bdev(fs, flags, dev_name, data,
3828 - yaffs_internal_read_super_mtd, mnt);
3831 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3832 - int flags, const char *dev_name,
3836 - return get_sb_bdev(fs, flags, dev_name, data,
3837 - yaffs_internal_read_super_mtd);
3841 -static struct file_system_type yaffs_fs_type = {
3842 - .owner = THIS_MODULE,
3844 - .get_sb = yaffs_read_super,
3845 - .kill_sb = kill_block_super,
3846 - .fs_flags = FS_REQUIRES_DEV,
3849 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3852 - return yaffs_internal_read_super(1, sb, data, silent);
3855 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3860 -#ifdef CONFIG_YAFFS_YAFFS2
3862 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3863 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3866 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3869 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3870 -static int yaffs2_read_super(struct file_system_type *fs,
3871 - int flags, const char *dev_name, void *data,
3872 - struct vfsmount *mnt)
3874 - return get_sb_bdev(fs, flags, dev_name, data,
3875 - yaffs2_internal_read_super_mtd, mnt);
3878 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3879 - int flags, const char *dev_name,
3883 - return get_sb_bdev(fs, flags, dev_name, data,
3884 - yaffs2_internal_read_super_mtd);
3888 -static struct file_system_type yaffs2_fs_type = {
3889 - .owner = THIS_MODULE,
3891 - .get_sb = yaffs2_read_super,
3892 - .kill_sb = kill_block_super,
3893 - .fs_flags = FS_REQUIRES_DEV,
3896 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3897 - void *data, int silent)
3899 - return yaffs_internal_read_super(2, sb, data, silent);
3902 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3906 -#endif /* CONFIG_YAFFS_YAFFS2 */
3908 -static struct proc_dir_entry *my_proc_entry;
3910 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3912 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3913 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3914 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3915 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3916 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3917 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3918 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3919 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3920 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3921 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3922 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3923 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3924 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3925 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3926 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3927 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3928 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3929 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3930 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3931 - buf += sprintf(buf, "passiveGCs......... %d\n",
3932 - dev->passiveGarbageCollections);
3933 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3934 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3935 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3936 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3937 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3938 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3939 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3940 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3941 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3942 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3944 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3945 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3946 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3947 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3952 -static int yaffs_proc_read(char *page,
3954 - off_t offset, int count, int *eof, void *data)
3956 - struct ylist_head *item;
3958 - int step = offset;
3961 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3962 - * We use 'offset' (*ppos) to indicate where we are in devList.
3963 - * This also assumes the user has posted a read buffer large
3964 - * enough to hold the complete output; but that's life in /proc.
3967 - *(int *)start = 1;
3969 - /* Print header first */
3971 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3972 - "\n%s\n%s\n", yaffs_fs_c_version,
3973 - yaffs_guts_c_version);
3976 - /* hold lock_kernel while traversing yaffs_dev_list */
3979 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3980 - ylist_for_each(item, &yaffs_dev_list) {
3981 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3986 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3987 - buf = yaffs_dump_dev(buf, dev);
3992 - return buf - page < count ? buf - page : count;
3996 - * Set the verbosity of the warnings and error messages.
3998 - * Note that the names can only be a..z or _ with the current code.
4003 - unsigned mask_bitfield;
4005 - {"allocate", YAFFS_TRACE_ALLOCATE},
4006 - {"always", YAFFS_TRACE_ALWAYS},
4007 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
4008 - {"buffers", YAFFS_TRACE_BUFFERS},
4009 - {"bug", YAFFS_TRACE_BUG},
4010 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
4011 - {"deletion", YAFFS_TRACE_DELETION},
4012 - {"erase", YAFFS_TRACE_ERASE},
4013 - {"error", YAFFS_TRACE_ERROR},
4014 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
4015 - {"gc", YAFFS_TRACE_GC},
4016 - {"mtd", YAFFS_TRACE_MTD},
4017 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
4018 - {"os", YAFFS_TRACE_OS},
4019 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
4020 - {"scan", YAFFS_TRACE_SCAN},
4021 - {"tracing", YAFFS_TRACE_TRACING},
4023 - {"verify", YAFFS_TRACE_VERIFY},
4024 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
4025 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
4026 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
4028 - {"write", YAFFS_TRACE_WRITE},
4029 - {"all", 0xffffffff},
4034 -#define MAX_MASK_NAME_LENGTH 40
4035 -static int yaffs_proc_write(struct file *file, const char *buf,
4036 - unsigned long count, void *data)
4038 - unsigned rg = 0, mask_bitfield;
4042 - char substring[MAX_MASK_NAME_LENGTH + 1];
4048 - rg = yaffs_traceMask;
4050 - while (!done && (pos < count)) {
4052 - while ((pos < count) && isspace(buf[pos]))
4055 - switch (buf[pos]) {
4069 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
4071 - if (end > buf + pos) {
4072 - mask_name = "numeral";
4073 - len = end - (buf + pos);
4077 - for (x = buf + pos, i = 0;
4078 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
4079 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
4080 - substring[i] = *x;
4081 - substring[i] = '\0';
4083 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
4084 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
4085 - mask_name = mask_flags[i].mask_name;
4086 - mask_bitfield = mask_flags[i].mask_bitfield;
4093 - if (mask_name != NULL) {
4097 - rg &= ~mask_bitfield;
4100 - rg |= mask_bitfield;
4103 - rg = mask_bitfield;
4106 - rg |= mask_bitfield;
4112 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
4114 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
4116 - if (rg & YAFFS_TRACE_ALWAYS) {
4117 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
4119 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
4120 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
4127 -/* Stuff to handle installation of file systems */
4128 -struct file_system_to_install {
4129 - struct file_system_type *fst;
4133 -static struct file_system_to_install fs_to_install[] = {
4134 - {&yaffs_fs_type, 0},
4135 - {&yaffs2_fs_type, 0},
4139 -static int __init init_yaffs_fs(void)
4142 - struct file_system_to_install *fsinst;
4144 - T(YAFFS_TRACE_ALWAYS,
4145 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
4147 - /* Install the proc_fs entry */
4148 - my_proc_entry = create_proc_entry("yaffs",
4149 - S_IRUGO | S_IFREG,
4152 - if (my_proc_entry) {
4153 - my_proc_entry->write_proc = yaffs_proc_write;
4154 - my_proc_entry->read_proc = yaffs_proc_read;
4155 - my_proc_entry->data = NULL;
4159 - /* Now add the file system entries */
4161 - fsinst = fs_to_install;
4163 - while (fsinst->fst && !error) {
4164 - error = register_filesystem(fsinst->fst);
4166 - fsinst->installed = 1;
4170 - /* Any errors? uninstall */
4172 - fsinst = fs_to_install;
4174 - while (fsinst->fst) {
4175 - if (fsinst->installed) {
4176 - unregister_filesystem(fsinst->fst);
4177 - fsinst->installed = 0;
4186 -static void __exit exit_yaffs_fs(void)
4189 - struct file_system_to_install *fsinst;
4191 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
4192 - " removing. \n"));
4194 - remove_proc_entry("yaffs", YPROC_ROOT);
4196 - fsinst = fs_to_install;
4198 - while (fsinst->fst) {
4199 - if (fsinst->installed) {
4200 - unregister_filesystem(fsinst->fst);
4201 - fsinst->installed = 0;
4207 -module_init(init_yaffs_fs)
4208 -module_exit(exit_yaffs_fs)
4210 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
4211 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
4212 -MODULE_LICENSE("GPL");
4213 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_getblockinfo.h
4214 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_getblockinfo.h 2010-10-20 13:17:58.945000294 +0300
4215 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_getblockinfo.h 2010-10-20 13:28:16.058000294 +0300
4218 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
4220 - * Copyright (C) 2002-2007 Aleph One Ltd.
4221 + * Copyright (C) 2002-2010 Aleph One Ltd.
4222 * for Toby Churchill Ltd and Brightstar Engineering
4224 * Created by Charles Manning <charles@aleph1.co.uk>
4226 #define __YAFFS_GETBLOCKINFO_H__
4228 #include "yaffs_guts.h"
4229 +#include "yaffs_trace.h"
4231 /* Function to manipulate block info */
4232 -static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
4233 +static Y_INLINE yaffs_block_info_t *yaffs_get_block_info(yaffs_dev_t * dev, int blk)
4235 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4236 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
4237 T(YAFFS_TRACE_ERROR,
4239 ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
4243 - return &dev->blockInfo[blk - dev->internalStartBlock];
4244 + return &dev->block_info[blk - dev->internal_start_block];
4248 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.c
4249 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.c 2010-10-20 13:17:58.951000294 +0300
4250 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.c 2010-10-20 13:28:16.027000294 +0300
4253 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4255 - * Copyright (C) 2002-2007 Aleph One Ltd.
4256 + * Copyright (C) 2002-2010 Aleph One Ltd.
4257 * for Toby Churchill Ltd and Brightstar Engineering
4259 * Created by Charles Manning <charles@aleph1.co.uk>
4261 * it under the terms of the GNU General Public License version 2 as
4262 * published by the Free Software Foundation.
4265 -const char *yaffs_guts_c_version =
4266 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
4268 #include "yportenv.h"
4269 +#include "yaffs_trace.h"
4271 #include "yaffsinterface.h"
4272 #include "yaffs_guts.h"
4273 @@ -22,118 +19,109 @@ const char *yaffs_guts_c_version =
4274 #include "yaffs_getblockinfo.h"
4276 #include "yaffs_tagscompat.h"
4277 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
4278 -#include "yaffs_qsort.h"
4281 #include "yaffs_nand.h"
4283 -#include "yaffs_checkptrw.h"
4284 +#include "yaffs_yaffs1.h"
4285 +#include "yaffs_yaffs2.h"
4286 +#include "yaffs_bitmap.h"
4287 +#include "yaffs_verify.h"
4289 #include "yaffs_nand.h"
4290 #include "yaffs_packedtags2.h"
4292 +#include "yaffs_nameval.h"
4293 +#include "yaffs_allocator.h"
4295 -#define YAFFS_PASSIVE_GC_CHUNKS 2
4296 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
4297 +#define YAFFS_GC_GOOD_ENOUGH 2
4298 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
4300 #include "yaffs_ecc.h"
4304 /* Robustification (if it ever comes about...) */
4305 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
4306 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4307 +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block);
4308 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
4310 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4311 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
4313 - const yaffs_ExtendedTags *tags);
4314 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4315 - const yaffs_ExtendedTags *tags);
4316 + const yaffs_ext_tags *tags);
4317 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
4318 + const yaffs_ext_tags *tags);
4320 /* Other local prototypes */
4321 -static int yaffs_UnlinkObject(yaffs_Object *obj);
4322 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
4324 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
4325 +static void yaffs_update_parent(yaffs_obj_t *obj);
4326 +static int yaffs_unlink_obj(yaffs_obj_t *obj);
4327 +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj);
4329 -static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
4330 +static int yaffs_write_new_chunk(yaffs_dev_t *dev,
4332 - yaffs_ExtendedTags *tags,
4333 + yaffs_ext_tags *tags,
4335 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
4336 - int chunkInNAND, int inScan);
4338 -static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
4339 - yaffs_ObjectType type);
4340 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
4341 - yaffs_Object *obj);
4342 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
4343 - int force, int isShrink, int shadows);
4344 -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
4345 -static int yaffs_CheckStructures(void);
4346 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
4347 - int chunkOffset, int *limit);
4348 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
4350 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
4352 +static yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
4353 + yaffs_obj_type type);
4355 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4358 -static int yaffs_UnlinkWorker(yaffs_Object *obj);
4359 +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod);
4361 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
4362 - int chunkInObject);
4363 +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj);
4364 +static int yaffs_check_structures(void);
4365 +static int yaffs_generic_obj_del(yaffs_obj_t *in);
4367 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
4370 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
4371 - yaffs_BlockInfo **blockUsedPtr);
4372 +static int yaffs_unlink_worker(yaffs_obj_t *obj);
4374 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
4375 +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
4376 + int chunkInObject);
4378 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
4379 +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
4380 + yaffs_block_info_t **blockUsedPtr);
4382 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
4383 -#ifdef YAFFS_PARANOID
4384 -static int yaffs_CheckFileSanity(yaffs_Object *in);
4386 -#define yaffs_CheckFileSanity(in)
4388 +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in);
4390 +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in);
4391 +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id);
4393 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
4394 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
4395 +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
4396 + yaffs_ext_tags *tags);
4398 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
4399 +static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
4402 + yaffs_ext_tags *tags);
4404 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
4405 - yaffs_ExtendedTags *tags);
4407 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4409 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4410 - yaffs_FileStructure *fStruct,
4412 +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
4413 +static void yaffs_load_oh_from_name(yaffs_dev_t *dev,YCHAR *ohName, const YCHAR *name);
4416 /* Function to calculate chunk and offset */
4418 -static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
4419 +static void yaffs_addr_to_chunk(yaffs_dev_t *dev, loff_t addr, int *chunkOut,
4425 - chunk = (__u32)(addr >> dev->chunkShift);
4426 + chunk = (__u32)(addr >> dev->chunk_shift);
4428 - if (dev->chunkDiv == 1) {
4429 + if (dev->chunk_div == 1) {
4430 /* easy power of 2 case */
4431 - offset = (__u32)(addr & dev->chunkMask);
4432 + offset = (__u32)(addr & dev->chunk_mask);
4434 /* Non power-of-2 case */
4438 - chunk /= dev->chunkDiv;
4439 + chunk /= dev->chunk_div;
4441 - chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;
4442 + chunkBase = ((loff_t)chunk) * dev->data_bytes_per_chunk;
4443 offset = (__u32)(addr - chunkBase);
4446 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
4448 static __u32 Shifts(__u32 x)
4455 @@ -193,49 +181,49 @@ static __u32 Shifts(__u32 x)
4456 * Temporary buffer manipulations.
4459 -static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)
4460 +static int yaffs_init_tmp_buffers(yaffs_dev_t *dev)
4463 __u8 *buf = (__u8 *)1;
4465 - memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer));
4466 + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
4468 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
4469 - dev->tempBuffer[i].line = 0; /* not in use */
4470 - dev->tempBuffer[i].buffer = buf =
4471 - YMALLOC_DMA(dev->totalBytesPerChunk);
4472 + dev->temp_buffer[i].line = 0; /* not in use */
4473 + dev->temp_buffer[i].buffer = buf =
4474 + YMALLOC_DMA(dev->param.total_bytes_per_chunk);
4477 return buf ? YAFFS_OK : YAFFS_FAIL;
4480 -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo)
4481 +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no)
4486 - if (dev->tempInUse > dev->maxTemp)
4487 - dev->maxTemp = dev->tempInUse;
4488 + dev->temp_in_use++;
4489 + if (dev->temp_in_use > dev->max_temp)
4490 + dev->max_temp = dev->temp_in_use;
4492 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4493 - if (dev->tempBuffer[i].line == 0) {
4494 - dev->tempBuffer[i].line = lineNo;
4495 - if ((i + 1) > dev->maxTemp) {
4496 - dev->maxTemp = i + 1;
4497 + if (dev->temp_buffer[i].line == 0) {
4498 + dev->temp_buffer[i].line = line_no;
4499 + if ((i + 1) > dev->max_temp) {
4500 + dev->max_temp = i + 1;
4501 for (j = 0; j <= i; j++)
4502 - dev->tempBuffer[j].maxLine =
4503 - dev->tempBuffer[j].line;
4504 + dev->temp_buffer[j].max_line =
4505 + dev->temp_buffer[j].line;
4508 - return dev->tempBuffer[i].buffer;
4509 + return dev->temp_buffer[i].buffer;
4513 T(YAFFS_TRACE_BUFFERS,
4514 (TSTR("Out of temp buffers at line %d, other held by lines:"),
4517 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
4518 - T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
4519 + T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->temp_buffer[i].line));
4521 T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
4523 @@ -244,21 +232,21 @@ __u8 *yaffs_GetTempBuffer(yaffs_Device *
4527 - dev->unmanagedTempAllocations++;
4528 - return YMALLOC(dev->nDataBytesPerChunk);
4529 + dev->unmanaged_buffer_allocs++;
4530 + return YMALLOC(dev->data_bytes_per_chunk);
4534 -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer,
4536 +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer,
4542 + dev->temp_in_use--;
4544 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4545 - if (dev->tempBuffer[i].buffer == buffer) {
4546 - dev->tempBuffer[i].line = 0;
4547 + if (dev->temp_buffer[i].buffer == buffer) {
4548 + dev->temp_buffer[i].line = 0;
4552 @@ -267,9 +255,9 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic
4553 /* assume it is an unmanaged one. */
4554 T(YAFFS_TRACE_BUFFERS,
4555 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
4559 - dev->unmanagedTempDeallocations++;
4560 + dev->unmanaged_buffer_deallocs++;
4564 @@ -277,21 +265,21 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic
4566 * Determine if we have a managed buffer.
4568 -int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)
4569 +int yaffs_is_managed_tmp_buffer(yaffs_dev_t *dev, const __u8 *buffer)
4573 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4574 - if (dev->tempBuffer[i].buffer == buffer)
4575 + if (dev->temp_buffer[i].buffer == buffer)
4579 - for (i = 0; i < dev->nShortOpCaches; i++) {
4580 - if (dev->srCache[i].data == buffer)
4581 + for (i = 0; i < dev->param.n_caches; i++) {
4582 + if (dev->cache[i].data == buffer)
4586 - if (buffer == dev->checkpointBuffer)
4587 + if (buffer == dev->checkpt_buffer)
4590 T(YAFFS_TRACE_ALWAYS,
4591 @@ -299,6397 +287,4205 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
4598 - * Chunk bitmap manipulations
4599 + * Verification code
4602 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
4604 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4605 - T(YAFFS_TRACE_ERROR,
4606 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4610 - return dev->chunkBits +
4611 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4614 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4616 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4617 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4618 - T(YAFFS_TRACE_ERROR,
4619 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4625 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4627 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4629 - memset(blkBits, 0, dev->chunkBitmapStride);
4632 + * Simple hash function. Needs to have a reasonable spread
4635 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4636 +static Y_INLINE int yaffs_hash_fn(int n)
4638 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4640 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4642 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4644 + return n % YAFFS_NOBJECT_BUCKETS;
4647 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4649 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4651 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4653 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4656 + * Access functions to useful fake objects.
4657 + * Note that root might have a presence in NAND if permissions are set.
4660 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4661 +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev)
4663 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4664 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4666 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4667 + return dev->root_dir;
4670 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4671 +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev)
4673 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4675 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4681 + return dev->lost_n_found;
4684 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4686 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4689 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4690 - __u8 x = *blkBits;
4703 - * Verification code
4704 + * Erased NAND checking functions
4707 -static int yaffs_SkipVerification(yaffs_Device *dev)
4709 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4712 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4714 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4717 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4718 +int yaffs_check_ff(__u8 *buffer, int n_bytes)
4720 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4721 + /* Horrible, slow implementation */
4722 + while (n_bytes--) {
4723 + if (*buffer != 0xFF)
4730 -static const char *blockStateName[] = {
4743 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4744 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
4749 + int retval = YAFFS_OK;
4750 + __u8 *data = yaffs_get_temp_buffer(dev, __LINE__);
4751 + yaffs_ext_tags tags;
4754 - if (yaffs_SkipVerification(dev))
4756 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
4758 - /* Report illegal runtime states */
4759 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4760 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4761 + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
4762 + retval = YAFFS_FAIL;
4764 - switch (bi->blockState) {
4765 - case YAFFS_BLOCK_STATE_UNKNOWN:
4766 - case YAFFS_BLOCK_STATE_SCANNING:
4767 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4768 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4769 - n, blockStateName[bi->blockState]));
4770 + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || tags.chunk_used) {
4771 + T(YAFFS_TRACE_NANDACCESS,
4772 + (TSTR("Chunk %d not erased" TENDSTR), nand_chunk));
4773 + retval = YAFFS_FAIL;
4776 - /* Check pages in use and soft deletions are legal */
4778 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4780 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4781 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4782 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4783 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4784 - n, bi->pagesInUse, bi->softDeletions));
4786 + yaffs_release_temp_buffer(dev, data, __LINE__);
4788 - /* Check chunk bitmap legal */
4789 - inUse = yaffs_CountChunkBits(dev, n);
4790 - if (inUse != bi->pagesInUse)
4791 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4792 - n, bi->pagesInUse, inUse));
4795 - /* Check that the sequence number is valid.
4796 - * Ten million is legal, but is very unlikely
4798 - if (dev->isYaffs2 &&
4799 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4800 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4801 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4802 - n, bi->sequenceNumber));
4805 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4808 +static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
4811 + yaffs_ext_tags *tags)
4813 - yaffs_VerifyBlock(dev, bi, n);
4814 + int retval = YAFFS_OK;
4815 + yaffs_ext_tags tempTags;
4816 + __u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__);
4819 + result = yaffs_rd_chunk_tags_nand(dev,nand_chunk,buffer,&tempTags);
4820 + if(memcmp(buffer,data,dev->data_bytes_per_chunk) ||
4821 + tempTags.obj_id != tags->obj_id ||
4822 + tempTags.chunk_id != tags->chunk_id ||
4823 + tempTags.n_bytes != tags->n_bytes)
4824 + retval = YAFFS_FAIL;
4826 - /* After collection the block should be in the erased state */
4827 - /* This will need to change if we do partial gc */
4828 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
4830 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4831 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4832 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4833 - n, bi->blockState));
4838 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4839 +static int yaffs_write_new_chunk(struct yaffs_dev_s *dev,
4841 + yaffs_ext_tags *tags,
4845 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4846 - int nIllegalBlockStates = 0;
4848 - if (yaffs_SkipVerification(dev))
4851 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4853 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4854 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4855 - yaffs_VerifyBlock(dev, bi, i);
4857 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4858 - nBlocksPerState[bi->blockState]++;
4860 - nIllegalBlockStates++;
4866 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4867 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4868 + yaffs2_checkpt_invalidate(dev);
4870 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4871 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4872 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4874 + yaffs_block_info_t *bi = 0;
4877 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4878 - T(YAFFS_TRACE_VERIFY,
4879 - (TSTR("%s %d blocks"TENDSTR),
4880 - blockStateName[i], nBlocksPerState[i]));
4881 + chunk = yaffs_alloc_chunk(dev, useReserve, &bi);
4887 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4888 - T(YAFFS_TRACE_VERIFY,
4889 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4890 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4891 + /* First check this chunk is erased, if it needs
4892 + * checking. The checking policy (unless forced
4893 + * always on) is as follows:
4895 + * Check the first page we try to write in a block.
4896 + * If the check passes then we don't need to check any
4897 + * more. If the check fails, we check again...
4898 + * If the block has been erased, we don't need to check.
4900 + * However, if the block has been prioritised for gc,
4901 + * then we think there might be something odd about
4902 + * this block and stop using it.
4904 + * Rationale: We should only ever see chunks that have
4905 + * not been erased if there was a partially written
4906 + * chunk due to power loss. This checking policy should
4907 + * catch that case with very few checks and thus save a
4908 + * lot of checks that are most likely not needed.
4910 + * Mods to the above
4911 + * If an erase check fails or the write fails we skip the
4912 + * rest of the block.
4915 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4916 - T(YAFFS_TRACE_VERIFY,
4917 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4918 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4919 + /* let's give it a try */
4922 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4923 - T(YAFFS_TRACE_VERIFY,
4924 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4925 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4926 + if(dev->param.always_check_erased)
4927 + bi->skip_erased_check = 0;
4929 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4930 + if (!bi->skip_erased_check) {
4931 + erasedOk = yaffs_check_chunk_erased(dev, chunk);
4932 + if (erasedOk != YAFFS_OK) {
4933 + T(YAFFS_TRACE_ERROR,
4934 + (TSTR("**>> yaffs chunk %d was not erased"
4935 + TENDSTR), chunk));
4938 + /* If not erased, delete this one,
4939 + * skip rest of block and
4940 + * try another chunk */
4941 + yaffs_chunk_del(dev,chunk,1,__LINE__);
4942 + yaffs_skip_rest_of_block(dev);
4948 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4949 - * case those tests will not be performed.
4951 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4953 - if (obj && yaffs_SkipVerification(obj->myDev))
4955 + writeOk = yaffs_wr_chunk_tags_nand(dev, chunk,
4958 - if (!(tags && obj && oh)) {
4959 - T(YAFFS_TRACE_VERIFY,
4960 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4961 - (__u32)tags, (__u32)obj, (__u32)oh));
4964 + if(!bi->skip_erased_check)
4965 + writeOk = yaffs_verify_chunk_written(dev, chunk, data, tags);
4967 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4968 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4969 - T(YAFFS_TRACE_VERIFY,
4970 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4971 - tags->objectId, oh->type));
4972 + if (writeOk != YAFFS_OK) {
4973 + /* Clean up aborted write, skip to next block and
4974 + * try another chunk */
4975 + yaffs_handle_chunk_wr_error(dev, chunk, erasedOk);
4979 - if (tags->objectId != obj->objectId)
4980 - T(YAFFS_TRACE_VERIFY,
4981 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4982 - tags->objectId, obj->objectId));
4983 + bi->skip_erased_check = 1;
4985 + /* Copy the data into the robustification buffer */
4986 + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
4989 - * Check that the object's parent ids match if parentCheck requested.
4991 - * Tests do not apply to the root object.
4993 + } while (writeOk != YAFFS_OK &&
4994 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4996 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4997 - T(YAFFS_TRACE_VERIFY,
4998 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4999 - tags->objectId, oh->parentObjectId));
5003 - if (parentCheck && obj->parent &&
5004 - oh->parentObjectId != obj->parent->objectId &&
5005 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
5006 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
5007 - T(YAFFS_TRACE_VERIFY,
5008 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
5009 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
5010 + if (attempts > 1) {
5011 + T(YAFFS_TRACE_ERROR,
5012 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5015 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
5016 - T(YAFFS_TRACE_VERIFY,
5017 - (TSTR("Obj %d header name is NULL"TENDSTR),
5019 + dev->n_retired_writes += (attempts - 1);
5022 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
5023 - T(YAFFS_TRACE_VERIFY,
5024 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
5032 + * Block retiring for handling a broken block.
5035 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
5036 - __u32 level, int chunkOffset)
5037 +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block)
5040 - yaffs_Device *dev = obj->myDev;
5042 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
5046 + yaffs2_checkpt_invalidate(dev);
5048 + yaffs2_clear_oldest_dirty_seq(dev,bi);
5050 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
5051 - if (tn->internal[i]) {
5052 - ok = yaffs_VerifyTnodeWorker(obj,
5055 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
5058 - } else if (level == 0) {
5059 - yaffs_ExtendedTags tags;
5060 - __u32 objectId = obj->objectId;
5061 + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
5062 + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
5063 + T(YAFFS_TRACE_ALWAYS, (TSTR(
5064 + "yaffs: Failed to mark bad and erase block %d"
5065 + TENDSTR), flash_block));
5067 + yaffs_ext_tags tags;
5068 + int chunk_id = flash_block * dev->param.chunks_per_block;
5070 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
5071 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
5073 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
5074 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5075 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
5076 + yaffs_init_tags(&tags);
5077 + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
5078 + if (dev->param.write_chunk_tags_fn(dev, chunk_id -
5079 + dev->chunk_offset, buffer, &tags) != YAFFS_OK)
5080 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5081 + TCONT("write bad block marker to block %d")
5082 + TENDSTR), flash_block));
5084 - if (theChunk > 0) {
5085 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
5086 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
5087 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
5088 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
5089 - objectId, chunkOffset, theChunk,
5090 - tags.objectId, tags.chunkId));
5095 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
5100 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
5101 + bi->gc_prioritise = 0;
5102 + bi->needs_retiring = 0;
5104 + dev->n_retired_blocks++;
5108 + * Functions for robustisizing TODO
5112 -static void yaffs_VerifyFile(yaffs_Object *obj)
5113 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
5115 + const yaffs_ext_tags *tags)
5117 - int requiredTallness;
5118 - int actualTallness;
5122 - yaffs_Device *dev;
5123 - yaffs_ExtendedTags tags;
5127 + nand_chunk=nand_chunk;
5134 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
5135 + const yaffs_ext_tags *tags)
5138 + nand_chunk=nand_chunk;
5142 - if (yaffs_SkipVerification(obj->myDev))
5144 +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi)
5146 + if (!bi->gc_prioritise) {
5147 + bi->gc_prioritise = 1;
5148 + dev->has_pending_prioritised_gc = 1;
5149 + bi->chunk_error_strikes++;
5152 - objectId = obj->objectId;
5153 + if (bi->chunk_error_strikes > 3) {
5154 + bi->needs_retiring = 1; /* Too many stikes, so retire this */
5155 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5157 - /* Check file size is consistent with tnode depth */
5158 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
5159 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
5160 - requiredTallness = 0;
5162 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5163 - requiredTallness++;
5168 - actualTallness = obj->variant.fileVariant.topLevel;
5169 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
5172 + int flash_block = nand_chunk / dev->param.chunks_per_block;
5173 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
5175 - if (requiredTallness > actualTallness)
5176 - T(YAFFS_TRACE_VERIFY,
5177 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
5178 - obj->objectId, actualTallness, requiredTallness));
5179 + yaffs_handle_chunk_error(dev, bi);
5182 + /* Was an actual write failure, so mark the block for retirement */
5183 + bi->needs_retiring = 1;
5184 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5185 + (TSTR("**>> Block %d needs retiring" TENDSTR), flash_block));
5188 - /* Check that the chunks in the tnode tree are all correct.
5189 - * We do this by scanning through the tnode tree and
5190 - * checking the tags for every chunk match.
5192 + /* Delete the chunk */
5193 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
5194 + yaffs_skip_rest_of_block(dev);
5197 - if (yaffs_SkipNANDVerification(dev))
5200 - for (i = 1; i <= lastChunk; i++) {
5201 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
5202 +/*---------------- Name handling functions ------------*/
5205 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5206 - if (theChunk > 0) {
5207 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
5208 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
5209 - if (tags.objectId != objectId || tags.chunkId != i) {
5210 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
5211 - objectId, i, theChunk,
5212 - tags.objectId, tags.chunkId));
5215 +static __u16 yaffs_calc_name_sum(const YCHAR *name)
5220 + const YUCHAR *bname = (const YUCHAR *) name;
5222 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5224 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5225 + sum += yaffs_toupper(*bname) * i;
5227 + sum += (*bname) * i;
5237 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
5238 +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name)
5240 - if (obj && yaffs_SkipVerification(obj->myDev))
5243 - /* Verify sane equivalent object */
5244 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5245 + memset(obj->short_name, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5246 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
5247 + yaffs_strcpy(obj->short_name, name);
5249 + obj->short_name[0] = _Y('\0');
5251 + obj->sum = yaffs_calc_name_sum(name);
5254 -static void yaffs_VerifySymlink(yaffs_Object *obj)
5255 +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh)
5257 - if (obj && yaffs_SkipVerification(obj->myDev))
5260 - /* Verify symlink string */
5261 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
5262 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
5263 + memset(tmpName,0,sizeof(tmpName));
5264 + yaffs_load_name_from_oh(obj->my_dev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
5265 + yaffs_set_obj_name(obj,tmpName);
5267 + yaffs_set_obj_name(obj,oh->name);
5271 -static void yaffs_VerifySpecial(yaffs_Object *obj)
5273 - if (obj && yaffs_SkipVerification(obj->myDev))
5277 -static void yaffs_VerifyObject(yaffs_Object *obj)
5279 - yaffs_Device *dev;
5285 - __u32 chunkInRange;
5286 - __u32 chunkShouldNotBeDeleted;
5292 - if (obj->beingCreated)
5294 +/*-------------------- TNODES -------------------
5297 + * List of spare tnodes
5298 + * The list is hooked together using the first pointer
5302 - if (yaffs_SkipVerification(dev))
5305 - /* Check sane object header chunk */
5306 +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev)
5308 + yaffs_tnode_t *tn = yaffs_alloc_raw_tnode(dev);
5310 + memset(tn, 0, dev->tnode_size);
5314 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
5315 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
5316 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
5318 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
5319 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
5320 - chunkValid = chunkInRange &&
5321 - yaffs_CheckChunkBit(dev,
5322 - obj->hdrChunk / dev->nChunksPerBlock,
5323 - obj->hdrChunk % dev->nChunksPerBlock);
5324 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
5329 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
5330 - T(YAFFS_TRACE_VERIFY,
5331 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
5332 - obj->objectId, obj->hdrChunk,
5333 - chunkIdOk ? "" : ",out of range",
5334 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
5336 +/* FreeTnode frees up a tnode and puts it back on the free list */
5337 +static void yaffs_free_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
5339 + yaffs_free_raw_tnode(dev,tn);
5341 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
5344 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
5345 - yaffs_ExtendedTags tags;
5346 - yaffs_ObjectHeader *oh;
5347 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5348 +static void yaffs_deinit_tnodes_and_objs(yaffs_dev_t *dev)
5350 + yaffs_deinit_raw_tnodes_and_objs(dev);
5352 + dev->n_tnodes = 0;
5355 - oh = (yaffs_ObjectHeader *)buffer;
5357 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
5359 +void yaffs_load_tnode_0(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos,
5362 + __u32 *map = (__u32 *)tn;
5368 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
5369 + pos &= YAFFS_TNODES_LEVEL0_MASK;
5370 + val >>= dev->chunk_grp_bits;
5372 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5374 + bitInMap = pos * dev->tnode_width;
5375 + wordInMap = bitInMap / 32;
5376 + bitInWord = bitInMap & (32 - 1);
5378 - /* Verify it has a parent */
5379 - if (obj && !obj->fake &&
5380 - (!obj->parent || obj->parent->myDev != dev)) {
5381 - T(YAFFS_TRACE_VERIFY,
5382 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
5383 - obj->objectId, obj->parent));
5385 + mask = dev->tnode_mask << bitInWord;
5387 - /* Verify parent is a directory */
5388 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
5389 - T(YAFFS_TRACE_VERIFY,
5390 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
5391 - obj->objectId, obj->parent->variantType));
5393 + map[wordInMap] &= ~mask;
5394 + map[wordInMap] |= (mask & (val << bitInWord));
5396 - switch (obj->variantType) {
5397 - case YAFFS_OBJECT_TYPE_FILE:
5398 - yaffs_VerifyFile(obj);
5400 - case YAFFS_OBJECT_TYPE_SYMLINK:
5401 - yaffs_VerifySymlink(obj);
5403 - case YAFFS_OBJECT_TYPE_DIRECTORY:
5404 - yaffs_VerifyDirectory(obj);
5406 - case YAFFS_OBJECT_TYPE_HARDLINK:
5407 - yaffs_VerifyHardLink(obj);
5409 - case YAFFS_OBJECT_TYPE_SPECIAL:
5410 - yaffs_VerifySpecial(obj);
5412 - case YAFFS_OBJECT_TYPE_UNKNOWN:
5414 - T(YAFFS_TRACE_VERIFY,
5415 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
5416 - obj->objectId, obj->variantType));
5418 + if (dev->tnode_width > (32 - bitInWord)) {
5419 + bitInWord = (32 - bitInWord);
5421 + mask = dev->tnode_mask >> (/*dev->tnode_width -*/ bitInWord);
5422 + map[wordInMap] &= ~mask;
5423 + map[wordInMap] |= (mask & (val >> bitInWord));
5427 -static void yaffs_VerifyObjects(yaffs_Device *dev)
5428 +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn,
5431 - yaffs_Object *obj;
5433 - struct ylist_head *lh;
5434 + __u32 *map = (__u32 *)tn;
5440 - if (yaffs_SkipVerification(dev))
5442 + pos &= YAFFS_TNODES_LEVEL0_MASK;
5444 - /* Iterate through the objects in each hash entry */
5445 + bitInMap = pos * dev->tnode_width;
5446 + wordInMap = bitInMap / 32;
5447 + bitInWord = bitInMap & (32 - 1);
5449 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
5450 - ylist_for_each(lh, &dev->objectBucket[i].list) {
5452 - obj = ylist_entry(lh, yaffs_Object, hashLink);
5453 - yaffs_VerifyObject(obj);
5458 + val = map[wordInMap] >> bitInWord;
5460 + if (dev->tnode_width > (32 - bitInWord)) {
5461 + bitInWord = (32 - bitInWord);
5463 + val |= (map[wordInMap] << bitInWord);
5467 - * Simple hash function. Needs to have a reasonable spread
5469 + val &= dev->tnode_mask;
5470 + val <<= dev->chunk_grp_bits;
5472 -static Y_INLINE int yaffs_HashFunction(int n)
5475 - return n % YAFFS_NOBJECT_BUCKETS;
5480 - * Access functions to useful fake objects.
5481 - * Note that root might have a presence in NAND if permissions are set.
5482 +/* ------------------- End of individual tnode manipulation -----------------*/
5484 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5485 + * The look up tree is represented by the top tnode and the number of top_level
5486 + * in the tree. 0 means only the level 0 tnode is in the tree.
5489 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
5490 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5491 +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
5492 + yaffs_file_s *file_struct,
5495 - return dev->rootDir;
5497 + yaffs_tnode_t *tn = file_struct->top;
5499 + int requiredTallness;
5500 + int level = file_struct->top_level;
5502 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
5504 - return dev->lostNFoundDir;
5508 + /* Check sane level and chunk Id */
5509 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5513 - * Erased NAND checking functions
5515 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
5518 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
5520 - /* Horrible, slow implementation */
5521 - while (nBytes--) {
5522 - if (*buffer != 0xFF)
5525 + /* First check we're tall enough (ie enough top_level) */
5527 + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
5528 + requiredTallness = 0;
5530 + i >>= YAFFS_TNODES_INTERNAL_BITS;
5531 + requiredTallness++;
5536 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
5539 - int retval = YAFFS_OK;
5540 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
5541 - yaffs_ExtendedTags tags;
5543 + if (requiredTallness > file_struct->top_level)
5544 + return NULL; /* Not tall enough, so we can't find it */
5546 + /* Traverse down to level 0 */
5547 + while (level > 0 && tn) {
5548 + tn = tn->internal[(chunk_id >>
5549 + (YAFFS_TNODES_LEVEL0_BITS +
5551 + YAFFS_TNODES_INTERNAL_BITS)) &
5552 + YAFFS_TNODES_INTERNAL_MASK];
5556 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
5560 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
5561 - retval = YAFFS_FAIL;
5562 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5563 + * This happens in two steps:
5564 + * 1. If the tree isn't tall enough, then make it taller.
5565 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5567 + * Used when modifying the tree.
5569 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5570 + * be plugged into the ttree.
5573 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
5574 - T(YAFFS_TRACE_NANDACCESS,
5575 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
5576 - retval = YAFFS_FAIL;
5578 +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
5579 + yaffs_file_s *file_struct,
5581 + yaffs_tnode_t *passed_tn)
5583 + int requiredTallness;
5586 + yaffs_tnode_t *tn;
5588 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
5594 + /* Check sane level and page Id */
5595 + if (file_struct->top_level < 0 || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
5598 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
5600 - yaffs_ExtendedTags *tags,
5606 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
5609 - yaffs_InvalidateCheckpoint(dev);
5610 + /* First check we're tall enough (ie enough top_level) */
5613 - yaffs_BlockInfo *bi = 0;
5615 + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
5616 + requiredTallness = 0;
5618 + x >>= YAFFS_TNODES_INTERNAL_BITS;
5619 + requiredTallness++;
5622 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5628 - /* First check this chunk is erased, if it needs
5629 - * checking. The checking policy (unless forced
5630 - * always on) is as follows:
5632 - * Check the first page we try to write in a block.
5633 - * If the check passes then we don't need to check any
5634 - * more. If the check fails, we check again...
5635 - * If the block has been erased, we don't need to check.
5637 - * However, if the block has been prioritised for gc,
5638 - * then we think there might be something odd about
5639 - * this block and stop using it.
5641 - * Rationale: We should only ever see chunks that have
5642 - * not been erased if there was a partially written
5643 - * chunk due to power loss. This checking policy should
5644 - * catch that case with very few checks and thus save a
5645 - * lot of checks that are most likely not needed.
5647 - if (bi->gcPrioritise) {
5648 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5649 - /* try another chunk */
5652 + if (requiredTallness > file_struct->top_level) {
5653 + /* Not tall enough, gotta make the tree taller */
5654 + for (i = file_struct->top_level; i < requiredTallness; i++) {
5656 - /* let's give it a try */
5658 + tn = yaffs_get_tnode(dev);
5660 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5661 - bi->skipErasedCheck = 0;
5663 - if (!bi->skipErasedCheck) {
5664 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5665 - if (erasedOk != YAFFS_OK) {
5667 + tn->internal[0] = file_struct->top;
5668 + file_struct->top = tn;
5669 + file_struct->top_level++;
5671 T(YAFFS_TRACE_ERROR,
5672 - (TSTR("**>> yaffs chunk %d was not erased"
5673 - TENDSTR), chunk));
5675 - /* try another chunk */
5677 + (TSTR("yaffs: no more tnodes" TENDSTR)));
5680 - bi->skipErasedCheck = 1;
5684 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5686 - if (writeOk != YAFFS_OK) {
5687 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5688 - /* try another chunk */
5691 + /* Traverse down to level 0, adding anything we need */
5693 - /* Copy the data into the robustification buffer */
5694 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5695 + l = file_struct->top_level;
5696 + tn = file_struct->top;
5698 - } while (writeOk != YAFFS_OK &&
5699 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5701 + while (l > 0 && tn) {
5703 + (YAFFS_TNODES_LEVEL0_BITS +
5704 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5705 + YAFFS_TNODES_INTERNAL_MASK;
5710 - if (attempts > 1) {
5711 - T(YAFFS_TRACE_ERROR,
5712 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5714 + if ((l > 1) && !tn->internal[x]) {
5715 + /* Add missing non-level-zero tnode */
5716 + tn->internal[x] = yaffs_get_tnode(dev);
5717 + if(!tn->internal[x])
5719 + } else if (l == 1) {
5720 + /* Looking from level 1 at level 0 */
5722 + /* If we already have one, then release it.*/
5723 + if (tn->internal[x])
5724 + yaffs_free_tnode(dev, tn->internal[x]);
5725 + tn->internal[x] = passed_tn;
5727 + } else if (!tn->internal[x]) {
5728 + /* Don't have one, none passed in */
5729 + tn->internal[x] = yaffs_get_tnode(dev);
5730 + if(!tn->internal[x])
5735 - dev->nRetriedWrites += (attempts - 1);
5736 + tn = tn->internal[x];
5740 + /* top is level 0 */
5742 + memcpy(tn, passed_tn, (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8);
5743 + yaffs_free_tnode(dev, passed_tn);
5752 - * Block retiring for handling a broken block.
5755 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5756 +static int yaffs_find_chunk_in_group(yaffs_dev_t *dev, int theChunk,
5757 + yaffs_ext_tags *tags, int obj_id,
5760 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5763 - yaffs_InvalidateCheckpoint(dev);
5764 + for (j = 0; theChunk && j < dev->chunk_grp_size; j++) {
5765 + if (yaffs_check_chunk_bit(dev, theChunk / dev->param.chunks_per_block,
5766 + theChunk % dev->param.chunks_per_block)) {
5768 + if(dev->chunk_grp_size == 1)
5771 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL,
5773 + if (yaffs_tags_match(tags, obj_id, inode_chunk)) {
5784 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5785 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5786 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5787 - "yaffs: Failed to mark bad and erase block %d"
5788 - TENDSTR), blockInNAND));
5790 - yaffs_ExtendedTags tags;
5791 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5793 +/* Experimental code not being used yet. Might speed up file deletion */
5794 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
5795 + * chunks and tnodes in the file.
5796 + * Returns 1 if the tree was deleted.
5797 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5800 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5801 +static int yaffs_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, __u32 level,
5802 + int chunk_offset, int *limit)
5807 + yaffs_ext_tags tags;
5809 + yaffs_dev_t *dev = in->my_dev;
5811 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5812 - yaffs_InitialiseTags(&tags);
5813 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5814 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5815 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5816 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5817 - TCONT("write bad block marker to block %d")
5818 - TENDSTR), blockInNAND));
5821 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5826 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5828 + if (tn->internal[i]) {
5829 + if (limit && (*limit) < 0) {
5833 + yaffs_del_worker(in,
5841 + YAFFS_TNODES_INTERNAL_BITS)
5846 + yaffs_free_tnode(dev,
5849 + tn->internal[i] = NULL;
5853 + return (allDone) ? 1 : 0;
5854 + } else if (level == 0) {
5857 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5858 - bi->gcPrioritise = 0;
5859 - bi->needsRetiring = 0;
5860 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5862 + theChunk = yaffs_get_group_base(dev, tn, i);
5865 - dev->nRetiredBlocks++;
5867 + inode_chunk = (chunk_offset <<
5868 + YAFFS_TNODES_LEVEL0_BITS) + i;
5871 - * Functions for robustisizing TODO
5875 + yaffs_find_chunk_in_group(dev,
5881 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5883 - const yaffs_ExtendedTags *tags)
5886 + if (foundChunk > 0) {
5887 + yaffs_chunk_del(dev,
5890 + in->n_data_chunks--;
5892 + *limit = *limit - 1;
5897 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5898 - const yaffs_ExtendedTags *tags)
5903 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5905 - if (!bi->gcPrioritise) {
5906 - bi->gcPrioritise = 1;
5907 - dev->hasPendingPrioritisedGCs = 1;
5908 - bi->chunkErrorStrikes++;
5909 + yaffs_load_tnode_0(dev, tn, i, 0);
5912 - if (bi->chunkErrorStrikes > 3) {
5913 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5914 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5916 + return (i < 0) ? 1 : 0;
5926 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5930 +static void yaffs_soft_del_chunk(yaffs_dev_t *dev, int chunk)
5932 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5933 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5934 + yaffs_block_info_t *theBlock;
5935 + unsigned block_no;
5937 - yaffs_HandleChunkError(dev, bi);
5938 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5941 - /* Was an actual write failure, so mark the block for retirement */
5942 - bi->needsRetiring = 1;
5943 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5944 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5945 + block_no = chunk / dev->param.chunks_per_block;
5946 + theBlock = yaffs_get_block_info(dev, block_no);
5948 + theBlock->soft_del_pages++;
5949 + dev->n_free_chunks++;
5950 + yaffs2_update_oldest_dirty_seq(dev, block_no, theBlock);
5953 - /* Delete the chunk */
5954 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5957 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5958 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5960 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5963 -/*---------------- Name handling functions ------------*/
5965 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5966 +static int yaffs_soft_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
5967 + __u32 level, int chunk_offset)
5974 + yaffs_dev_t *dev = in->my_dev;
5976 - const YUCHAR *bname = (const YUCHAR *) name;
5978 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5982 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5984 + if (tn->internal[i]) {
5986 + yaffs_soft_del_worker(in,
5992 + YAFFS_TNODES_INTERNAL_BITS)
5995 + yaffs_free_tnode(dev,
5998 + tn->internal[i] = NULL;
6000 + /* Hoosterman... how could this happen? */
6004 + return (allDone) ? 1 : 0;
6005 + } else if (level == 0) {
6007 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
6008 + theChunk = yaffs_get_group_base(dev, tn, i);
6010 + /* Note this does not find the real chunk, only the chunk group.
6011 + * We make an assumption that a chunk group is not larger than
6014 + yaffs_soft_del_chunk(dev, theChunk);
6015 + yaffs_load_tnode_0(dev, tn, i, 0);
6021 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6022 - sum += yaffs_toupper(*bname) * i;
6024 - sum += (*bname) * i;
6037 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
6038 +static void yaffs_soft_del_file(yaffs_obj_t *obj)
6040 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
6041 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
6042 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
6043 - yaffs_strcpy(obj->shortName, name);
6045 - obj->shortName[0] = _Y('\0');
6047 - obj->sum = yaffs_CalcNameSum(name);
6048 + if (obj->deleted &&
6049 + obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) {
6050 + if (obj->n_data_chunks <= 0) {
6051 + /* Empty file with no duplicate object headers, just delete it immediately */
6052 + yaffs_free_tnode(obj->my_dev,
6053 + obj->variant.file_variant.top);
6054 + obj->variant.file_variant.top = NULL;
6055 + T(YAFFS_TRACE_TRACING,
6056 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
6058 + yaffs_generic_obj_del(obj);
6060 + yaffs_soft_del_worker(obj,
6061 + obj->variant.file_variant.top,
6062 + obj->variant.file_variant.
6064 + obj->soft_del = 1;
6069 -/*-------------------- TNODES -------------------
6071 - * List of spare tnodes
6072 - * The list is hooked together using the first pointer
6076 -/* yaffs_CreateTnodes creates a bunch more tnodes and
6077 - * adds them to the tnode free list.
6078 - * Don't use this function directly
6079 +/* Pruning removes any part of the file structure tree that is beyond the
6080 + * bounds of the file (ie that does not point to chunks).
6082 + * A file should only get pruned when its size is reduced.
6084 + * Before pruning, the chunks must be pulled from the tree and the
6085 + * level 0 tnode entries must be zeroed out.
6086 + * Could also use this for file deletion, but that's probably better handled
6087 + * by a special case.
6089 + * This function is recursive. For levels > 0 the function is called again on
6090 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
6091 + * If there is no data in a subtree then it is pruned.
6094 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
6095 +static yaffs_tnode_t *yaffs_prune_worker(yaffs_dev_t *dev, yaffs_tnode_t *tn,
6096 + __u32 level, int del0)
6100 - yaffs_Tnode *newTnodes;
6102 - yaffs_Tnode *curr;
6103 - yaffs_Tnode *next;
6104 - yaffs_TnodeList *tnl;
6112 - /* Calculate the tnode size in bytes for variable width tnode support.
6113 - * Must be a multiple of 32-bits */
6114 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6116 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
6117 + if (tn->internal[i]) {
6119 + yaffs_prune_worker(dev, tn->internal[i],
6121 + (i == 0) ? del0 : 1);
6124 - if (tnodeSize < sizeof(yaffs_Tnode))
6125 - tnodeSize = sizeof(yaffs_Tnode);
6126 + if (tn->internal[i])
6130 + int tnode_size_u32 = dev->tnode_size/sizeof(__u32);
6131 + __u32 *map = (__u32 *)tn;
6133 - /* make these things */
6134 + for(i = 0; !hasData && i < tnode_size_u32; i++){
6140 - newTnodes = YMALLOC(nTnodes * tnodeSize);
6141 - mem = (__u8 *)newTnodes;
6142 + if (hasData == 0 && del0) {
6143 + /* Free and return NULL */
6146 - T(YAFFS_TRACE_ERROR,
6147 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
6148 - return YAFFS_FAIL;
6150 + yaffs_free_tnode(dev, tn);
6154 - /* Hook them into the free list */
6156 - for (i = 0; i < nTnodes - 1; i++) {
6157 - newTnodes[i].internal[0] = &newTnodes[i + 1];
6158 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6159 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6163 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
6164 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6165 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6167 - dev->freeTnodes = newTnodes;
6169 - /* New hookup for wide tnodes */
6170 - for (i = 0; i < nTnodes - 1; i++) {
6171 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
6172 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
6173 - curr->internal[0] = next;
6177 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
6178 - curr->internal[0] = dev->freeTnodes;
6179 - dev->freeTnodes = (yaffs_Tnode *)mem;
6183 +static int yaffs_prune_tree(yaffs_dev_t *dev,
6184 + yaffs_file_s *file_struct)
6189 + yaffs_tnode_t *tn;
6191 + if (file_struct->top_level > 0) {
6192 + file_struct->top =
6193 + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
6195 + /* Now we have a tree with all the non-zero branches NULL but the height
6196 + * is the same as it was.
6197 + * Let's see if we can trim internal tnodes to shorten the tree.
6198 + * We can do this if only the 0th element in the tnode is in use
6199 + * (ie all the non-zero are NULL)
6202 - dev->nFreeTnodes += nTnodes;
6203 - dev->nTnodesCreated += nTnodes;
6204 + while (file_struct->top_level && !done) {
6205 + tn = file_struct->top;
6207 - /* Now add this bunch of tnodes to a list for freeing up.
6208 - * NB If we can't add this to the management list it isn't fatal
6209 - * but it just means we can't free this bunch of tnodes later.
6212 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
6213 + if (tn->internal[i])
6217 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
6219 - T(YAFFS_TRACE_ERROR,
6221 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
6222 - return YAFFS_FAIL;
6224 - tnl->tnodes = newTnodes;
6225 - tnl->next = dev->allocatedTnodeList;
6226 - dev->allocatedTnodeList = tnl;
6228 + file_struct->top = tn->internal[0];
6229 + file_struct->top_level--;
6230 + yaffs_free_tnode(dev, tn);
6237 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
6242 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
6243 +/*-------------------- End of File Structure functions.-------------------*/
6246 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
6247 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
6248 +static yaffs_obj_t *yaffs_alloc_empty_obj(yaffs_dev_t *dev)
6250 - yaffs_Tnode *tn = NULL;
6251 + yaffs_obj_t *obj = yaffs_alloc_raw_obj(dev);
6253 - /* If there are none left make more */
6254 - if (!dev->freeTnodes)
6255 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
6257 - if (dev->freeTnodes) {
6258 - tn = dev->freeTnodes;
6259 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6260 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
6261 - /* Hoosterman, this thing looks like it isn't in the list */
6262 - T(YAFFS_TRACE_ALWAYS,
6263 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
6266 - dev->freeTnodes = dev->freeTnodes->internal[0];
6267 - dev->nFreeTnodes--;
6272 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6273 + /* Now sweeten it up... */
6277 + memset(obj, 0, sizeof(yaffs_obj_t));
6278 + obj->being_created = 1;
6280 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
6282 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
6283 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6284 + obj->my_dev = dev;
6285 + obj->hdr_chunk = 0;
6286 + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
6287 + YINIT_LIST_HEAD(&(obj->hard_links));
6288 + YINIT_LIST_HEAD(&(obj->hash_link));
6289 + YINIT_LIST_HEAD(&obj->siblings);
6291 - if (tnodeSize < sizeof(yaffs_Tnode))
6292 - tnodeSize = sizeof(yaffs_Tnode);
6295 - memset(tn, 0, tnodeSize);
6296 + /* Now make the directory sane */
6297 + if (dev->root_dir) {
6298 + obj->parent = dev->root_dir;
6299 + ylist_add(&(obj->siblings), &dev->root_dir->variant.dir_variant.children);
6303 + /* Add it to the lost and found directory.
6304 + * NB Can't put root or lostNFound in lostNFound so
6305 + * check if lostNFound exists first
6307 + if (dev->lost_n_found)
6308 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
6310 + obj->being_created = 0;
6313 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
6318 -/* FreeTnode frees up a tnode and puts it back on the free list */
6319 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
6320 +static yaffs_obj_t *yaffs_create_fake_dir(yaffs_dev_t *dev, int number,
6324 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6325 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
6326 - /* Hoosterman, this thing looks like it is already in the list */
6327 - T(YAFFS_TRACE_ALWAYS,
6328 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
6330 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6332 - tn->internal[0] = dev->freeTnodes;
6333 - dev->freeTnodes = tn;
6334 - dev->nFreeTnodes++;
6336 + yaffs_obj_t *obj =
6337 + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6339 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
6340 + obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */
6341 + obj->unlink_allowed = 0; /* ... or unlink it */
6343 + obj->unlinked = 0;
6344 + obj->yst_mode = mode;
6345 + obj->my_dev = dev;
6346 + obj->hdr_chunk = 0; /* Not a valid chunk. */
6353 +static void yaffs_unhash_obj(yaffs_obj_t *obj)
6356 + yaffs_dev_t *dev = obj->my_dev;
6358 + /* If it is still linked into the bucket list, free from the list */
6359 + if (!ylist_empty(&obj->hash_link)) {
6360 + ylist_del_init(&obj->hash_link);
6361 + bucket = yaffs_hash_fn(obj->obj_id);
6362 + dev->obj_bucket[bucket].count--;
6364 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6367 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
6368 +/* FreeObject frees up a Object and puts it back on the free list */
6369 +static void yaffs_free_obj(yaffs_obj_t *obj)
6371 - /* Free the list of allocated tnodes */
6372 - yaffs_TnodeList *tmp;
6373 + yaffs_dev_t *dev = obj->my_dev;
6375 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->my_inode));
6377 - while (dev->allocatedTnodeList) {
6378 - tmp = dev->allocatedTnodeList->next;
6383 + if (!ylist_empty(&obj->siblings))
6386 - YFREE(dev->allocatedTnodeList->tnodes);
6387 - YFREE(dev->allocatedTnodeList);
6388 - dev->allocatedTnodeList = tmp;
6390 + if (obj->my_inode) {
6391 + /* We're still hooked up to a cached inode.
6392 + * Don't delete now, but mark for later deletion
6394 + obj->defered_free = 1;
6398 - dev->freeTnodes = NULL;
6399 - dev->nFreeTnodes = 0;
6401 + yaffs_unhash_obj(obj);
6403 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
6405 - dev->allocatedTnodeList = NULL;
6406 - dev->freeTnodes = NULL;
6407 - dev->nFreeTnodes = 0;
6408 - dev->nTnodesCreated = 0;
6409 + yaffs_free_raw_obj(dev,obj);
6411 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
6415 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
6417 +void yaffs_handle_defered_free(yaffs_obj_t *obj)
6419 - __u32 *map = (__u32 *)tn;
6425 - pos &= YAFFS_TNODES_LEVEL0_MASK;
6426 - val >>= dev->chunkGroupBits;
6427 + if (obj->defered_free)
6428 + yaffs_free_obj(obj);
6431 - bitInMap = pos * dev->tnodeWidth;
6432 - wordInMap = bitInMap / 32;
6433 - bitInWord = bitInMap & (32 - 1);
6434 +static void yaffs_init_tnodes_and_objs(yaffs_dev_t *dev)
6438 - mask = dev->tnodeMask << bitInWord;
6440 + dev->n_tnodes = 0;
6442 - map[wordInMap] &= ~mask;
6443 - map[wordInMap] |= (mask & (val << bitInWord));
6444 + yaffs_init_raw_tnodes_and_objs(dev);
6446 - if (dev->tnodeWidth > (32 - bitInWord)) {
6447 - bitInWord = (32 - bitInWord);
6449 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
6450 - map[wordInMap] &= ~mask;
6451 - map[wordInMap] |= (mask & (val >> bitInWord));
6452 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6453 + YINIT_LIST_HEAD(&dev->obj_bucket[i].list);
6454 + dev->obj_bucket[i].count = 0;
6458 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
6460 +static int yaffs_find_nice_bucket(yaffs_dev_t *dev)
6462 - __u32 *map = (__u32 *)tn;
6469 + int lowest = 999999;
6471 - pos &= YAFFS_TNODES_LEVEL0_MASK;
6473 - bitInMap = pos * dev->tnodeWidth;
6474 - wordInMap = bitInMap / 32;
6475 - bitInWord = bitInMap & (32 - 1);
6476 + /* Search for the shortest list or one that
6480 - val = map[wordInMap] >> bitInWord;
6481 + for (i = 0; i < 10 && lowest > 4; i++) {
6482 + dev->bucket_finder++;
6483 + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
6484 + if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
6485 + lowest = dev->obj_bucket[dev->bucket_finder].count;
6486 + l = dev->bucket_finder;
6489 - if (dev->tnodeWidth > (32 - bitInWord)) {
6490 - bitInWord = (32 - bitInWord);
6492 - val |= (map[wordInMap] << bitInWord);
6495 - val &= dev->tnodeMask;
6496 - val <<= dev->chunkGroupBits;
6502 -/* ------------------- End of individual tnode manipulation -----------------*/
6504 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
6505 - * The look up tree is represented by the top tnode and the number of topLevel
6506 - * in the tree. 0 means only the level 0 tnode is in the tree.
6509 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
6510 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
6511 - yaffs_FileStructure *fStruct,
6513 +static int yaffs_new_obj_id(yaffs_dev_t *dev)
6515 - yaffs_Tnode *tn = fStruct->top;
6517 - int requiredTallness;
6518 - int level = fStruct->topLevel;
6520 - /* Check sane level and chunk Id */
6521 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
6523 + int bucket = yaffs_find_nice_bucket(dev);
6525 - if (chunkId > YAFFS_MAX_CHUNK_ID)
6527 + /* Now find an object value that has not already been taken
6528 + * by scanning the list.
6531 - /* First check we're tall enough (ie enough topLevel) */
6533 + struct ylist_head *i;
6535 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
6536 - requiredTallness = 0;
6538 - i >>= YAFFS_TNODES_INTERNAL_BITS;
6539 - requiredTallness++;
6541 + __u32 n = (__u32) bucket;
6543 - if (requiredTallness > fStruct->topLevel)
6544 - return NULL; /* Not tall enough, so we can't find it */
6545 + /* yaffs_check_obj_hash_sane(); */
6547 - /* Traverse down to level 0 */
6548 - while (level > 0 && tn) {
6549 - tn = tn->internal[(chunkId >>
6550 - (YAFFS_TNODES_LEVEL0_BITS +
6552 - YAFFS_TNODES_INTERNAL_BITS)) &
6553 - YAFFS_TNODES_INTERNAL_MASK];
6557 + n += YAFFS_NOBJECT_BUCKETS;
6558 + if (1 || dev->obj_bucket[bucket].count > 0) {
6559 + ylist_for_each(i, &dev->obj_bucket[bucket].list) {
6560 + /* If there is already one in the list */
6561 + if (i && ylist_entry(i, yaffs_obj_t,
6562 + hash_link)->obj_id == n) {
6573 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
6574 - * This happens in two steps:
6575 - * 1. If the tree isn't tall enough, then make it taller.
6576 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
6578 - * Used when modifying the tree.
6580 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
6581 - * be plugged into the ttree.
6584 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
6585 - yaffs_FileStructure *fStruct,
6587 - yaffs_Tnode *passedTn)
6588 +static void yaffs_hash_obj(yaffs_obj_t *in)
6590 - int requiredTallness;
6596 + int bucket = yaffs_hash_fn(in->obj_id);
6597 + yaffs_dev_t *dev = in->my_dev;
6599 + ylist_add(&in->hash_link, &dev->obj_bucket[bucket].list);
6600 + dev->obj_bucket[bucket].count++;
6603 - /* Check sane level and page Id */
6604 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
6606 +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number)
6608 + int bucket = yaffs_hash_fn(number);
6609 + struct ylist_head *i;
6612 - if (chunkId > YAFFS_MAX_CHUNK_ID)
6614 + ylist_for_each(i, &dev->obj_bucket[bucket].list) {
6615 + /* Look if it is in the list */
6617 + in = ylist_entry(i, yaffs_obj_t, hash_link);
6618 + if (in->obj_id == number) {
6620 - /* First check we're tall enough (ie enough topLevel) */
6621 + /* Don't tell the VFS about this one if it is defered free */
6622 + if (in->defered_free)
6625 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
6626 - requiredTallness = 0;
6628 - x >>= YAFFS_TNODES_INTERNAL_BITS;
6629 - requiredTallness++;
6638 - if (requiredTallness > fStruct->topLevel) {
6639 - /* Not tall enough, gotta make the tree taller */
6640 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
6641 +yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
6642 + yaffs_obj_type type)
6644 + yaffs_obj_t *theObject=NULL;
6645 + yaffs_tnode_t *tn = NULL;
6647 - tn = yaffs_GetTnode(dev);
6649 + number = yaffs_new_obj_id(dev);
6652 - tn->internal[0] = fStruct->top;
6653 - fStruct->top = tn;
6655 - T(YAFFS_TRACE_ERROR,
6656 - (TSTR("yaffs: no more tnodes" TENDSTR)));
6659 + if (type == YAFFS_OBJECT_TYPE_FILE) {
6660 + tn = yaffs_get_tnode(dev);
6665 - fStruct->topLevel = requiredTallness;
6666 + theObject = yaffs_alloc_empty_obj(dev);
6669 + yaffs_free_tnode(dev,tn);
6673 - /* Traverse down to level 0, adding anything we need */
6675 - l = fStruct->topLevel;
6676 - tn = fStruct->top;
6678 + theObject->fake = 0;
6679 + theObject->rename_allowed = 1;
6680 + theObject->unlink_allowed = 1;
6681 + theObject->obj_id = number;
6682 + yaffs_hash_obj(theObject);
6683 + theObject->variant_type = type;
6684 +#ifdef CONFIG_YAFFS_WINCE
6685 + yfsd_win_file_time_now(theObject->win_atime);
6686 + theObject->win_ctime[0] = theObject->win_mtime[0] =
6687 + theObject->win_atime[0];
6688 + theObject->win_ctime[1] = theObject->win_mtime[1] =
6689 + theObject->win_atime[1];
6694 - while (l > 0 && tn) {
6696 - (YAFFS_TNODES_LEVEL0_BITS +
6697 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
6698 - YAFFS_TNODES_INTERNAL_MASK;
6699 + theObject->yst_atime = theObject->yst_mtime =
6700 + theObject->yst_ctime = Y_CURRENT_TIME;
6703 + case YAFFS_OBJECT_TYPE_FILE:
6704 + theObject->variant.file_variant.file_size = 0;
6705 + theObject->variant.file_variant.scanned_size = 0;
6706 + theObject->variant.file_variant.shrink_size = 0xFFFFFFFF; /* max __u32 */
6707 + theObject->variant.file_variant.top_level = 0;
6708 + theObject->variant.file_variant.top = tn;
6710 + case YAFFS_OBJECT_TYPE_DIRECTORY:
6711 + YINIT_LIST_HEAD(&theObject->variant.dir_variant.
6713 + YINIT_LIST_HEAD(&theObject->variant.dir_variant.
6716 + case YAFFS_OBJECT_TYPE_SYMLINK:
6717 + case YAFFS_OBJECT_TYPE_HARDLINK:
6718 + case YAFFS_OBJECT_TYPE_SPECIAL:
6719 + /* No action required */
6721 + case YAFFS_OBJECT_TYPE_UNKNOWN:
6722 + /* todo this should not happen */
6730 - if ((l > 1) && !tn->internal[x]) {
6731 - /* Add missing non-level-zero tnode */
6732 - tn->internal[x] = yaffs_GetTnode(dev);
6733 +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
6735 + yaffs_obj_type type)
6737 + yaffs_obj_t *theObject = NULL;
6739 - } else if (l == 1) {
6740 - /* Looking from level 1 at level 0 */
6742 - /* If we already have one, then release it.*/
6743 - if (tn->internal[x])
6744 - yaffs_FreeTnode(dev, tn->internal[x]);
6745 - tn->internal[x] = passedTn;
6747 + theObject = yaffs_find_by_number(dev, number);
6749 - } else if (!tn->internal[x]) {
6750 - /* Don't have one, none passed in */
6751 - tn->internal[x] = yaffs_GetTnode(dev);
6755 + theObject = yaffs_new_obj(dev, number, type);
6757 - tn = tn->internal[x];
6761 - /* top is level 0 */
6763 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
6764 - yaffs_FreeTnode(dev, passedTn);
6772 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
6773 - yaffs_ExtendedTags *tags, int objectId,
6776 +YCHAR *yaffs_clone_str(const YCHAR *str)
6779 + YCHAR *newStr = NULL;
6782 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
6783 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
6784 - theChunk % dev->nChunksPerBlock)) {
6785 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
6787 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
6796 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
6797 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
6799 + yaffs_strncpy(newStr, str,len);
6808 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
6809 - * chunks and tnodes in the file
6810 - * Returns 1 if the tree was deleted.
6811 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
6813 + * Mknod (create) a new object.
6814 + * equiv_obj only has meaning for a hard link;
6815 + * aliasString only has meaning for a symlink.
6816 + * rdev only has meaning for devices (a subset of special objects)
6819 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
6820 - int chunkOffset, int *limit)
6821 +static yaffs_obj_t *yaffs_create_obj(yaffs_obj_type type,
6822 + yaffs_obj_t *parent,
6823 + const YCHAR *name,
6827 + yaffs_obj_t *equiv_obj,
6828 + const YCHAR *aliasString, __u32 rdev)
6833 - yaffs_ExtendedTags tags;
6835 - yaffs_Device *dev = in->myDev;
6841 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
6843 - if (tn->internal[i]) {
6844 - if (limit && (*limit) < 0) {
6848 - yaffs_DeleteWorker(in,
6856 - YAFFS_TNODES_INTERNAL_BITS)
6861 - yaffs_FreeTnode(dev,
6864 - tn->internal[i] = NULL;
6868 - return (allDone) ? 1 : 0;
6869 - } else if (level == 0) {
6872 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
6874 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
6877 - chunkInInode = (chunkOffset <<
6878 - YAFFS_TNODES_LEVEL0_BITS) + i;
6881 - yaffs_FindChunkInGroup(dev,
6887 - if (foundChunk > 0) {
6888 - yaffs_DeleteChunk(dev,
6891 - in->nDataChunks--;
6893 - *limit = *limit - 1;
6900 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
6904 - return (i < 0) ? 1 : 0;
6914 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
6916 - yaffs_BlockInfo *theBlock;
6918 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
6920 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
6922 - theBlock->softDeletions++;
6923 - dev->nFreeChunks++;
6927 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
6928 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
6930 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
6933 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
6934 - __u32 level, int chunkOffset)
6939 - yaffs_Device *dev = in->myDev;
6944 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
6946 - if (tn->internal[i]) {
6948 - yaffs_SoftDeleteWorker(in,
6954 - YAFFS_TNODES_INTERNAL_BITS)
6957 - yaffs_FreeTnode(dev,
6960 - tn->internal[i] = NULL;
6962 - /* Hoosterman... how could this happen? */
6966 - return (allDone) ? 1 : 0;
6967 - } else if (level == 0) {
6969 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
6970 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
6972 - /* Note this does not find the real chunk, only the chunk group.
6973 - * We make an assumption that a chunk group is not larger than
6976 - yaffs_SoftDeleteChunk(dev, theChunk);
6977 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
6991 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
6993 - if (obj->deleted &&
6994 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
6995 - if (obj->nDataChunks <= 0) {
6996 - /* Empty file with no duplicate object headers, just delete it immediately */
6997 - yaffs_FreeTnode(obj->myDev,
6998 - obj->variant.fileVariant.top);
6999 - obj->variant.fileVariant.top = NULL;
7000 - T(YAFFS_TRACE_TRACING,
7001 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
7003 - yaffs_DoGenericObjectDeletion(obj);
7005 - yaffs_SoftDeleteWorker(obj,
7006 - obj->variant.fileVariant.top,
7007 - obj->variant.fileVariant.
7009 - obj->softDeleted = 1;
7014 -/* Pruning removes any part of the file structure tree that is beyond the
7015 - * bounds of the file (ie that does not point to chunks).
7017 - * A file should only get pruned when its size is reduced.
7019 - * Before pruning, the chunks must be pulled from the tree and the
7020 - * level 0 tnode entries must be zeroed out.
7021 - * Could also use this for file deletion, but that's probably better handled
7022 - * by a special case.
7025 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7026 - __u32 level, int del0)
7034 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7035 - if (tn->internal[i] && level > 0) {
7037 - yaffs_PruneWorker(dev, tn->internal[i],
7039 - (i == 0) ? del0 : 1);
7042 - if (tn->internal[i])
7046 - if (hasData == 0 && del0) {
7047 - /* Free and return NULL */
7049 - yaffs_FreeTnode(dev, tn);
7059 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
7060 - yaffs_FileStructure *fStruct)
7067 - if (fStruct->topLevel > 0) {
7069 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7071 - /* Now we have a tree with all the non-zero branches NULL but the height
7072 - * is the same as it was.
7073 - * Let's see if we can trim internal tnodes to shorten the tree.
7074 - * We can do this if only the 0th element in the tnode is in use
7075 - * (ie all the non-zero are NULL)
7078 - while (fStruct->topLevel && !done) {
7079 - tn = fStruct->top;
7082 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7083 - if (tn->internal[i])
7088 - fStruct->top = tn->internal[0];
7089 - fStruct->topLevel--;
7090 - yaffs_FreeTnode(dev, tn);
7100 -/*-------------------- End of File Structure functions.-------------------*/
7102 -/* yaffs_CreateFreeObjects creates a bunch more objects and
7103 - * adds them to the object free list.
7105 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
7108 - yaffs_Object *newObjects;
7109 - yaffs_ObjectList *list;
7114 - /* make these things */
7115 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
7116 - list = YMALLOC(sizeof(yaffs_ObjectList));
7118 - if (!newObjects || !list) {
7120 - YFREE(newObjects);
7123 - T(YAFFS_TRACE_ALLOCATE,
7124 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
7125 - return YAFFS_FAIL;
7128 - /* Hook them into the free list */
7129 - for (i = 0; i < nObjects - 1; i++) {
7130 - newObjects[i].siblings.next =
7131 - (struct ylist_head *)(&newObjects[i + 1]);
7134 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
7135 - dev->freeObjects = newObjects;
7136 - dev->nFreeObjects += nObjects;
7137 - dev->nObjectsCreated += nObjects;
7139 - /* Now add this bunch of Objects to a list for freeing up. */
7141 - list->objects = newObjects;
7142 - list->next = dev->allocatedObjectList;
7143 - dev->allocatedObjectList = list;
7149 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7150 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7152 - yaffs_Object *tn = NULL;
7154 -#ifdef VALGRIND_TEST
7155 - tn = YMALLOC(sizeof(yaffs_Object));
7157 - /* If there are none left make more */
7158 - if (!dev->freeObjects)
7159 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
7161 - if (dev->freeObjects) {
7162 - tn = dev->freeObjects;
7163 - dev->freeObjects =
7164 - (yaffs_Object *) (dev->freeObjects->siblings.next);
7165 - dev->nFreeObjects--;
7169 - /* Now sweeten it up... */
7171 - memset(tn, 0, sizeof(yaffs_Object));
7172 - tn->beingCreated = 1;
7176 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7177 - YINIT_LIST_HEAD(&(tn->hardLinks));
7178 - YINIT_LIST_HEAD(&(tn->hashLink));
7179 - YINIT_LIST_HEAD(&tn->siblings);
7182 - /* Now make the directory sane */
7183 - if (dev->rootDir) {
7184 - tn->parent = dev->rootDir;
7185 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
7188 - /* Add it to the lost and found directory.
7189 - * NB Can't put root or lostNFound in lostNFound so
7190 - * check if lostNFound exists first
7192 - if (dev->lostNFoundDir)
7193 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
7195 - tn->beingCreated = 0;
7198 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7203 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
7207 - yaffs_Object *obj =
7208 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
7210 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
7211 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
7212 - obj->unlinkAllowed = 0; /* ... or unlink it */
7214 - obj->unlinked = 0;
7215 - obj->yst_mode = mode;
7217 - obj->hdrChunk = 0; /* Not a valid chunk. */
7224 -static void yaffs_UnhashObject(yaffs_Object *tn)
7227 - yaffs_Device *dev = tn->myDev;
7229 - /* If it is still linked into the bucket list, free from the list */
7230 - if (!ylist_empty(&tn->hashLink)) {
7231 - ylist_del_init(&tn->hashLink);
7232 - bucket = yaffs_HashFunction(tn->objectId);
7233 - dev->objectBucket[bucket].count--;
7237 -/* FreeObject frees up a Object and puts it back on the free list */
7238 -static void yaffs_FreeObject(yaffs_Object *tn)
7240 - yaffs_Device *dev = tn->myDev;
7243 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
7248 - if (!ylist_empty(&tn->siblings))
7253 - if (tn->myInode) {
7254 - /* We're still hooked up to a cached inode.
7255 - * Don't delete now, but mark for later deletion
7257 - tn->deferedFree = 1;
7262 - yaffs_UnhashObject(tn);
7264 -#ifdef VALGRIND_TEST
7267 - /* Link into the free list. */
7268 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
7269 - dev->freeObjects = tn;
7270 - dev->nFreeObjects++;
7272 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7277 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
7279 - if (obj->deferedFree)
7280 - yaffs_FreeObject(obj);
7285 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
7287 - /* Free the list of allocated Objects */
7289 - yaffs_ObjectList *tmp;
7291 - while (dev->allocatedObjectList) {
7292 - tmp = dev->allocatedObjectList->next;
7293 - YFREE(dev->allocatedObjectList->objects);
7294 - YFREE(dev->allocatedObjectList);
7296 - dev->allocatedObjectList = tmp;
7299 - dev->freeObjects = NULL;
7300 - dev->nFreeObjects = 0;
7303 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
7307 - dev->allocatedObjectList = NULL;
7308 - dev->freeObjects = NULL;
7309 - dev->nFreeObjects = 0;
7311 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
7312 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
7313 - dev->objectBucket[i].count = 0;
7317 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
7322 - int lowest = 999999;
7324 - /* First let's see if we can find one that's empty. */
7326 - for (i = 0; i < 10 && lowest > 0; i++) {
7328 - x %= YAFFS_NOBJECT_BUCKETS;
7329 - if (dev->objectBucket[x].count < lowest) {
7330 - lowest = dev->objectBucket[x].count;
7336 - /* If we didn't find an empty list, then try
7337 - * looking a bit further for a short one
7340 - for (i = 0; i < 10 && lowest > 3; i++) {
7342 - x %= YAFFS_NOBJECT_BUCKETS;
7343 - if (dev->objectBucket[x].count < lowest) {
7344 - lowest = dev->objectBucket[x].count;
7353 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
7355 - int bucket = yaffs_FindNiceObjectBucket(dev);
7357 - /* Now find an object value that has not already been taken
7358 - * by scanning the list.
7362 - struct ylist_head *i;
7364 - __u32 n = (__u32) bucket;
7366 - /* yaffs_CheckObjectHashSanity(); */
7370 - n += YAFFS_NOBJECT_BUCKETS;
7371 - if (1 || dev->objectBucket[bucket].count > 0) {
7372 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
7373 - /* If there is already one in the list */
7374 - if (i && ylist_entry(i, yaffs_Object,
7375 - hashLink)->objectId == n) {
7385 -static void yaffs_HashObject(yaffs_Object *in)
7387 - int bucket = yaffs_HashFunction(in->objectId);
7388 - yaffs_Device *dev = in->myDev;
7390 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
7391 - dev->objectBucket[bucket].count++;
7394 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
7396 - int bucket = yaffs_HashFunction(number);
7397 - struct ylist_head *i;
7400 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
7401 - /* Look if it is in the list */
7403 - in = ylist_entry(i, yaffs_Object, hashLink);
7404 - if (in->objectId == number) {
7406 - /* Don't tell the VFS about this one if it is defered free */
7407 - if (in->deferedFree)
7419 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
7420 - yaffs_ObjectType type)
7422 - yaffs_Object *theObject;
7423 - yaffs_Tnode *tn = NULL;
7426 - number = yaffs_CreateNewObjectNumber(dev);
7428 - theObject = yaffs_AllocateEmptyObject(dev);
7432 - if (type == YAFFS_OBJECT_TYPE_FILE) {
7433 - tn = yaffs_GetTnode(dev);
7435 - yaffs_FreeObject(theObject);
7441 - theObject->fake = 0;
7442 - theObject->renameAllowed = 1;
7443 - theObject->unlinkAllowed = 1;
7444 - theObject->objectId = number;
7445 - yaffs_HashObject(theObject);
7446 - theObject->variantType = type;
7447 -#ifdef CONFIG_YAFFS_WINCE
7448 - yfsd_WinFileTimeNow(theObject->win_atime);
7449 - theObject->win_ctime[0] = theObject->win_mtime[0] =
7450 - theObject->win_atime[0];
7451 - theObject->win_ctime[1] = theObject->win_mtime[1] =
7452 - theObject->win_atime[1];
7456 - theObject->yst_atime = theObject->yst_mtime =
7457 - theObject->yst_ctime = Y_CURRENT_TIME;
7460 - case YAFFS_OBJECT_TYPE_FILE:
7461 - theObject->variant.fileVariant.fileSize = 0;
7462 - theObject->variant.fileVariant.scannedFileSize = 0;
7463 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
7464 - theObject->variant.fileVariant.topLevel = 0;
7465 - theObject->variant.fileVariant.top = tn;
7467 - case YAFFS_OBJECT_TYPE_DIRECTORY:
7468 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
7471 - case YAFFS_OBJECT_TYPE_SYMLINK:
7472 - case YAFFS_OBJECT_TYPE_HARDLINK:
7473 - case YAFFS_OBJECT_TYPE_SPECIAL:
7474 - /* No action required */
7476 - case YAFFS_OBJECT_TYPE_UNKNOWN:
7477 - /* todo this should not happen */
7485 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
7487 - yaffs_ObjectType type)
7489 - yaffs_Object *theObject = NULL;
7492 - theObject = yaffs_FindObjectByNumber(dev, number);
7495 - theObject = yaffs_CreateNewObject(dev, number, type);
7502 -static YCHAR *yaffs_CloneString(const YCHAR *str)
7504 - YCHAR *newStr = NULL;
7506 - if (str && *str) {
7507 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
7509 - yaffs_strcpy(newStr, str);
7517 - * Mknod (create) a new object.
7518 - * equivalentObject only has meaning for a hard link;
7519 - * aliasString only has meaning for a sumlink.
7520 - * rdev only has meaning for devices (a subset of special objects)
7523 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
7524 - yaffs_Object *parent,
7525 - const YCHAR *name,
7529 - yaffs_Object *equivalentObject,
7530 - const YCHAR *aliasString, __u32 rdev)
7533 - YCHAR *str = NULL;
7535 - yaffs_Device *dev = parent->myDev;
7537 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
7538 - if (yaffs_FindObjectByName(parent, name))
7541 - in = yaffs_CreateNewObject(dev, -1, type);
7544 - return YAFFS_FAIL;
7546 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
7547 - str = yaffs_CloneString(aliasString);
7549 - yaffs_FreeObject(in);
7559 - in->variantType = type;
7561 - in->yst_mode = mode;
7563 -#ifdef CONFIG_YAFFS_WINCE
7564 - yfsd_WinFileTimeNow(in->win_atime);
7565 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
7566 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
7569 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
7571 - in->yst_rdev = rdev;
7572 - in->yst_uid = uid;
7573 - in->yst_gid = gid;
7575 - in->nDataChunks = 0;
7577 - yaffs_SetObjectName(in, name);
7580 - yaffs_AddObjectToDirectory(parent, in);
7582 - in->myDev = parent->myDev;
7585 - case YAFFS_OBJECT_TYPE_SYMLINK:
7586 - in->variant.symLinkVariant.alias = str;
7588 - case YAFFS_OBJECT_TYPE_HARDLINK:
7589 - in->variant.hardLinkVariant.equivalentObject =
7591 - in->variant.hardLinkVariant.equivalentObjectId =
7592 - equivalentObject->objectId;
7593 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
7595 - case YAFFS_OBJECT_TYPE_FILE:
7596 - case YAFFS_OBJECT_TYPE_DIRECTORY:
7597 - case YAFFS_OBJECT_TYPE_SPECIAL:
7598 - case YAFFS_OBJECT_TYPE_UNKNOWN:
7603 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
7604 - /* Could not create the object header, fail the creation */
7605 - yaffs_DeleteObject(in);
7614 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
7615 - __u32 mode, __u32 uid, __u32 gid)
7617 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
7618 - uid, gid, NULL, NULL, 0);
7621 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
7622 - __u32 mode, __u32 uid, __u32 gid)
7624 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
7625 - mode, uid, gid, NULL, NULL, 0);
7628 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
7629 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
7631 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
7632 - uid, gid, NULL, NULL, rdev);
7635 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
7636 - __u32 mode, __u32 uid, __u32 gid,
7637 - const YCHAR *alias)
7639 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
7640 - uid, gid, NULL, alias, 0);
7643 -/* yaffs_Link returns the object id of the equivalent object.*/
7644 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
7645 - yaffs_Object *equivalentObject)
7647 - /* Get the real object in case we were fed a hard link as an equivalent object */
7648 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
7650 - if (yaffs_MknodObject
7651 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
7652 - equivalentObject, NULL, 0)) {
7653 - return equivalentObject;
7660 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
7661 - const YCHAR *newName, int force, int shadows)
7666 - yaffs_Object *existingTarget;
7668 - if (newDir == NULL)
7669 - newDir = obj->parent; /* use the old directory */
7671 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
7672 - T(YAFFS_TRACE_ALWAYS,
7674 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
7679 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
7680 - if (obj->myDev->isYaffs2)
7681 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
7683 - unlinkOp = (newDir == obj->myDev->unlinkedDir
7684 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
7686 - deleteOp = (newDir == obj->myDev->deletedDir);
7688 - existingTarget = yaffs_FindObjectByName(newDir, newName);
7690 - /* If the object is a file going into the unlinked directory,
7691 - * then it is OK to just stuff it in since duplicate names are allowed.
7692 - * else only proceed if the new name does not exist and if we're putting
7693 - * it into a directory.
7699 - !existingTarget) &&
7700 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
7701 - yaffs_SetObjectName(obj, newName);
7704 - yaffs_AddObjectToDirectory(newDir, obj);
7707 - obj->unlinked = 1;
7709 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
7710 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
7714 - return YAFFS_FAIL;
7717 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
7718 - yaffs_Object *newDir, const YCHAR *newName)
7720 - yaffs_Object *obj = NULL;
7721 - yaffs_Object *existingTarget = NULL;
7725 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7727 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7730 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
7731 - /* Special case for case insemsitive systems (eg. WinCE).
7732 - * While look-up is case insensitive, the name isn't.
7733 - * Therefore we might want to change x.txt to X.txt
7735 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
7739 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
7740 - /* ENAMETOOLONG */
7741 - return YAFFS_FAIL;
7743 - obj = yaffs_FindObjectByName(oldDir, oldName);
7745 - if (obj && obj->renameAllowed) {
7747 - /* Now do the handling for an existing target, if there is one */
7749 - existingTarget = yaffs_FindObjectByName(newDir, newName);
7750 - if (existingTarget &&
7751 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
7752 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
7753 - /* There is a target that is a non-empty directory, so we fail */
7754 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
7755 - } else if (existingTarget && existingTarget != obj) {
7756 - /* Nuke the target first, using shadowing,
7757 - * but only if it isn't the same object
7759 - yaffs_ChangeObjectName(obj, newDir, newName, force,
7760 - existingTarget->objectId);
7761 - yaffs_UnlinkObject(existingTarget);
7764 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
7766 - return YAFFS_FAIL;
7769 -/*------------------------- Block Management and Page Allocation ----------------*/
7771 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
7773 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
7775 - dev->blockInfo = NULL;
7776 - dev->chunkBits = NULL;
7778 - dev->allocationBlock = -1; /* force it to get a new one */
7780 - /* If the first allocation strategy fails, thry the alternate one */
7781 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
7782 - if (!dev->blockInfo) {
7783 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
7784 - dev->blockInfoAlt = 1;
7786 - dev->blockInfoAlt = 0;
7788 - if (dev->blockInfo) {
7789 - /* Set up dynamic blockinfo stuff. */
7790 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
7791 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
7792 - if (!dev->chunkBits) {
7793 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
7794 - dev->chunkBitsAlt = 1;
7796 - dev->chunkBitsAlt = 0;
7799 - if (dev->blockInfo && dev->chunkBits) {
7800 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
7801 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
7805 - return YAFFS_FAIL;
7808 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
7810 - if (dev->blockInfoAlt && dev->blockInfo)
7811 - YFREE_ALT(dev->blockInfo);
7812 - else if (dev->blockInfo)
7813 - YFREE(dev->blockInfo);
7815 - dev->blockInfoAlt = 0;
7817 - dev->blockInfo = NULL;
7819 - if (dev->chunkBitsAlt && dev->chunkBits)
7820 - YFREE_ALT(dev->chunkBits);
7821 - else if (dev->chunkBits)
7822 - YFREE(dev->chunkBits);
7823 - dev->chunkBitsAlt = 0;
7824 - dev->chunkBits = NULL;
7827 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
7828 - yaffs_BlockInfo *bi)
7832 - yaffs_BlockInfo *b;
7834 - if (!dev->isYaffs2)
7835 - return 1; /* disqualification only applies to yaffs2. */
7837 - if (!bi->hasShrinkHeader)
7838 - return 1; /* can gc */
7840 - /* Find the oldest dirty sequence number if we don't know it and save it
7841 - * so we don't have to keep recomputing it.
7843 - if (!dev->oldestDirtySequence) {
7844 - seq = dev->sequenceNumber;
7846 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
7848 - b = yaffs_GetBlockInfo(dev, i);
7849 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
7850 - (b->pagesInUse - b->softDeletions) <
7851 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
7852 - seq = b->sequenceNumber;
7855 - dev->oldestDirtySequence = seq;
7858 - /* Can't do gc of this block if there are any blocks older than this one that have
7859 - * discarded pages.
7861 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
7864 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
7865 - * for garbage collection.
7868 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
7871 - int b = dev->currentDirtyChecker;
7875 - int dirtiest = -1;
7876 - int pagesInUse = 0;
7877 - int prioritised = 0;
7878 - yaffs_BlockInfo *bi;
7879 - int pendingPrioritisedExist = 0;
7881 - /* First let's see if we need to grab a prioritised block */
7882 - if (dev->hasPendingPrioritisedGCs) {
7883 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
7885 - bi = yaffs_GetBlockInfo(dev, i);
7886 - /* yaffs_VerifyBlock(dev,bi,i); */
7888 - if (bi->gcPrioritise) {
7889 - pendingPrioritisedExist = 1;
7890 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
7891 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
7892 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
7895 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
7900 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
7901 - dev->hasPendingPrioritisedGCs = 0;
7904 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
7906 - * else (we're doing a leasurely gc), then we only bother to do this if the
7907 - * block has only a few pages in use.
7910 - dev->nonAggressiveSkip--;
7912 - if (!aggressive && (dev->nonAggressiveSkip > 0))
7917 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
7921 - dev->internalEndBlock - dev->internalStartBlock + 1;
7924 - dev->internalEndBlock - dev->internalStartBlock + 1;
7925 - iterations = iterations / 16;
7926 - if (iterations > 200)
7930 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
7932 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
7933 - b = dev->internalStartBlock;
7935 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
7936 - T(YAFFS_TRACE_ERROR,
7937 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
7941 - bi = yaffs_GetBlockInfo(dev, b);
7943 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
7944 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
7945 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
7947 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
7951 - dev->currentDirtyChecker = b;
7953 - if (dirtiest > 0) {
7955 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
7956 - dev->nChunksPerBlock - pagesInUse, prioritised));
7959 - dev->oldestDirtySequence = 0;
7962 - dev->nonAggressiveSkip = 4;
7967 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
7969 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
7973 - /* If the block is still healthy erase it and mark as clean.
7974 - * If the block has had a data failure, then retire it.
7977 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
7978 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
7979 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
7981 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
7983 - if (!bi->needsRetiring) {
7984 - yaffs_InvalidateCheckpoint(dev);
7985 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
7987 - dev->nErasureFailures++;
7988 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
7989 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
7994 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
7996 - for (i = 0; i < dev->nChunksPerBlock; i++) {
7997 - if (!yaffs_CheckChunkErased
7998 - (dev, blockNo * dev->nChunksPerBlock + i)) {
7999 - T(YAFFS_TRACE_ERROR,
8001 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
8002 - TENDSTR), blockNo, i));
8008 - /* Clean it up... */
8009 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
8010 - dev->nErasedBlocks++;
8011 - bi->pagesInUse = 0;
8012 - bi->softDeletions = 0;
8013 - bi->hasShrinkHeader = 0;
8014 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
8015 - bi->gcPrioritise = 0;
8016 - yaffs_ClearChunkBits(dev, blockNo);
8018 - T(YAFFS_TRACE_ERASE,
8019 - (TSTR("Erased block %d" TENDSTR), blockNo));
8021 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
8023 - yaffs_RetireBlock(dev, blockNo);
8024 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
8025 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
8029 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
8033 - yaffs_BlockInfo *bi;
8035 - if (dev->nErasedBlocks < 1) {
8036 - /* Hoosterman we've got a problem.
8037 - * Can't get space to gc
8039 - T(YAFFS_TRACE_ERROR,
8040 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
8045 - /* Find an empty block. */
8047 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
8048 - dev->allocationBlockFinder++;
8049 - if (dev->allocationBlockFinder < dev->internalStartBlock
8050 - || dev->allocationBlockFinder > dev->internalEndBlock) {
8051 - dev->allocationBlockFinder = dev->internalStartBlock;
8054 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
8056 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
8057 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
8058 - dev->sequenceNumber++;
8059 - bi->sequenceNumber = dev->sequenceNumber;
8060 - dev->nErasedBlocks--;
8061 - T(YAFFS_TRACE_ALLOCATE,
8062 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
8063 - dev->allocationBlockFinder, dev->sequenceNumber,
8064 - dev->nErasedBlocks));
8065 - return dev->allocationBlockFinder;
8069 - T(YAFFS_TRACE_ALWAYS,
8071 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
8072 - TENDSTR), dev->nErasedBlocks));
8079 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
8081 - if (!dev->nCheckpointBlocksRequired &&
8083 - /* Not a valid value so recalculate */
8086 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
8089 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
8091 - if (tnodeSize < sizeof(yaffs_Tnode))
8092 - tnodeSize = sizeof(yaffs_Tnode);
8094 - nBytes += sizeof(yaffs_CheckpointValidity);
8095 - nBytes += sizeof(yaffs_CheckpointDevice);
8096 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
8097 - nBytes += devBlocks * dev->chunkBitmapStride;
8098 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
8099 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
8100 - nBytes += sizeof(yaffs_CheckpointValidity);
8101 - nBytes += sizeof(__u32); /* checksum*/
8103 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
8105 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
8107 - dev->nCheckpointBlocksRequired = nBlocks;
8110 - return dev->nCheckpointBlocksRequired;
8114 - * Check if there's space to allocate...
8115 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
8117 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
8119 - int reservedChunks;
8120 - int reservedBlocks = dev->nReservedBlocks;
8121 - int checkpointBlocks;
8123 - if (dev->isYaffs2) {
8124 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
8125 - dev->blocksInCheckpoint;
8126 - if (checkpointBlocks < 0)
8127 - checkpointBlocks = 0;
8129 - checkpointBlocks = 0;
8132 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
8134 - return (dev->nFreeChunks > reservedChunks);
8137 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
8138 - yaffs_BlockInfo **blockUsedPtr)
8141 - yaffs_BlockInfo *bi;
8143 - if (dev->allocationBlock < 0) {
8144 - /* Get next block to allocate off */
8145 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
8146 - dev->allocationPage = 0;
8149 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
8150 - /* Not enough space to allocate unless we're allowed to use the reserve. */
8154 - if (dev->nErasedBlocks < dev->nReservedBlocks
8155 - && dev->allocationPage == 0) {
8156 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
8159 - /* Next page please.... */
8160 - if (dev->allocationBlock >= 0) {
8161 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
8163 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
8164 - dev->allocationPage;
8166 - yaffs_SetChunkBit(dev, dev->allocationBlock,
8167 - dev->allocationPage);
8169 - dev->allocationPage++;
8171 - dev->nFreeChunks--;
8173 - /* If the block is full set the state to full */
8174 - if (dev->allocationPage >= dev->nChunksPerBlock) {
8175 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
8176 - dev->allocationBlock = -1;
8180 - *blockUsedPtr = bi;
8185 - T(YAFFS_TRACE_ERROR,
8186 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
8191 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
8195 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
8197 - if (dev->allocationBlock > 0)
8198 - n += (dev->nChunksPerBlock - dev->allocationPage);
8204 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
8210 - int retVal = YAFFS_OK;
8213 - int isCheckpointBlock;
8214 - int matchingChunk;
8217 - int chunksBefore = yaffs_GetErasedChunks(dev);
8220 - yaffs_ExtendedTags tags;
8222 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
8224 - yaffs_Object *object;
8226 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
8228 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
8230 - T(YAFFS_TRACE_TRACING,
8231 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
8234 - bi->hasShrinkHeader,
8237 - /*yaffs_VerifyFreeChunks(dev); */
8239 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
8241 - /* Take off the number of soft deleted entries because
8242 - * they're going to get really deleted during GC.
8244 - dev->nFreeChunks -= bi->softDeletions;
8246 - dev->isDoingGC = 1;
8248 - if (isCheckpointBlock ||
8249 - !yaffs_StillSomeChunkBits(dev, block)) {
8250 - T(YAFFS_TRACE_TRACING,
8252 - ("Collecting block %d that has no chunks in use" TENDSTR),
8254 - yaffs_BlockBecameDirty(dev, block);
8257 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
8259 - yaffs_VerifyBlock(dev, bi, block);
8261 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
8262 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
8264 - for (/* init already done */;
8265 - retVal == YAFFS_OK &&
8266 - dev->gcChunk < dev->nChunksPerBlock &&
8267 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
8269 - dev->gcChunk++, oldChunk++) {
8270 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
8272 - /* This page is in use and might need to be copied off */
8278 - yaffs_InitialiseTags(&tags);
8280 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
8284 - yaffs_FindObjectByNumber(dev,
8287 - T(YAFFS_TRACE_GC_DETAIL,
8289 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
8290 - dev->gcChunk, tags.objectId, tags.chunkId,
8293 - if (object && !yaffs_SkipVerification(dev)) {
8294 - if (tags.chunkId == 0)
8295 - matchingChunk = object->hdrChunk;
8296 - else if (object->softDeleted)
8297 - matchingChunk = oldChunk; /* Defeat the test */
8299 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
8301 - if (oldChunk != matchingChunk)
8302 - T(YAFFS_TRACE_ERROR,
8303 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
8304 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
8309 - T(YAFFS_TRACE_ERROR,
8311 - ("page %d in gc has no object: %d %d %d "
8312 - TENDSTR), oldChunk,
8313 - tags.objectId, tags.chunkId, tags.byteCount));
8317 - object->deleted &&
8318 - object->softDeleted &&
8319 - tags.chunkId != 0) {
8320 - /* Data chunk in a soft deleted file, throw it away
8321 - * It's a soft deleted data chunk,
8322 - * No need to copy this, just forget about it and
8323 - * fix up the object.
8326 - object->nDataChunks--;
8328 - if (object->nDataChunks <= 0) {
8329 - /* remeber to clean up the object */
8330 - dev->gcCleanupList[cleanups] =
8336 - /* Todo object && object->deleted && object->nDataChunks == 0 */
8337 - /* Deleted object header with no data chunks.
8338 - * Can be discarded and the file deleted.
8340 - object->hdrChunk = 0;
8341 - yaffs_FreeTnode(object->myDev,
8344 - object->variant.fileVariant.top = NULL;
8345 - yaffs_DoGenericObjectDeletion(object);
8347 - } else if (object) {
8348 - /* It's either a data chunk in a live file or
8349 - * an ObjectHeader, so we're interested in it.
8350 - * NB Need to keep the ObjectHeaders of deleted files
8351 - * until the whole file has been deleted off
8353 - tags.serialNumber++;
8357 - if (tags.chunkId == 0) {
8358 - /* It is an object Id,
8359 - * We need to nuke the shrinkheader flags first
8360 - * We no longer want the shrinkHeader flag since its work is done
8361 - * and if it is left in place it will mess up scanning.
8364 - yaffs_ObjectHeader *oh;
8365 - oh = (yaffs_ObjectHeader *)buffer;
8367 - tags.extraIsShrinkHeader = 0;
8369 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
8373 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
8375 - if (newChunk < 0) {
8376 - retVal = YAFFS_FAIL;
8379 - /* Ok, now fix up the Tnodes etc. */
8381 - if (tags.chunkId == 0) {
8382 - /* It's a header */
8383 - object->hdrChunk = newChunk;
8384 - object->serial = tags.serialNumber;
8386 - /* It's a data chunk */
8387 - yaffs_PutChunkIntoFile
8395 - if (retVal == YAFFS_OK)
8396 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
8401 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8404 - /* Do any required cleanups */
8405 - for (i = 0; i < cleanups; i++) {
8406 - /* Time to delete the file too */
8408 - yaffs_FindObjectByNumber(dev,
8409 - dev->gcCleanupList[i]);
8411 - yaffs_FreeTnode(dev,
8412 - object->variant.fileVariant.
8414 - object->variant.fileVariant.top = NULL;
8417 - ("yaffs: About to finally delete object %d"
8418 - TENDSTR), object->objectId));
8419 - yaffs_DoGenericObjectDeletion(object);
8420 - object->myDev->nDeletedFiles--;
8427 - yaffs_VerifyCollectedBlock(dev, bi, block);
8429 - chunksAfter = yaffs_GetErasedChunks(dev);
8430 - if (chunksBefore >= chunksAfter) {
8433 - ("gc did not increase free chunks before %d after %d"
8434 - TENDSTR), chunksBefore, chunksAfter));
8437 - /* If the gc completed then clear the current gcBlock so that we find another. */
8438 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
8439 - dev->gcBlock = -1;
8443 - dev->isDoingGC = 0;
8448 -/* New garbage collector
8449 - * If we're very low on erased blocks then we do aggressive garbage collection
8450 - * otherwise we do "leasurely" garbage collection.
8451 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
8452 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
8454 - * The idea is to help clear out space in a more spread-out manner.
8455 - * Dunno if it really does anything useful.
8457 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
8461 - int gcOk = YAFFS_OK;
8464 - int checkpointBlockAdjust;
8466 - if (dev->isDoingGC) {
8467 - /* Bail out so we don't get recursive gc */
8471 - /* This loop should pass the first time.
8472 - * We'll only see looping here if the erase of the collected block fails.
8478 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
8479 - if (checkpointBlockAdjust < 0)
8480 - checkpointBlockAdjust = 0;
8482 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
8483 - /* We need a block soon...*/
8486 - /* We're in no hurry */
8490 - if (dev->gcBlock <= 0) {
8491 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
8495 - block = dev->gcBlock;
8498 - dev->garbageCollections++;
8500 - dev->passiveGarbageCollections++;
8504 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
8505 - dev->nErasedBlocks, aggressive));
8507 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
8510 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
8513 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
8514 - TENDSTR), dev->nErasedBlocks, maxTries, block));
8516 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
8520 - return aggressive ? gcOk : YAFFS_OK;
8523 -/*------------------------- TAGS --------------------------------*/
8525 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
8526 - int chunkInObject)
8528 - return (tags->chunkId == chunkInObject &&
8529 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
8534 -/*-------------------- Data file manipulation -----------------*/
8536 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
8537 - yaffs_ExtendedTags *tags)
8539 - /*Get the Tnode, then get the level 0 offset chunk offset */
8541 - int theChunk = -1;
8542 - yaffs_ExtendedTags localTags;
8545 - yaffs_Device *dev = in->myDev;
8548 - /* Passed a NULL, so use our own tags space */
8549 - tags = &localTags;
8552 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
8555 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8558 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
8564 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
8565 - yaffs_ExtendedTags *tags)
8567 - /* Get the Tnode, then get the level 0 offset chunk offset */
8569 - int theChunk = -1;
8570 - yaffs_ExtendedTags localTags;
8572 - yaffs_Device *dev = in->myDev;
8576 - /* Passed a NULL, so use our own tags space */
8577 - tags = &localTags;
8580 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
8584 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8587 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
8590 - /* Delete the entry in the filestructure (if found) */
8592 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
8598 -#ifdef YAFFS_PARANOID
8600 -static int yaffs_CheckFileSanity(yaffs_Object *in)
8608 - yaffs_Tags localTags;
8609 - yaffs_Tags *tags = &localTags;
8613 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
8614 - return YAFFS_FAIL;
8616 - objId = in->objectId;
8617 - fSize = in->variant.fileVariant.fileSize;
8619 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
8621 - for (chunk = 1; chunk <= nChunks; chunk++) {
8622 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
8627 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
8629 - if (yaffs_CheckChunkBits
8630 - (dev, theChunk / dev->nChunksPerBlock,
8631 - theChunk % dev->nChunksPerBlock)) {
8633 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
8636 - if (yaffs_TagsMatch
8637 - (tags, in->objectId, chunk, chunkDeleted)) {
8647 - /* T(("No level 0 found for %d\n", chunk)); */
8651 - return failed ? YAFFS_FAIL : YAFFS_OK;
8656 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
8657 - int chunkInNAND, int inScan)
8659 - /* NB inScan is zero unless scanning.
8660 - * For forward scanning, inScan is > 0;
8661 - * for backward scanning inScan is < 0
8665 - yaffs_Device *dev = in->myDev;
8666 - int existingChunk;
8667 - yaffs_ExtendedTags existingTags;
8668 - yaffs_ExtendedTags newTags;
8669 - unsigned existingSerial, newSerial;
8671 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
8672 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
8673 - * If it is not during Scanning then something went wrong!
8676 - T(YAFFS_TRACE_ERROR,
8678 - ("yaffs tragedy:attempt to put data chunk into a non-file"
8683 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
8687 - tn = yaffs_AddOrFindLevel0Tnode(dev,
8688 - &in->variant.fileVariant,
8692 - return YAFFS_FAIL;
8694 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8696 - if (inScan != 0) {
8697 - /* If we're scanning then we need to test for duplicates
8698 - * NB This does not need to be efficient since it should only ever
8699 - * happen when the power fails during a write, then only one
8700 - * chunk should ever be affected.
8702 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
8703 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
8706 - if (existingChunk > 0) {
8707 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
8708 - * thus we have to do a FindChunkInFile to get the real chunk id.
8710 - * We have a duplicate now we need to decide which one to use:
8712 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
8713 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
8714 - * YAFFS1: Get both sets of tags and compare serial numbers.
8718 - /* Only do this for forward scanning */
8719 - yaffs_ReadChunkWithTagsFromNAND(dev,
8723 - /* Do a proper find */
8725 - yaffs_FindChunkInFile(in, chunkInInode,
8729 - if (existingChunk <= 0) {
8730 - /*Hoosterman - how did this happen? */
8732 - T(YAFFS_TRACE_ERROR,
8734 - ("yaffs tragedy: existing chunk < 0 in scan"
8739 - /* NB The deleted flags should be false, otherwise the chunks will
8740 - * not be loaded during a scan
8744 - newSerial = newTags.serialNumber;
8745 - existingSerial = existingTags.serialNumber;
8748 - if ((inScan > 0) &&
8749 - (in->myDev->isYaffs2 ||
8750 - existingChunk <= 0 ||
8751 - ((existingSerial + 1) & 3) == newSerial)) {
8752 - /* Forward scanning.
8754 - * Delete the old one and drop through to update the tnode
8756 - yaffs_DeleteChunk(dev, existingChunk, 1,
8759 - /* Backward scanning or we want to use the existing one
8761 - * Delete the new one and return early so that the tnode isn't changed
8763 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
8771 - if (existingChunk == 0)
8772 - in->nDataChunks++;
8774 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
8779 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
8782 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
8784 - if (chunkInNAND >= 0)
8785 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
8788 - T(YAFFS_TRACE_NANDACCESS,
8789 - (TSTR("Chunk %d not found zero instead" TENDSTR),
8791 - /* get sane (zero) data if you read a hole */
8792 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
8798 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
8802 - yaffs_ExtendedTags tags;
8803 - yaffs_BlockInfo *bi;
8808 - dev->nDeletions++;
8809 - block = chunkId / dev->nChunksPerBlock;
8810 - page = chunkId % dev->nChunksPerBlock;
8813 - if (!yaffs_CheckChunkBit(dev, block, page))
8814 - T(YAFFS_TRACE_VERIFY,
8815 - (TSTR("Deleting invalid chunk %d"TENDSTR),
8818 - bi = yaffs_GetBlockInfo(dev, block);
8820 - T(YAFFS_TRACE_DELETION,
8821 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
8824 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
8826 - yaffs_InitialiseTags(&tags);
8828 - tags.chunkDeleted = 1;
8830 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
8831 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
8833 - dev->nUnmarkedDeletions++;
8836 - /* Pull out of the management area.
8837 - * If the whole block became dirty, this will kick off an erasure.
8839 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8840 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8841 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8842 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8843 - dev->nFreeChunks++;
8845 - yaffs_ClearChunkBit(dev, block, page);
8849 - if (bi->pagesInUse == 0 &&
8850 - !bi->hasShrinkHeader &&
8851 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8852 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8853 - yaffs_BlockBecameDirty(dev, block);
8860 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8861 - const __u8 *buffer, int nBytes,
8864 - /* Find old chunk Need to do this to get serial number
8865 - * Write new one and patch into tree.
8866 - * Invalidate old tags.
8870 - yaffs_ExtendedTags prevTags;
8873 - yaffs_ExtendedTags newTags;
8875 - yaffs_Device *dev = in->myDev;
8877 - yaffs_CheckGarbageCollection(dev);
8879 - /* Get the previous chunk at this location in the file if it exists */
8880 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8882 - /* Set up new tags */
8883 - yaffs_InitialiseTags(&newTags);
8885 - newTags.chunkId = chunkInInode;
8886 - newTags.objectId = in->objectId;
8887 - newTags.serialNumber =
8888 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8889 - newTags.byteCount = nBytes;
8891 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8892 - T(YAFFS_TRACE_ERROR,
8893 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8898 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8901 - if (newChunkId >= 0) {
8902 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8904 - if (prevChunkId >= 0)
8905 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8907 - yaffs_CheckFileSanity(in);
8909 - return newChunkId;
8913 -/* UpdateObjectHeader updates the header on NAND for an object.
8914 - * If name is not NULL, then that new name is used.
8916 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8917 - int isShrink, int shadows)
8920 - yaffs_BlockInfo *bi;
8922 - yaffs_Device *dev = in->myDev;
8929 - yaffs_ExtendedTags newTags;
8930 - yaffs_ExtendedTags oldTags;
8932 - __u8 *buffer = NULL;
8933 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8935 - yaffs_ObjectHeader *oh = NULL;
8937 + YCHAR *str = NULL;
8939 - yaffs_strcpy(oldName, _Y("silly old name"));
8940 + yaffs_dev_t *dev = parent->my_dev;
8942 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8943 + if (yaffs_find_by_name(parent, name))
8947 - in == dev->rootDir || /* The rootDir should also be saved */
8949 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8950 + str = yaffs_clone_str(aliasString);
8955 - yaffs_CheckGarbageCollection(dev);
8956 - yaffs_CheckObjectDetailsLoaded(in);
8957 + in = yaffs_new_obj(dev, -1, type);
8959 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8960 - oh = (yaffs_ObjectHeader *) buffer;
8967 - prevChunkId = in->hdrChunk;
8969 - if (prevChunkId > 0) {
8970 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8971 - buffer, &oldTags);
8973 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8975 - memcpy(oldName, oh->name, sizeof(oh->name));
8978 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8980 + in->hdr_chunk = 0;
8982 + in->variant_type = type;
8984 - oh->type = in->variantType;
8985 - oh->yst_mode = in->yst_mode;
8986 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8987 + in->yst_mode = mode;
8989 #ifdef CONFIG_YAFFS_WINCE
8990 - oh->win_atime[0] = in->win_atime[0];
8991 - oh->win_ctime[0] = in->win_ctime[0];
8992 - oh->win_mtime[0] = in->win_mtime[0];
8993 - oh->win_atime[1] = in->win_atime[1];
8994 - oh->win_ctime[1] = in->win_ctime[1];
8995 - oh->win_mtime[1] = in->win_mtime[1];
8996 + yfsd_win_file_time_now(in->win_atime);
8997 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8998 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
9001 - oh->yst_uid = in->yst_uid;
9002 - oh->yst_gid = in->yst_gid;
9003 - oh->yst_atime = in->yst_atime;
9004 - oh->yst_mtime = in->yst_mtime;
9005 - oh->yst_ctime = in->yst_ctime;
9006 - oh->yst_rdev = in->yst_rdev;
9007 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
9009 + in->yst_rdev = rdev;
9010 + in->yst_uid = uid;
9011 + in->yst_gid = gid;
9014 - oh->parentObjectId = in->parent->objectId;
9016 - oh->parentObjectId = 0;
9017 + in->n_data_chunks = 0;
9019 - if (name && *name) {
9020 - memset(oh->name, 0, sizeof(oh->name));
9021 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
9022 - } else if (prevChunkId >= 0)
9023 - memcpy(oh->name, oldName, sizeof(oh->name));
9025 - memset(oh->name, 0, sizeof(oh->name));
9026 + yaffs_set_obj_name(in, name);
9029 - oh->isShrink = isShrink;
9030 + yaffs_add_obj_to_dir(parent, in);
9032 - switch (in->variantType) {
9033 - case YAFFS_OBJECT_TYPE_UNKNOWN:
9034 - /* Should not happen */
9036 - case YAFFS_OBJECT_TYPE_FILE:
9038 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
9039 - || oh->parentObjectId ==
9040 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
9041 - fileVariant.fileSize;
9042 + in->my_dev = parent->my_dev;
9045 + case YAFFS_OBJECT_TYPE_SYMLINK:
9046 + in->variant.symlink_variant.alias = str;
9048 case YAFFS_OBJECT_TYPE_HARDLINK:
9049 - oh->equivalentObjectId =
9050 - in->variant.hardLinkVariant.equivalentObjectId;
9052 - case YAFFS_OBJECT_TYPE_SPECIAL:
9054 + in->variant.hardlink_variant.equiv_obj =
9056 + in->variant.hardlink_variant.equiv_id =
9057 + equiv_obj->obj_id;
9058 + ylist_add(&in->hard_links, &equiv_obj->hard_links);
9060 + case YAFFS_OBJECT_TYPE_FILE:
9061 case YAFFS_OBJECT_TYPE_DIRECTORY:
9064 - case YAFFS_OBJECT_TYPE_SYMLINK:
9065 - yaffs_strncpy(oh->alias,
9066 - in->variant.symLinkVariant.alias,
9067 - YAFFS_MAX_ALIAS_LENGTH);
9068 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
9069 + case YAFFS_OBJECT_TYPE_SPECIAL:
9070 + case YAFFS_OBJECT_TYPE_UNKNOWN:
9076 - yaffs_InitialiseTags(&newTags);
9078 - newTags.chunkId = 0;
9079 - newTags.objectId = in->objectId;
9080 - newTags.serialNumber = in->serial;
9082 - /* Add extra info for file header */
9084 - newTags.extraHeaderInfoAvailable = 1;
9085 - newTags.extraParentObjectId = oh->parentObjectId;
9086 - newTags.extraFileLength = oh->fileSize;
9087 - newTags.extraIsShrinkHeader = oh->isShrink;
9088 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
9089 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
9090 - newTags.extraObjectType = in->variantType;
9092 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
9094 - /* Create new chunk in NAND */
9096 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
9097 - (prevChunkId >= 0) ? 1 : 0);
9099 - if (newChunkId >= 0) {
9101 - in->hdrChunk = newChunkId;
9103 - if (prevChunkId >= 0) {
9104 - yaffs_DeleteChunk(dev, prevChunkId, 1,
9108 - if (!yaffs_ObjectHasCachedWriteData(in))
9111 - /* If this was a shrink, then mark the block that the chunk lives on */
9113 - bi = yaffs_GetBlockInfo(in->myDev,
9114 - newChunkId / in->myDev->nChunksPerBlock);
9115 - bi->hasShrinkHeader = 1;
9118 + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
9119 + /* Could not create the object header, fail the creation */
9120 + yaffs_del_obj(in);
9124 - retVal = newChunkId;
9126 + yaffs_update_parent(parent);
9130 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9136 -/*------------------------ Short Operations Cache ----------------------------------------
9137 - * In many situations where there is no high level buffering (eg WinCE) a lot of
9138 - * reads might be short sequential reads, and a lot of writes may be short
9139 - * sequential writes. eg. scanning/writing a jpeg file.
9140 - * In these cases, a short read/write cache can provide a huge perfomance benefit
9141 - * with dumb-as-a-rock code.
9142 - * In Linux, the page cache provides read buffering aand the short op cache provides write
9145 - * There are a limited number (~10) of cache chunks per device so that we don't
9146 - * need a very intelligent search.
9149 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
9150 +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
9151 + __u32 mode, __u32 uid, __u32 gid)
9153 - yaffs_Device *dev = obj->myDev;
9155 - yaffs_ChunkCache *cache;
9156 - int nCaches = obj->myDev->nShortOpCaches;
9158 - for (i = 0; i < nCaches; i++) {
9159 - cache = &dev->srCache[i];
9160 - if (cache->object == obj &&
9164 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
9165 + uid, gid, NULL, NULL, 0);
9169 +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
9170 + __u32 mode, __u32 uid, __u32 gid)
9172 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
9173 + mode, uid, gid, NULL, NULL, 0);
9176 +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
9177 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
9179 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
9180 + uid, gid, NULL, NULL, rdev);
9183 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
9184 +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
9185 + __u32 mode, __u32 uid, __u32 gid,
9186 + const YCHAR *alias)
9188 - yaffs_Device *dev = obj->myDev;
9189 - int lowest = -99; /* Stop compiler whining. */
9191 - yaffs_ChunkCache *cache;
9192 - int chunkWritten = 0;
9193 - int nCaches = obj->myDev->nShortOpCaches;
9194 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
9195 + uid, gid, NULL, alias, 0);
9198 - if (nCaches > 0) {
9201 +/* yaffs_link_obj returns the object id of the equivalent object.*/
9202 +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
9203 + yaffs_obj_t *equiv_obj)
9205 + /* Get the real object in case we were fed a hard link as an equivalent object */
9206 + equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
9208 - /* Find the dirty cache for this object with the lowest chunk id. */
9209 - for (i = 0; i < nCaches; i++) {
9210 - if (dev->srCache[i].object == obj &&
9211 - dev->srCache[i].dirty) {
9213 - || dev->srCache[i].chunkId <
9215 - cache = &dev->srCache[i];
9216 - lowest = cache->chunkId;
9220 + if (yaffs_create_obj
9221 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
9222 + equiv_obj, NULL, 0)) {
9228 - if (cache && !cache->locked) {
9229 - /* Write it out and free it up */
9233 - yaffs_WriteChunkDataToObject(cache->object,
9239 - cache->object = NULL;
9241 +static int yaffs_change_obj_name(yaffs_obj_t *obj, yaffs_obj_t *new_dir,
9242 + const YCHAR *new_name, int force, int shadows)
9247 - } while (cache && chunkWritten > 0);
9248 + yaffs_obj_t *existingTarget;
9251 - /* Hoosterman, disk full while writing cache out. */
9252 - T(YAFFS_TRACE_ERROR,
9253 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
9254 + if (new_dir == NULL)
9255 + new_dir = obj->parent; /* use the old directory */
9258 + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
9259 + T(YAFFS_TRACE_ALWAYS,
9261 + ("tragedy: yaffs_change_obj_name: new_dir is not a directory"
9267 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
9268 + if (obj->my_dev->param.is_yaffs2)
9269 + unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
9271 + unlinkOp = (new_dir == obj->my_dev->unlinked_dir
9272 + && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
9274 -/*yaffs_FlushEntireDeviceCache(dev)
9278 + deleteOp = (new_dir == obj->my_dev->del_dir);
9280 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
9282 - yaffs_Object *obj;
9283 - int nCaches = dev->nShortOpCaches;
9285 + existingTarget = yaffs_find_by_name(new_dir, new_name);
9287 - /* Find a dirty object in the cache and flush it...
9288 - * until there are no further dirty objects.
9289 + /* If the object is a file going into the unlinked directory,
9290 + * then it is OK to just stuff it in since duplicate names are allowed.
9291 + * else only proceed if the new name does not exist and if we're putting
9292 + * it into a directory.
9296 - for (i = 0; i < nCaches && !obj; i++) {
9297 - if (dev->srCache[i].object &&
9298 - dev->srCache[i].dirty)
9299 - obj = dev->srCache[i].object;
9303 - yaffs_FlushFilesChunkCache(obj);
9312 + !existingTarget) &&
9313 + new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
9314 + yaffs_set_obj_name(obj, new_name);
9317 + yaffs_add_obj_to_dir(new_dir, obj);
9319 -/* Grab us a cache chunk for use.
9320 - * First look for an empty one.
9321 - * Then look for the least recently used non-dirty one.
9322 - * Then look for the least recently used dirty one...., flush and look again.
9324 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
9328 + obj->unlinked = 1;
9330 - if (dev->nShortOpCaches > 0) {
9331 - for (i = 0; i < dev->nShortOpCaches; i++) {
9332 - if (!dev->srCache[i].object)
9333 - return &dev->srCache[i];
9335 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
9336 + if (yaffs_update_oh(obj, new_name, 0, deleteOp, shadows, NULL) >= 0)
9341 + return YAFFS_FAIL;
9344 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
9345 +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
9346 + yaffs_obj_t *new_dir, const YCHAR *new_name)
9348 - yaffs_ChunkCache *cache;
9349 - yaffs_Object *theObj;
9354 - if (dev->nShortOpCaches > 0) {
9355 - /* Try find a non-dirty one... */
9357 - cache = yaffs_GrabChunkCacheWorker(dev);
9358 + yaffs_obj_t *obj = NULL;
9359 + yaffs_obj_t *existingTarget = NULL;
9365 - /* They were all dirty, find the last recently used object and flush
9366 - * its cache, then find again.
9367 - * NB what's here is not very accurate, we actually flush the object
9368 - * the last recently used page.
9371 - /* With locking we can't assume we can use entry zero */
9372 + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
9374 + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
9381 + dev = old_dir->my_dev;
9383 - for (i = 0; i < dev->nShortOpCaches; i++) {
9384 - if (dev->srCache[i].object &&
9385 - !dev->srCache[i].locked &&
9386 - (dev->srCache[i].lastUse < usage || !cache)) {
9387 - usage = dev->srCache[i].lastUse;
9388 - theObj = dev->srCache[i].object;
9389 - cache = &dev->srCache[i];
9393 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
9394 + /* Special case for case insemsitive systems (eg. WinCE).
9395 + * While look-up is case insensitive, the name isn't.
9396 + * Therefore we might want to change x.txt to X.txt
9398 + if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0)
9402 - if (!cache || cache->dirty) {
9403 - /* Flush and try again */
9404 - yaffs_FlushFilesChunkCache(theObj);
9405 - cache = yaffs_GrabChunkCacheWorker(dev);
9407 + if(yaffs_strnlen(new_name,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
9408 + /* ENAMETOOLONG */
9409 + return YAFFS_FAIL;
9415 + obj = yaffs_find_by_name(old_dir, old_name);
9418 + if (obj && obj->rename_allowed) {
9420 -/* Find a cached chunk */
9421 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
9424 - yaffs_Device *dev = obj->myDev;
9426 - if (dev->nShortOpCaches > 0) {
9427 - for (i = 0; i < dev->nShortOpCaches; i++) {
9428 - if (dev->srCache[i].object == obj &&
9429 - dev->srCache[i].chunkId == chunkId) {
9431 + /* Now do the handling for an existing target, if there is one */
9433 - return &dev->srCache[i];
9435 + existingTarget = yaffs_find_by_name(new_dir, new_name);
9436 + if (existingTarget &&
9437 + existingTarget->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
9438 + !ylist_empty(&existingTarget->variant.dir_variant.children)) {
9439 + /* There is a target that is a non-empty directory, so we fail */
9440 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
9441 + } else if (existingTarget && existingTarget != obj) {
9442 + /* Nuke the target first, using shadowing,
9443 + * but only if it isn't the same object.
9445 + * Note we must disable gc otherwise it can mess up the shadowing.
9448 + dev->gc_disable=1;
9449 + yaffs_change_obj_name(obj, new_dir, new_name, force,
9450 + existingTarget->obj_id);
9451 + existingTarget->is_shadowed = 1;
9452 + yaffs_unlink_obj(existingTarget);
9453 + dev->gc_disable=0;
9456 + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
9458 + yaffs_update_parent(old_dir);
9459 + if(new_dir != old_dir)
9460 + yaffs_update_parent(new_dir);
9465 + return YAFFS_FAIL;
9468 -/* Mark the chunk for the least recently used algorithym */
9469 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
9471 +/*------------------------- Block Management and Page Allocation ----------------*/
9473 +static int yaffs_init_blocks(yaffs_dev_t *dev)
9475 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
9477 - if (dev->nShortOpCaches > 0) {
9478 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
9479 - /* Reset the cache usages */
9481 - for (i = 1; i < dev->nShortOpCaches; i++)
9482 - dev->srCache[i].lastUse = 0;
9483 + dev->block_info = NULL;
9484 + dev->chunk_bits = NULL;
9486 - dev->srLastUse = 0;
9488 + dev->alloc_block = -1; /* force it to get a new one */
9491 + /* If the first allocation strategy fails, thry the alternate one */
9492 + dev->block_info = YMALLOC(nBlocks * sizeof(yaffs_block_info_t));
9493 + if (!dev->block_info) {
9494 + dev->block_info = YMALLOC_ALT(nBlocks * sizeof(yaffs_block_info_t));
9495 + dev->block_info_alt = 1;
9497 + dev->block_info_alt = 0;
9499 - cache->lastUse = dev->srLastUse;
9500 + if (dev->block_info) {
9501 + /* Set up dynamic blockinfo stuff. */
9502 + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; /* round up bytes */
9503 + dev->chunk_bits = YMALLOC(dev->chunk_bit_stride * nBlocks);
9504 + if (!dev->chunk_bits) {
9505 + dev->chunk_bits = YMALLOC_ALT(dev->chunk_bit_stride * nBlocks);
9506 + dev->chunk_bits_alt = 1;
9508 + dev->chunk_bits_alt = 0;
9513 + if (dev->block_info && dev->chunk_bits) {
9514 + memset(dev->block_info, 0, nBlocks * sizeof(yaffs_block_info_t));
9515 + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * nBlocks);
9519 + return YAFFS_FAIL;
9522 -/* Invalidate a single cache page.
9523 - * Do this when a whole page gets written,
9524 - * ie the short cache for this page is no longer valid.
9526 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
9527 +static void yaffs_deinit_blocks(yaffs_dev_t *dev)
9529 - if (object->myDev->nShortOpCaches > 0) {
9530 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
9531 + if (dev->block_info_alt && dev->block_info)
9532 + YFREE_ALT(dev->block_info);
9533 + else if (dev->block_info)
9534 + YFREE(dev->block_info);
9537 - cache->object = NULL;
9540 + dev->block_info_alt = 0;
9542 -/* Invalidate all the cache pages associated with this object
9543 - * Do this whenever ther file is deleted or resized.
9545 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
9548 - yaffs_Device *dev = in->myDev;
9549 + dev->block_info = NULL;
9551 - if (dev->nShortOpCaches > 0) {
9552 - /* Invalidate it. */
9553 - for (i = 0; i < dev->nShortOpCaches; i++) {
9554 - if (dev->srCache[i].object == in)
9555 - dev->srCache[i].object = NULL;
9558 + if (dev->chunk_bits_alt && dev->chunk_bits)
9559 + YFREE_ALT(dev->chunk_bits);
9560 + else if (dev->chunk_bits)
9561 + YFREE(dev->chunk_bits);
9562 + dev->chunk_bits_alt = 0;
9563 + dev->chunk_bits = NULL;
9566 -/*--------------------- Checkpointing --------------------*/
9567 +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no)
9569 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block_no);
9573 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
9575 - yaffs_CheckpointValidity cp;
9576 + /* If the block is still healthy erase it and mark as clean.
9577 + * If the block has had a data failure, then retire it.
9580 - memset(&cp, 0, sizeof(cp));
9581 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9582 + (TSTR("yaffs_block_became_dirty block %d state %d %s"TENDSTR),
9583 + block_no, bi->block_state, (bi->needs_retiring) ? "needs retiring" : ""));
9585 - cp.structType = sizeof(cp);
9586 - cp.magic = YAFFS_MAGIC;
9587 - cp.version = YAFFS_CHECKPOINT_VERSION;
9588 - cp.head = (head) ? 1 : 0;
9589 + yaffs2_clear_oldest_dirty_seq(dev,bi);
9591 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
9594 + bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
9596 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
9598 - yaffs_CheckpointValidity cp;
9600 + /* If this is the block being garbage collected then stop gc'ing this block */
9601 + if(block_no == dev->gc_block)
9602 + dev->gc_block = 0;
9604 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9605 + /* If this block is currently the best candidate for gc then drop as a candidate */
9606 + if(block_no == dev->gc_dirtiest){
9607 + dev->gc_dirtiest = 0;
9608 + dev->gc_pages_in_use = 0;
9612 - ok = (cp.structType == sizeof(cp)) &&
9613 - (cp.magic == YAFFS_MAGIC) &&
9614 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
9615 - (cp.head == ((head) ? 1 : 0));
9616 - return ok ? 1 : 0;
9618 + if (!bi->needs_retiring) {
9619 + yaffs2_checkpt_invalidate(dev);
9620 + erasedOk = yaffs_erase_block(dev, block_no);
9622 + dev->n_erase_failures++;
9623 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9624 + (TSTR("**>> Erasure failed %d" TENDSTR), block_no));
9628 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
9629 - yaffs_Device *dev)
9631 - cp->nErasedBlocks = dev->nErasedBlocks;
9632 - cp->allocationBlock = dev->allocationBlock;
9633 - cp->allocationPage = dev->allocationPage;
9634 - cp->nFreeChunks = dev->nFreeChunks;
9636 + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || !yaffs_skip_verification(dev))) {
9638 + for (i = 0; i < dev->param.chunks_per_block; i++) {
9639 + if (!yaffs_check_chunk_erased
9640 + (dev, block_no * dev->param.chunks_per_block + i)) {
9641 + T(YAFFS_TRACE_ERROR,
9643 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9644 + TENDSTR), block_no, i));
9650 + /* Clean it up... */
9651 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
9652 + bi->seq_number = 0;
9653 + dev->n_erased_blocks++;
9654 + bi->pages_in_use = 0;
9655 + bi->soft_del_pages = 0;
9656 + bi->has_shrink_hdr = 0;
9657 + bi->skip_erased_check = 1; /* This is clean, so no need to check */
9658 + bi->gc_prioritise = 0;
9659 + yaffs_clear_chunk_bits(dev, block_no);
9661 - cp->nDeletedFiles = dev->nDeletedFiles;
9662 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9663 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9664 - cp->sequenceNumber = dev->sequenceNumber;
9665 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9666 + T(YAFFS_TRACE_ERASE,
9667 + (TSTR("Erased block %d" TENDSTR), block_no));
9669 + dev->n_free_chunks -= dev->param.chunks_per_block; /* We lost a block of free space */
9671 + yaffs_retire_block(dev, block_no);
9672 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9673 + (TSTR("**>> Block %d retired" TENDSTR), block_no));
9677 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9678 - yaffs_CheckpointDevice *cp)
9679 +static int yaffs_find_alloc_block(yaffs_dev_t *dev)
9681 - dev->nErasedBlocks = cp->nErasedBlocks;
9682 - dev->allocationBlock = cp->allocationBlock;
9683 - dev->allocationPage = cp->allocationPage;
9684 - dev->nFreeChunks = cp->nFreeChunks;
9686 - dev->nDeletedFiles = cp->nDeletedFiles;
9687 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9688 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9689 - dev->sequenceNumber = cp->sequenceNumber;
9690 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9694 + yaffs_block_info_t *bi;
9696 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9698 - yaffs_CheckpointDevice cp;
9700 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9701 + if (dev->n_erased_blocks < 1) {
9702 + /* Hoosterman we've got a problem.
9703 + * Can't get space to gc
9705 + T(YAFFS_TRACE_ERROR,
9706 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9712 - /* Write device runtime values*/
9713 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9714 - cp.structType = sizeof(cp);
9715 + /* Find an empty block. */
9717 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9718 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
9719 + dev->alloc_block_finder++;
9720 + if (dev->alloc_block_finder < dev->internal_start_block
9721 + || dev->alloc_block_finder > dev->internal_end_block) {
9722 + dev->alloc_block_finder = dev->internal_start_block;
9725 - /* Write block info */
9727 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9728 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9729 + bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
9731 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
9732 + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
9733 + dev->seq_number++;
9734 + bi->seq_number = dev->seq_number;
9735 + dev->n_erased_blocks--;
9736 + T(YAFFS_TRACE_ALLOCATE,
9737 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9738 + dev->alloc_block_finder, dev->seq_number,
9739 + dev->n_erased_blocks));
9740 + return dev->alloc_block_finder;
9744 - /* Write chunk bits */
9746 - nBytes = nBlocks * dev->chunkBitmapStride;
9747 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9749 - return ok ? 1 : 0;
9750 + T(YAFFS_TRACE_ALWAYS,
9752 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9753 + TENDSTR), dev->n_erased_blocks));
9758 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9761 + * Check if there's space to allocate...
9762 + * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()?
9764 +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks)
9766 - yaffs_CheckpointDevice cp;
9768 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9769 + int reservedChunks;
9770 + int reservedBlocks = dev->param.n_reserved_blocks;
9771 + int checkpointBlocks;
9774 + checkpointBlocks = yaffs_calc_checkpt_blocks_required(dev);
9776 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9779 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.chunks_per_block);
9781 - if (cp.structType != sizeof(cp))
9783 + return (dev->n_free_chunks > (reservedChunks + n_chunks));
9786 +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
9787 + yaffs_block_info_t **blockUsedPtr)
9790 + yaffs_block_info_t *bi;
9792 + if (dev->alloc_block < 0) {
9793 + /* Get next block to allocate off */
9794 + dev->alloc_block = yaffs_find_alloc_block(dev);
9795 + dev->alloc_page = 0;
9798 + if (!useReserve && !yaffs_check_alloc_available(dev, 1)) {
9799 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9803 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9804 + if (dev->n_erased_blocks < dev->param.n_reserved_blocks
9805 + && dev->alloc_page == 0) {
9806 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9809 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9810 + /* Next page please.... */
9811 + if (dev->alloc_block >= 0) {
9812 + bi = yaffs_get_block_info(dev, dev->alloc_block);
9814 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9815 + retVal = (dev->alloc_block * dev->param.chunks_per_block) +
9817 + bi->pages_in_use++;
9818 + yaffs_set_chunk_bit(dev, dev->alloc_block,
9823 - nBytes = nBlocks * dev->chunkBitmapStride;
9824 + dev->alloc_page++;
9826 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9827 + dev->n_free_chunks--;
9829 - return ok ? 1 : 0;
9831 + /* If the block is full set the state to full */
9832 + if (dev->alloc_page >= dev->param.chunks_per_block) {
9833 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
9834 + dev->alloc_block = -1;
9837 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9838 - yaffs_Object *obj)
9841 + *blockUsedPtr = bi;
9846 - cp->objectId = obj->objectId;
9847 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9848 - cp->hdrChunk = obj->hdrChunk;
9849 - cp->variantType = obj->variantType;
9850 - cp->deleted = obj->deleted;
9851 - cp->softDeleted = obj->softDeleted;
9852 - cp->unlinked = obj->unlinked;
9853 - cp->fake = obj->fake;
9854 - cp->renameAllowed = obj->renameAllowed;
9855 - cp->unlinkAllowed = obj->unlinkAllowed;
9856 - cp->serial = obj->serial;
9857 - cp->nDataChunks = obj->nDataChunks;
9858 + T(YAFFS_TRACE_ERROR,
9859 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9861 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9862 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9863 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9864 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9868 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9869 +static int yaffs_get_erased_chunks(yaffs_dev_t *dev)
9873 - yaffs_Object *parent;
9874 + n = dev->n_erased_blocks * dev->param.chunks_per_block;
9876 - if (obj->variantType != cp->variantType) {
9877 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9878 - TCONT("chunk %d does not match existing object type %d")
9879 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9880 - obj->variantType));
9883 + if (dev->alloc_block > 0)
9884 + n += (dev->param.chunks_per_block - dev->alloc_page);
9886 - obj->objectId = cp->objectId;
9890 - parent = yaffs_FindOrCreateObjectByNumber(
9893 - YAFFS_OBJECT_TYPE_DIRECTORY);
9899 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9900 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9901 - TCONT(" chunk %d Parent type, %d, not directory")
9903 - cp->objectId, cp->parentId, cp->variantType,
9904 - cp->hdrChunk, parent->variantType));
9907 + * yaffs_skip_rest_of_block() skips over the rest of the allocation block
9908 + * if we don't want to write to it.
9910 +void yaffs_skip_rest_of_block(yaffs_dev_t *dev)
9912 + if(dev->alloc_block > 0){
9913 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->alloc_block);
9914 + if(bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING){
9915 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
9916 + dev->alloc_block = -1;
9918 - yaffs_AddObjectToDirectory(parent, obj);
9921 - obj->hdrChunk = cp->hdrChunk;
9922 - obj->variantType = cp->variantType;
9923 - obj->deleted = cp->deleted;
9924 - obj->softDeleted = cp->softDeleted;
9925 - obj->unlinked = cp->unlinked;
9926 - obj->fake = cp->fake;
9927 - obj->renameAllowed = cp->renameAllowed;
9928 - obj->unlinkAllowed = cp->unlinkAllowed;
9929 - obj->serial = cp->serial;
9930 - obj->nDataChunks = cp->nDataChunks;
9932 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9933 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9934 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9935 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9937 - if (obj->hdrChunk > 0)
9938 - obj->lazyLoaded = 1;
9944 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9945 - __u32 level, int chunkOffset)
9946 +static int yaffs_gc_block(yaffs_dev_t *dev, int block,
9952 + int retVal = YAFFS_OK;
9954 - yaffs_Device *dev = in->myDev;
9956 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9958 - if (tnodeSize < sizeof(yaffs_Tnode))
9959 - tnodeSize = sizeof(yaffs_Tnode);
9960 + int isCheckpointBlock;
9961 + int matchingChunk;
9964 + int chunksBefore = yaffs_get_erased_chunks(dev);
9969 + yaffs_ext_tags tags;
9971 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9972 - if (tn->internal[i]) {
9973 - ok = yaffs_CheckpointTnodeWorker(in,
9976 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9979 - } else if (level == 0) {
9980 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9981 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9983 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9986 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block);
9989 + yaffs_obj_t *object;
9992 + isCheckpointBlock = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
9994 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9996 - __u32 endMarker = ~0;
9999 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
10000 - ok = yaffs_CheckpointTnodeWorker(obj,
10001 - obj->variant.fileVariant.top,
10002 - obj->variant.fileVariant.topLevel,
10005 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
10006 - sizeof(endMarker));
10008 + T(YAFFS_TRACE_TRACING,
10009 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
10011 + bi->pages_in_use,
10012 + bi->has_shrink_hdr,
10015 - return ok ? 1 : 0;
10017 + /*yaffs_verify_free_chunks(dev); */
10019 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
10023 - yaffs_Device *dev = obj->myDev;
10024 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
10027 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
10028 + if(bi->block_state == YAFFS_BLOCK_STATE_FULL)
10029 + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
10031 + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
10033 - if (tnodeSize < sizeof(yaffs_Tnode))
10034 - tnodeSize = sizeof(yaffs_Tnode);
10035 + dev->gc_disable = 1;
10037 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
10038 + if (isCheckpointBlock ||
10039 + !yaffs_still_some_chunks(dev, block)) {
10040 + T(YAFFS_TRACE_TRACING,
10042 + ("Collecting block %d that has no chunks in use" TENDSTR),
10044 + yaffs_block_became_dirty(dev, block);
10047 - while (ok && (~baseChunk)) {
10049 - /* Read level 0 tnode */
10050 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
10052 + yaffs_verify_blk(dev, bi, block);
10054 - tn = yaffs_GetTnodeRaw(dev);
10056 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
10059 + maxCopies = (wholeBlock) ? dev->param.chunks_per_block : 5;
10060 + oldChunk = block * dev->param.chunks_per_block + dev->gc_chunk;
10063 - ok = yaffs_AddOrFindLevel0Tnode(dev,
10067 + for (/* init already done */;
10068 + retVal == YAFFS_OK &&
10069 + dev->gc_chunk < dev->param.chunks_per_block &&
10070 + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
10072 + dev->gc_chunk++, oldChunk++) {
10073 + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
10076 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
10077 + /* This page is in use and might need to be copied off */
10082 - T(YAFFS_TRACE_CHECKPOINT, (
10083 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
10084 - nread, baseChunk, ok));
10087 - return ok ? 1 : 0;
10089 + yaffs_init_tags(&tags);
10091 + yaffs_rd_chunk_tags_nand(dev, oldChunk,
10094 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
10096 - yaffs_Object *obj;
10097 - yaffs_CheckpointObject cp;
10100 - struct ylist_head *lh;
10102 + yaffs_find_by_number(dev,
10105 + T(YAFFS_TRACE_GC_DETAIL,
10107 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
10108 + dev->gc_chunk, tags.obj_id, tags.chunk_id,
10111 - /* Iterate through the objects in each hash entry,
10112 - * dumping them to the checkpointing stream.
10114 + if (object && !yaffs_skip_verification(dev)) {
10115 + if (tags.chunk_id == 0)
10116 + matchingChunk = object->hdr_chunk;
10117 + else if (object->soft_del)
10118 + matchingChunk = oldChunk; /* Defeat the test */
10120 + matchingChunk = yaffs_find_chunk_in_file(object, tags.chunk_id, NULL);
10122 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
10123 - ylist_for_each(lh, &dev->objectBucket[i].list) {
10125 - obj = ylist_entry(lh, yaffs_Object, hashLink);
10126 - if (!obj->deferedFree) {
10127 - yaffs_ObjectToCheckpointObject(&cp, obj);
10128 - cp.structType = sizeof(cp);
10130 - T(YAFFS_TRACE_CHECKPOINT, (
10131 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
10132 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
10133 + if (oldChunk != matchingChunk)
10134 + T(YAFFS_TRACE_ERROR,
10135 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
10136 + oldChunk, matchingChunk, tags.obj_id, tags.chunk_id));
10138 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
10141 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
10142 - ok = yaffs_WriteCheckpointTnodes(obj);
10144 + T(YAFFS_TRACE_ERROR,
10146 + ("page %d in gc has no object: %d %d %d "
10147 + TENDSTR), oldChunk,
10148 + tags.obj_id, tags.chunk_id, tags.n_bytes));
10154 - /* Dump end of list */
10155 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
10156 - cp.structType = sizeof(cp);
10158 + object->deleted &&
10159 + object->soft_del &&
10160 + tags.chunk_id != 0) {
10161 + /* Data chunk in a soft deleted file, throw it away
10162 + * It's a soft deleted data chunk,
10163 + * No need to copy this, just forget about it and
10164 + * fix up the object.
10167 + /* Free chunks already includes softdeleted chunks.
10168 + * How ever this chunk is going to soon be really deleted
10169 + * which will increment free chunks.
10170 + * We have to decrement free chunks so this works out properly.
10172 + dev->n_free_chunks--;
10173 + bi->soft_del_pages--;
10175 + object->n_data_chunks--;
10178 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
10179 + if (object->n_data_chunks <= 0) {
10180 + /* remeber to clean up the object */
10181 + dev->gc_cleanup_list[dev->n_clean_ups] =
10183 + dev->n_clean_ups++;
10187 + /* Todo object && object->deleted && object->n_data_chunks == 0 */
10188 + /* Deleted object header with no data chunks.
10189 + * Can be discarded and the file deleted.
10191 + object->hdr_chunk = 0;
10192 + yaffs_free_tnode(object->my_dev,
10194 + file_variant.top);
10195 + object->variant.file_variant.top = NULL;
10196 + yaffs_generic_obj_del(object);
10198 - return ok ? 1 : 0;
10200 + } else if (object) {
10201 + /* It's either a data chunk in a live file or
10202 + * an ObjectHeader, so we're interested in it.
10203 + * NB Need to keep the ObjectHeaders of deleted files
10204 + * until the whole file has been deleted off
10206 + tags.serial_number++;
10208 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
10210 - yaffs_Object *obj;
10211 - yaffs_CheckpointObject cp;
10214 - yaffs_Object *hardList = NULL;
10215 + dev->n_gc_copies++;
10217 - while (ok && !done) {
10218 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
10219 - if (cp.structType != sizeof(cp)) {
10220 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
10221 - cp.structType, sizeof(cp), ok));
10225 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
10226 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
10228 - if (ok && cp.objectId == ~0)
10231 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
10233 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
10236 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
10237 - ok = yaffs_ReadCheckpointTnodes(obj);
10238 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
10239 - obj->hardLinks.next =
10240 - (struct ylist_head *) hardList;
10247 + if (tags.chunk_id == 0) {
10248 + /* It is an object Id,
10249 + * We need to nuke the shrinkheader flags first
10250 + * Also need to clean up shadowing.
10251 + * We no longer want the shrinkHeader flag since its work is done
10252 + * and if it is left in place it will mess up scanning.
10256 - yaffs_HardlinkFixup(dev, hardList);
10257 + yaffs_obj_header *oh;
10258 + oh = (yaffs_obj_header *)buffer;
10260 - return ok ? 1 : 0;
10262 + oh->is_shrink = 0;
10263 + tags.extra_is_shrink = 0;
10265 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
10267 - __u32 checkpointSum;
10269 + oh->shadows_obj = 0;
10270 + oh->inband_shadowed_obj_id = 0;
10271 + tags.extra_shadows = 0;
10273 + /* Update file size */
10274 + if(object->variant_type == YAFFS_OBJECT_TYPE_FILE){
10275 + oh->file_size = object->variant.file_variant.file_size;
10276 + tags.extra_length = oh->file_size;
10279 + yaffs_verify_oh(object, oh, &tags, 1);
10281 + yaffs_write_new_chunk(dev,(__u8 *) oh, &tags, 1);
10284 + yaffs_write_new_chunk(dev, buffer, &tags, 1);
10286 + if (newChunk < 0) {
10287 + retVal = YAFFS_FAIL;
10290 - yaffs_GetCheckpointSum(dev, &checkpointSum);
10291 + /* Ok, now fix up the Tnodes etc. */
10293 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
10294 + if (tags.chunk_id == 0) {
10295 + /* It's a header */
10296 + object->hdr_chunk = newChunk;
10297 + object->serial = tags.serial_number;
10299 + /* It's a data chunk */
10301 + ok = yaffs_put_chunk_in_file
10311 + if (retVal == YAFFS_OK)
10312 + yaffs_chunk_del(dev, oldChunk, mark_flash, __LINE__);
10319 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
10321 - __u32 checkpointSum0;
10322 - __u32 checkpointSum1;
10324 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
10326 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
10328 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
10334 - if (checkpointSum0 != checkpointSum1)
10336 + yaffs_verify_collected_blk(dev, bi, block);
10342 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
10345 + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
10347 + * The gc did not complete. Set block state back to FULL
10348 + * because checkpointing does not restore gc.
10350 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
10352 + /* The gc completed. */
10353 + /* Do any required cleanups */
10354 + for (i = 0; i < dev->n_clean_ups; i++) {
10355 + /* Time to delete the file too */
10357 + yaffs_find_by_number(dev,
10358 + dev->gc_cleanup_list[i]);
10360 + yaffs_free_tnode(dev,
10361 + object->variant.file_variant.
10363 + object->variant.file_variant.top = NULL;
10364 + T(YAFFS_TRACE_GC,
10366 + ("yaffs: About to finally delete object %d"
10367 + TENDSTR), object->obj_id));
10368 + yaffs_generic_obj_del(object);
10369 + object->my_dev->n_deleted_files--;
10372 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
10373 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
10379 - ok = yaffs_CheckpointOpen(dev, 1);
10382 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
10383 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
10386 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
10387 - ok = yaffs_WriteCheckpointDevice(dev);
10390 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
10391 - ok = yaffs_WriteCheckpointObjects(dev);
10394 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
10395 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
10396 + chunksAfter = yaffs_get_erased_chunks(dev);
10397 + if (chunksBefore >= chunksAfter) {
10398 + T(YAFFS_TRACE_GC,
10400 + ("gc did not increase free chunks before %d after %d"
10401 + TENDSTR), chunksBefore, chunksAfter));
10403 + dev->gc_block = 0;
10404 + dev->gc_chunk = 0;
10405 + dev->n_clean_ups = 0;
10409 - ok = yaffs_WriteCheckpointSum(dev);
10411 - if (!yaffs_CheckpointClose(dev))
10415 - dev->isCheckpointed = 1;
10417 - dev->isCheckpointed = 0;
10418 + dev->gc_disable = 0;
10420 - return dev->isCheckpointed;
10424 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
10426 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
10427 + * for garbage collection.
10430 +static unsigned yaffs_find_gc_block(yaffs_dev_t *dev,
10437 + unsigned selected = 0;
10438 + int prioritised = 0;
10439 + int prioritisedExists = 0;
10440 + yaffs_block_info_t *bi;
10443 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
10444 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
10447 + /* First let's see if we need to grab a prioritised block */
10448 + if (dev->has_pending_prioritised_gc && !aggressive) {
10449 + dev->gc_dirtiest = 0;
10450 + bi = dev->block_info;
10451 + for (i = dev->internal_start_block;
10452 + i <= dev->internal_end_block && !selected;
10455 + if (bi->gc_prioritise) {
10456 + prioritisedExists = 1;
10457 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
10458 + yaffs_block_ok_for_gc(dev, bi)) {
10467 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
10469 + * If there is a prioritised block and none was selected then
10470 + * this happened because there is at least one old dirty block gumming
10471 + * up the works. Let's gc the oldest dirty block.
10475 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
10476 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
10479 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
10480 - ok = yaffs_ReadCheckpointDevice(dev);
10483 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
10484 - ok = yaffs_ReadCheckpointObjects(dev);
10487 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
10488 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
10490 + if(prioritisedExists &&
10492 + dev->oldest_dirty_block > 0)
10493 + selected = dev->oldest_dirty_block;
10496 - ok = yaffs_ReadCheckpointSum(dev);
10497 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
10498 + if (!prioritisedExists) /* None found, so we can clear this */
10499 + dev->has_pending_prioritised_gc = 0;
10502 - if (!yaffs_CheckpointClose(dev))
10506 - dev->isCheckpointed = 1;
10508 - dev->isCheckpointed = 0;
10510 - return ok ? 1 : 0;
10511 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
10513 + * else (we're doing a leasurely gc), then we only bother to do this if the
10514 + * block has only a few pages in use.
10520 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
10522 + threshold = dev->param.chunks_per_block;
10523 + iterations = nBlocks;
10525 + int maxThreshold;
10527 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
10529 - if (dev->isCheckpointed ||
10530 - dev->blocksInCheckpoint > 0) {
10531 - dev->isCheckpointed = 0;
10532 - yaffs_CheckpointInvalidateStream(dev);
10533 - if (dev->superBlock && dev->markSuperBlockDirty)
10534 - dev->markSuperBlockDirty(dev->superBlock);
10538 + maxThreshold = dev->param.chunks_per_block/2;
10540 + maxThreshold = dev->param.chunks_per_block/8;
10542 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
10543 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
10545 -int yaffs_CheckpointSave(yaffs_Device *dev)
10547 + threshold = background ?
10548 + (dev->gc_not_done + 2) * 2 : 0;
10549 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10550 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10551 + if(threshold > maxThreshold)
10552 + threshold = maxThreshold;
10554 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10555 + iterations = nBlocks / 16 + 1;
10556 + if (iterations > 100)
10557 + iterations = 100;
10560 - yaffs_VerifyObjects(dev);
10561 - yaffs_VerifyBlocks(dev);
10562 - yaffs_VerifyFreeChunks(dev);
10564 + i < iterations &&
10565 + (dev->gc_dirtiest < 1 ||
10566 + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
10568 + dev->gc_block_finder++;
10569 + if (dev->gc_block_finder < dev->internal_start_block ||
10570 + dev->gc_block_finder > dev->internal_end_block)
10571 + dev->gc_block_finder = dev->internal_start_block;
10573 - if (!dev->isCheckpointed) {
10574 - yaffs_InvalidateCheckpoint(dev);
10575 - yaffs_WriteCheckpointData(dev);
10577 + bi = yaffs_get_block_info(dev, dev->gc_block_finder);
10579 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10580 + pagesUsed = bi->pages_in_use - bi->soft_del_pages;
10582 - return dev->isCheckpointed;
10584 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
10585 + pagesUsed < dev->param.chunks_per_block &&
10586 + (dev->gc_dirtiest < 1 || pagesUsed < dev->gc_pages_in_use) &&
10587 + yaffs_block_ok_for_gc(dev, bi)) {
10588 + dev->gc_dirtiest = dev->gc_block_finder;
10589 + dev->gc_pages_in_use = pagesUsed;
10593 -int yaffs_CheckpointRestore(yaffs_Device *dev)
10596 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10597 + if(dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
10598 + selected = dev->gc_dirtiest;
10601 - retval = yaffs_ReadCheckpointData(dev);
10603 + * If nothing has been selected for a while, try selecting the oldest dirty
10604 + * because that's gumming up the works.
10607 - if (dev->isCheckpointed) {
10608 - yaffs_VerifyObjects(dev);
10609 - yaffs_VerifyBlocks(dev);
10610 - yaffs_VerifyFreeChunks(dev);
10611 + if(!selected && dev->param.is_yaffs2 &&
10612 + dev->gc_not_done >= ( background ? 10 : 20)){
10613 + yaffs2_find_oldest_dirty_seq(dev);
10614 + if(dev->oldest_dirty_block > 0) {
10615 + selected = dev->oldest_dirty_block;
10616 + dev->gc_dirtiest = selected;
10617 + dev->oldest_dirty_gc_count++;
10618 + bi = yaffs_get_block_info(dev, selected);
10619 + dev->gc_pages_in_use = bi->pages_in_use - bi->soft_del_pages;
10621 + dev->gc_not_done = 0;
10624 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10626 + T(YAFFS_TRACE_GC,
10627 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10629 + dev->param.chunks_per_block - dev->gc_pages_in_use,
10632 + dev->n_gc_blocks++;
10636 + dev->gc_dirtiest = 0;
10637 + dev->gc_pages_in_use = 0;
10638 + dev->gc_not_done = 0;
10639 + if(dev->refresh_skip > 0)
10640 + dev->refresh_skip--;
10642 + dev->gc_not_done++;
10643 + T(YAFFS_TRACE_GC,
10644 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10645 + dev->gc_block_finder, dev->gc_not_done,
10647 + dev->gc_dirtiest, dev->gc_pages_in_use,
10648 + dev->oldest_dirty_block,
10649 + background ? " bg" : ""));
10656 -/*--------------------- File read/write ------------------------
10657 - * Read and write have very similar structures.
10658 - * In general the read/write has three parts to it
10659 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
10660 - * Some complete chunks
10661 - * An incomplete chunk to end off with
10662 +/* New garbage collector
10663 + * If we're very low on erased blocks then we do aggressive garbage collection
10664 + * otherwise we do "leasurely" garbage collection.
10665 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10666 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10668 - * Curve-balls: the first chunk might also be the last chunk.
10669 + * The idea is to help clear out space in a more spread-out manner.
10670 + * Dunno if it really does anything useful.
10673 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
10675 +static int yaffs_check_gc(yaffs_dev_t *dev, int background)
10677 + int aggressive = 0;
10678 + int gcOk = YAFFS_OK;
10679 + int maxTries = 0;
10681 + int erasedChunks;
10682 + int checkpointBlockAdjust;
10689 - yaffs_ChunkCache *cache;
10691 - yaffs_Device *dev;
10696 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10697 - /* start = offset % dev->nDataBytesPerChunk; */
10698 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10701 - /* OK now check for the curveball where the start and end are in
10702 - * the same chunk.
10704 - if ((start + n) < dev->nDataBytesPerChunk)
10707 - nToCopy = dev->nDataBytesPerChunk - start;
10709 - cache = yaffs_FindChunkCache(in, chunk);
10711 - /* If the chunk is already in the cache or it is less than a whole chunk
10712 - * or we're using inband tags then use the cache (if there is caching)
10713 - * else bypass the cache.
10715 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10716 - if (dev->nShortOpCaches > 0) {
10718 - /* If we can't find the data in the cache, then load it up. */
10719 + if(dev->param.gc_control &&
10720 + (dev->param.gc_control(dev) & 1) == 0)
10724 - cache = yaffs_GrabChunkCache(in->myDev);
10725 - cache->object = in;
10726 - cache->chunkId = chunk;
10727 - cache->dirty = 0;
10728 - cache->locked = 0;
10729 - yaffs_ReadChunkDataFromObject(in, chunk,
10732 - cache->nBytes = 0;
10734 + if (dev->gc_disable) {
10735 + /* Bail out so we don't get recursive gc */
10739 - yaffs_UseChunkCache(dev, cache, 0);
10740 + /* This loop should pass the first time.
10741 + * We'll only see looping here if the collection does not increase space.
10744 - cache->locked = 1;
10748 + checkpointBlockAdjust = yaffs_calc_checkpt_blocks_required(dev);
10750 - memcpy(buffer, &cache->data[start], nToCopy);
10751 + minErased = dev->param.n_reserved_blocks + checkpointBlockAdjust + 1;
10752 + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
10754 - cache->locked = 0;
10756 - /* Read into the local buffer then copy..*/
10757 + /* If we need a block soon then do aggressive gc.*/
10758 + if (dev->n_erased_blocks < minErased)
10761 + if(!background && erasedChunks > (dev->n_free_chunks / 4))
10764 - __u8 *localBuffer =
10765 - yaffs_GetTempBuffer(dev, __LINE__);
10766 - yaffs_ReadChunkDataFromObject(in, chunk,
10768 + if(dev->gc_skip > 20)
10769 + dev->gc_skip = 20;
10770 + if(erasedChunks < dev->n_free_chunks/2 ||
10771 + dev->gc_skip < 1 ||
10780 - memcpy(buffer, &localBuffer[start], nToCopy);
10781 + dev->gc_skip = 5;
10783 + /* If we don't already have a block being gc'd then see if we should start another */
10785 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10788 + if (dev->gc_block < 1 && !aggressive) {
10789 + dev->gc_block = yaffs2_find_refresh_block(dev);
10790 + dev->gc_chunk = 0;
10791 + dev->n_clean_ups=0;
10793 + if (dev->gc_block < 1) {
10794 + dev->gc_block = yaffs_find_gc_block(dev, aggressive, background);
10795 + dev->gc_chunk = 0;
10796 + dev->n_clean_ups=0;
10800 + if (dev->gc_block > 0) {
10803 + dev->passive_gc_count++;
10805 - /* A full chunk. Read directly into the supplied buffer. */
10806 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10807 + T(YAFFS_TRACE_GC,
10809 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10810 + dev->n_erased_blocks, aggressive));
10812 + gcOk = yaffs_gc_block(dev, dev->gc_block, aggressive);
10816 - offset += nToCopy;
10817 - buffer += nToCopy;
10818 - nDone += nToCopy;
10821 + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && dev->gc_block > 0) {
10822 + T(YAFFS_TRACE_GC,
10824 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10825 + TENDSTR), dev->n_erased_blocks, maxTries, dev->gc_block));
10827 + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
10828 + (dev->gc_block > 0) &&
10832 + return aggressive ? gcOk : YAFFS_OK;
10835 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10836 - int nBytes, int writeThrough)
10839 + * Garbage collects. Intended to be called from a background thread.
10840 + * Returns non-zero if at least half the free chunks are erased.
10842 +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency)
10844 + int erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
10851 - int nToWriteBack;
10852 - int startOfWrite = offset;
10853 - int chunkWritten = 0;
10854 - __u32 nBytesRead;
10855 - __u32 chunkStart;
10856 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10858 - yaffs_Device *dev;
10859 + yaffs_check_gc(dev, 1);
10860 + return erasedChunks > dev->n_free_chunks/2;
10864 +/*------------------------- TAGS --------------------------------*/
10866 - while (n > 0 && chunkWritten >= 0) {
10867 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10868 - /* start = offset % dev->nDataBytesPerChunk; */
10869 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10870 +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
10871 + int chunkInObject)
10873 + return (tags->chunk_id == chunkInObject &&
10874 + tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
10876 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10877 - start >= dev->nDataBytesPerChunk) {
10878 - T(YAFFS_TRACE_ERROR, (
10879 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10881 - (int)offset, chunk, start));
10886 - /* OK now check for the curveball where the start and end are in
10887 - * the same chunk.
10890 - if ((start + n) < dev->nDataBytesPerChunk) {
10892 +/*-------------------- Data file manipulation -----------------*/
10894 - /* Now folks, to calculate how many bytes to write back....
10895 - * If we're overwriting and not writing to then end of file then
10896 - * we need to write back as much as was there before.
10898 +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
10899 + yaffs_ext_tags *tags)
10901 + /*Get the Tnode, then get the level 0 offset chunk offset */
10902 + yaffs_tnode_t *tn;
10903 + int theChunk = -1;
10904 + yaffs_ext_tags localTags;
10907 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10908 + yaffs_dev_t *dev = in->my_dev;
10910 - if (chunkStart > in->variant.fileVariant.fileSize)
10911 - nBytesRead = 0; /* Past end of file */
10913 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10915 + /* Passed a NULL, so use our own tags space */
10916 + tags = &localTags;
10919 - if (nBytesRead > dev->nDataBytesPerChunk)
10920 - nBytesRead = dev->nDataBytesPerChunk;
10921 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
10925 - (start + n)) ? nBytesRead : (start + n);
10927 + theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
10929 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10932 + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
10939 - nToCopy = dev->nDataBytesPerChunk - start;
10940 - nToWriteBack = dev->nDataBytesPerChunk;
10942 +static int yaffs_find_del_file_chunk(yaffs_obj_t *in, int inode_chunk,
10943 + yaffs_ext_tags *tags)
10945 + /* Get the Tnode, then get the level 0 offset chunk offset */
10946 + yaffs_tnode_t *tn;
10947 + int theChunk = -1;
10948 + yaffs_ext_tags localTags;
10950 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10951 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10952 - * or we're using inband tags, so we want to use the cache buffers.
10954 - if (dev->nShortOpCaches > 0) {
10955 - yaffs_ChunkCache *cache;
10956 - /* If we can't find the data in the cache, then load the cache */
10957 - cache = yaffs_FindChunkCache(in, chunk);
10958 + yaffs_dev_t *dev = in->my_dev;
10962 - && yaffs_CheckSpaceForAllocation(in->
10964 - cache = yaffs_GrabChunkCache(in->myDev);
10965 - cache->object = in;
10966 - cache->chunkId = chunk;
10967 - cache->dirty = 0;
10968 - cache->locked = 0;
10969 - yaffs_ReadChunkDataFromObject(in, chunk,
10972 - } else if (cache &&
10974 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10975 - /* Drop the cache if it was a read cache item and
10976 - * no space check has been made for it.
10981 + /* Passed a NULL, so use our own tags space */
10982 + tags = &localTags;
10986 - yaffs_UseChunkCache(dev, cache, 1);
10987 - cache->locked = 1;
10988 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
10992 - memcpy(&cache->data[start], buffer,
10994 + theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
10997 + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
11000 - cache->locked = 0;
11001 - cache->nBytes = nToWriteBack;
11002 + /* Delete the entry in the filestructure (if found) */
11003 + if (retVal != -1)
11004 + yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
11007 - if (writeThrough) {
11009 - yaffs_WriteChunkDataToObject
11012 - cache->data, cache->nBytes,
11014 - cache->dirty = 0;
11020 - chunkWritten = -1; /* fail the write */
11023 - /* An incomplete start or end chunk (or maybe both start and end chunk)
11024 - * Read into the local buffer then copy, then copy over and write back.
11027 - __u8 *localBuffer =
11028 - yaffs_GetTempBuffer(dev, __LINE__);
11029 +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
11030 + int nand_chunk, int in_scan)
11032 + /* NB in_scan is zero unless scanning.
11033 + * For forward scanning, in_scan is > 0;
11034 + * for backward scanning in_scan is < 0
11036 + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
11039 - yaffs_ReadChunkDataFromObject(in, chunk,
11041 + yaffs_tnode_t *tn;
11042 + yaffs_dev_t *dev = in->my_dev;
11043 + int existingChunk;
11044 + yaffs_ext_tags existingTags;
11045 + yaffs_ext_tags newTags;
11046 + unsigned existingSerial, newSerial;
11048 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
11049 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
11050 + * If it is not during Scanning then something went wrong!
11053 + T(YAFFS_TRACE_ERROR,
11055 + ("yaffs tragedy:attempt to put data chunk into a non-file"
11060 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
11064 - memcpy(&localBuffer[start], buffer, nToCopy);
11065 + tn = yaffs_add_find_tnode_0(dev,
11066 + &in->variant.file_variant,
11070 + return YAFFS_FAIL;
11073 + /* Dummy insert, bail now */
11077 - yaffs_WriteChunkDataToObject(in, chunk,
11081 + existingChunk = yaffs_get_group_base(dev, tn, inode_chunk);
11083 - yaffs_ReleaseTempBuffer(dev, localBuffer,
11085 + if (in_scan != 0) {
11086 + /* If we're scanning then we need to test for duplicates
11087 + * NB This does not need to be efficient since it should only ever
11088 + * happen when the power fails during a write, then only one
11089 + * chunk should ever be affected.
11091 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
11092 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
11095 + if (existingChunk > 0) {
11096 + /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
11097 + * thus we have to do a FindChunkInFile to get the real chunk id.
11099 + * We have a duplicate now we need to decide which one to use:
11101 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
11102 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
11103 + * YAFFS1: Get both sets of tags and compare serial numbers.
11106 + if (in_scan > 0) {
11107 + /* Only do this for forward scanning */
11108 + yaffs_rd_chunk_tags_nand(dev,
11112 + /* Do a proper find */
11114 + yaffs_find_chunk_in_file(in, inode_chunk,
11119 - /* A full chunk. Write directly from the supplied buffer. */
11120 + if (existingChunk <= 0) {
11121 + /*Hoosterman - how did this happen? */
11123 + T(YAFFS_TRACE_ERROR,
11125 + ("yaffs tragedy: existing chunk < 0 in scan"
11131 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
11132 - dev->nDataBytesPerChunk,
11134 + /* NB The deleted flags should be false, otherwise the chunks will
11135 + * not be loaded during a scan
11138 - /* Since we've overwritten the cached data, we better invalidate it. */
11139 - yaffs_InvalidateChunkCache(in, chunk);
11141 + if (in_scan > 0) {
11142 + newSerial = newTags.serial_number;
11143 + existingSerial = existingTags.serial_number;
11146 - if (chunkWritten >= 0) {
11148 - offset += nToCopy;
11149 - buffer += nToCopy;
11150 - nDone += nToCopy;
11151 + if ((in_scan > 0) &&
11152 + (existingChunk <= 0 ||
11153 + ((existingSerial + 1) & 3) == newSerial)) {
11154 + /* Forward scanning.
11156 + * Delete the old one and drop through to update the tnode
11158 + yaffs_chunk_del(dev, existingChunk, 1,
11161 + /* Backward scanning or we want to use the existing one
11163 + * Delete the new one and return early so that the tnode isn't changed
11165 + yaffs_chunk_del(dev, nand_chunk, 1,
11173 - /* Update file object */
11175 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
11176 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
11177 + if (existingChunk == 0)
11178 + in->n_data_chunks++;
11181 + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
11187 +static int yaffs_rd_data_obj(yaffs_obj_t *in, int inode_chunk,
11190 + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
11192 -/* ---------------------- File resizing stuff ------------------ */
11193 + if (nand_chunk >= 0)
11194 + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
11197 + T(YAFFS_TRACE_NANDACCESS,
11198 + (TSTR("Chunk %d not found zero instead" TENDSTR),
11200 + /* get sane (zero) data if you read a hole */
11201 + memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
11207 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
11208 +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn)
11212 + yaffs_ext_tags tags;
11213 + yaffs_block_info_t *bi;
11215 - yaffs_Device *dev = in->myDev;
11216 - int oldFileSize = in->variant.fileVariant.fileSize;
11217 + if (chunk_id <= 0)
11220 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
11221 + dev->n_deletions++;
11222 + block = chunk_id / dev->param.chunks_per_block;
11223 + page = chunk_id % dev->param.chunks_per_block;
11225 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
11226 - dev->nDataBytesPerChunk;
11230 - /* Delete backwards so that we don't end up with holes if
11231 - * power is lost part-way through the operation.
11232 + if (!yaffs_check_chunk_bit(dev, block, page))
11233 + T(YAFFS_TRACE_VERIFY,
11234 + (TSTR("Deleting invalid chunk %d"TENDSTR),
11237 + bi = yaffs_get_block_info(dev, block);
11239 + yaffs2_update_oldest_dirty_seq(dev, block, bi);
11241 + T(YAFFS_TRACE_DELETION,
11242 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunk_id));
11244 + if (!dev->param.is_yaffs2 && mark_flash &&
11245 + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
11247 + yaffs_init_tags(&tags);
11249 + tags.is_deleted = 1;
11251 + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
11252 + yaffs_handle_chunk_update(dev, chunk_id, &tags);
11254 + dev->n_unmarked_deletions++;
11257 + /* Pull out of the management area.
11258 + * If the whole block became dirty, this will kick off an erasure.
11260 - for (i = lastDel; i >= startDel; i--) {
11261 - /* NB this could be optimised somewhat,
11262 - * eg. could retrieve the tags and write them without
11263 - * using yaffs_DeleteChunk
11265 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
11266 + bi->block_state == YAFFS_BLOCK_STATE_FULL ||
11267 + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
11268 + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
11269 + dev->n_free_chunks++;
11271 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
11272 - if (chunkId > 0) {
11274 - (dev->internalStartBlock * dev->nChunksPerBlock)
11276 - ((dev->internalEndBlock +
11277 - 1) * dev->nChunksPerBlock)) {
11278 - T(YAFFS_TRACE_ALWAYS,
11279 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
11282 - in->nDataChunks--;
11283 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
11285 + yaffs_clear_chunk_bit(dev, block, page);
11287 + bi->pages_in_use--;
11289 + if (bi->pages_in_use == 0 &&
11290 + !bi->has_shrink_hdr &&
11291 + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
11292 + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
11293 + yaffs_block_became_dirty(dev, block);
11300 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
11301 +static int yaffs_wr_data_obj(yaffs_obj_t *in, int inode_chunk,
11302 + const __u8 *buffer, int n_bytes,
11305 + /* Find old chunk Need to do this to get serial number
11306 + * Write new one and patch into tree.
11307 + * Invalidate old tags.
11310 - int oldFileSize = in->variant.fileVariant.fileSize;
11311 - __u32 newSizeOfPartialChunk;
11312 - int newFullChunks;
11314 + yaffs_ext_tags prevTags;
11316 - yaffs_Device *dev = in->myDev;
11318 + yaffs_ext_tags newTags;
11320 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
11321 + yaffs_dev_t *dev = in->my_dev;
11323 - yaffs_FlushFilesChunkCache(in);
11324 - yaffs_InvalidateWholeChunkCache(in);
11325 + yaffs_check_gc(dev,0);
11327 - yaffs_CheckGarbageCollection(dev);
11328 + /* Get the previous chunk at this location in the file if it exists.
11329 + * If it does not exist then put a zero into the tree. This creates
11330 + * the tnode now, rather than later when it is harder to clean up.
11332 + prevChunkId = yaffs_find_chunk_in_file(in, inode_chunk, &prevTags);
11333 + if(prevChunkId < 1 &&
11334 + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
11337 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
11338 - return YAFFS_FAIL;
11339 + /* Set up new tags */
11340 + yaffs_init_tags(&newTags);
11342 - if (newSize == oldFileSize)
11344 + newTags.chunk_id = inode_chunk;
11345 + newTags.obj_id = in->obj_id;
11346 + newTags.serial_number =
11347 + (prevChunkId > 0) ? prevTags.serial_number + 1 : 1;
11348 + newTags.n_bytes = n_bytes;
11350 - if (newSize < oldFileSize) {
11351 + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
11352 + T(YAFFS_TRACE_ERROR,
11353 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes));
11359 + yaffs_write_new_chunk(dev, buffer, &newTags,
11362 - yaffs_PruneResizedChunks(in, newSize);
11363 + if (newChunkId > 0) {
11364 + yaffs_put_chunk_in_file(in, inode_chunk, newChunkId, 0);
11366 - if (newSizeOfPartialChunk != 0) {
11367 - int lastChunk = 1 + newFullChunks;
11368 + if (prevChunkId > 0)
11369 + yaffs_chunk_del(dev, prevChunkId, 1, __LINE__);
11371 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
11372 + yaffs_verify_file_sane(in);
11374 + return newChunkId;
11376 - /* Got to read and rewrite the last chunk with its new size and zero pad */
11377 - yaffs_ReadChunkDataFromObject(in, lastChunk,
11381 - memset(localBuffer + newSizeOfPartialChunk, 0,
11382 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
11383 +/* UpdateObjectHeader updates the header on NAND for an object.
11384 + * If name is not NULL, then that new name is used.
11386 +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name, int force,
11387 + int is_shrink, int shadows, yaffs_xattr_mod *xmod)
11390 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
11391 - newSizeOfPartialChunk, 1);
11392 + yaffs_block_info_t *bi;
11394 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
11396 + yaffs_dev_t *dev = in->my_dev;
11398 - in->variant.fileVariant.fileSize = newSize;
11403 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
11405 - /* newsSize > oldFileSize */
11406 - in->variant.fileVariant.fileSize = newSize;
11409 + yaffs_ext_tags newTags;
11410 + yaffs_ext_tags oldTags;
11411 + const YCHAR *alias = NULL;
11413 + __u8 *buffer = NULL;
11414 + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
11416 - /* Write a new object header.
11417 - * show we've shrunk the file, if need be
11418 - * Do this only if the file is not in the deleted directories.
11420 - if (in->parent &&
11421 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
11422 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
11423 - yaffs_UpdateObjectHeader(in, NULL, 0,
11424 - (newSize < oldFileSize) ? 1 : 0, 0);
11425 + yaffs_obj_header *oh = NULL;
11429 + yaffs_strcpy(old_name, _Y("silly old name"));
11431 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
11433 - obj = yaffs_GetEquivalentObject(obj);
11435 - switch (obj->variantType) {
11436 - case YAFFS_OBJECT_TYPE_FILE:
11437 - return obj->variant.fileVariant.fileSize;
11438 - case YAFFS_OBJECT_TYPE_SYMLINK:
11439 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
11445 + in == dev->root_dir || /* The root_dir should also be saved */
11448 + yaffs_check_gc(dev,0);
11449 + yaffs_check_obj_details_loaded(in);
11451 + buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__);
11452 + oh = (yaffs_obj_header *) buffer;
11454 + prevChunkId = in->hdr_chunk;
11456 + if (prevChunkId > 0) {
11457 + result = yaffs_rd_chunk_tags_nand(dev, prevChunkId,
11458 + buffer, &oldTags);
11460 + yaffs_verify_oh(in, oh, &oldTags, 0);
11462 + memcpy(old_name, oh->name, sizeof(oh->name));
11463 + memset(buffer, 0xFF, sizeof(yaffs_obj_header));
11465 + memset(buffer, 0xFF, dev->data_bytes_per_chunk);
11467 + oh->type = in->variant_type;
11468 + oh->yst_mode = in->yst_mode;
11469 + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
11471 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
11475 - yaffs_FlushFilesChunkCache(in);
11476 - if (updateTime) {
11477 #ifdef CONFIG_YAFFS_WINCE
11478 - yfsd_WinFileTimeNow(in->win_mtime);
11479 + oh->win_atime[0] = in->win_atime[0];
11480 + oh->win_ctime[0] = in->win_ctime[0];
11481 + oh->win_mtime[0] = in->win_mtime[0];
11482 + oh->win_atime[1] = in->win_atime[1];
11483 + oh->win_ctime[1] = in->win_ctime[1];
11484 + oh->win_mtime[1] = in->win_mtime[1];
11486 + oh->yst_uid = in->yst_uid;
11487 + oh->yst_gid = in->yst_gid;
11488 + oh->yst_atime = in->yst_atime;
11489 + oh->yst_mtime = in->yst_mtime;
11490 + oh->yst_ctime = in->yst_ctime;
11491 + oh->yst_rdev = in->yst_rdev;
11494 + oh->parent_obj_id = in->parent->obj_id;
11496 + oh->parent_obj_id = 0;
11498 + if (name && *name) {
11499 + memset(oh->name, 0, sizeof(oh->name));
11500 + yaffs_load_oh_from_name(dev,oh->name,name);
11501 + } else if (prevChunkId > 0)
11502 + memcpy(oh->name, old_name, sizeof(oh->name));
11504 + memset(oh->name, 0, sizeof(oh->name));
11506 - in->yst_mtime = Y_CURRENT_TIME;
11507 + oh->is_shrink = is_shrink;
11510 + switch (in->variant_type) {
11511 + case YAFFS_OBJECT_TYPE_UNKNOWN:
11512 + /* Should not happen */
11514 + case YAFFS_OBJECT_TYPE_FILE:
11516 + (oh->parent_obj_id == YAFFS_OBJECTID_DELETED
11517 + || oh->parent_obj_id ==
11518 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
11519 + file_variant.file_size;
11521 + case YAFFS_OBJECT_TYPE_HARDLINK:
11523 + in->variant.hardlink_variant.equiv_id;
11525 + case YAFFS_OBJECT_TYPE_SPECIAL:
11528 + case YAFFS_OBJECT_TYPE_DIRECTORY:
11531 + case YAFFS_OBJECT_TYPE_SYMLINK:
11532 + alias = in->variant.symlink_variant.alias;
11534 + alias = _Y("no alias");
11535 + yaffs_strncpy(oh->alias,
11537 + YAFFS_MAX_ALIAS_LENGTH);
11538 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11542 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
11543 - 0) ? YAFFS_OK : YAFFS_FAIL;
11545 - retVal = YAFFS_OK;
11547 + /* process any xattrib modifications */
11549 + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
11555 + yaffs_init_tags(&newTags);
11557 + newTags.chunk_id = 0;
11558 + newTags.obj_id = in->obj_id;
11559 + newTags.serial_number = in->serial;
11561 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
11563 + /* Add extra info for file header */
11565 - /* First off, invalidate the file's data in the cache, without flushing. */
11566 - yaffs_InvalidateWholeChunkCache(in);
11567 + newTags.extra_available = 1;
11568 + newTags.extra_parent_id = oh->parent_obj_id;
11569 + newTags.extra_length = oh->file_size;
11570 + newTags.extra_is_shrink = oh->is_shrink;
11571 + newTags.extra_equiv_id = oh->equiv_id;
11572 + newTags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
11573 + newTags.extra_obj_type = in->variant_type;
11575 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
11576 - /* Move to the unlinked directory so we have a record that it was deleted. */
11577 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
11578 + yaffs_verify_oh(in, oh, &newTags, 1);
11581 + /* Create new chunk in NAND */
11583 + yaffs_write_new_chunk(dev, buffer, &newTags,
11584 + (prevChunkId > 0) ? 1 : 0);
11586 - yaffs_RemoveObjectFromDirectory(in);
11587 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
11588 - in->hdrChunk = 0;
11589 + if (newChunkId >= 0) {
11591 - yaffs_FreeObject(in);
11593 + in->hdr_chunk = newChunkId;
11596 + if (prevChunkId > 0) {
11597 + yaffs_chunk_del(dev, prevChunkId, 1,
11601 -/* yaffs_DeleteFile deletes the whole file data
11602 - * and the inode associated with the file.
11603 - * It does not delete the links associated with the file.
11605 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
11607 + if (!yaffs_obj_cache_dirty(in))
11611 - int immediateDeletion = 0;
11612 + /* If this was a shrink, then mark the block that the chunk lives on */
11614 + bi = yaffs_get_block_info(in->my_dev,
11615 + newChunkId / in->my_dev->param.chunks_per_block);
11616 + bi->has_shrink_hdr = 1;
11620 - if (!in->myInode)
11621 - immediateDeletion = 1;
11623 - if (in->inUse <= 0)
11624 - immediateDeletion = 1;
11628 + retVal = newChunkId;
11630 - if (immediateDeletion) {
11632 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
11633 - _Y("deleted"), 0, 0);
11634 - T(YAFFS_TRACE_TRACING,
11635 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
11638 - in->myDev->nDeletedFiles++;
11639 - if (1 || in->myDev->isYaffs2)
11640 - yaffs_ResizeFile(in, 0);
11641 - yaffs_SoftDeleteFile(in);
11644 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
11645 - _Y("unlinked"), 0, 0);
11649 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
11654 -int yaffs_DeleteFile(yaffs_Object *in)
11656 - int retVal = YAFFS_OK;
11657 - int deleted = in->deleted;
11659 - yaffs_ResizeFile(in, 0);
11661 - if (in->nDataChunks > 0) {
11662 - /* Use soft deletion if there is data in the file.
11663 - * That won't be the case if it has been resized to zero.
11665 - if (!in->unlinked)
11666 - retVal = yaffs_UnlinkFileIfNeeded(in);
11668 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11671 - in->myDev->nDeletedFiles++;
11672 - yaffs_SoftDeleteFile(in);
11674 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11676 - /* The file has no data chunks so we toss it immediately */
11677 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11678 - in->variant.fileVariant.top = NULL;
11679 - yaffs_DoGenericObjectDeletion(in);
11684 +/*------------------------ Short Operations Cache ----------------------------------------
11685 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11686 + * reads might be short sequential reads, and a lot of writes may be short
11687 + * sequential writes. eg. scanning/writing a jpeg file.
11688 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11689 + * with dumb-as-a-rock code.
11690 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11693 + * There are a limited number (~10) of cache chunks per device so that we don't
11694 + * need a very intelligent search.
11697 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11698 +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj)
11700 - /* First check that the directory is empty. */
11701 - if (ylist_empty(&in->variant.directoryVariant.children))
11702 - return yaffs_DoGenericObjectDeletion(in);
11703 + yaffs_dev_t *dev = obj->my_dev;
11705 + yaffs_cache_t *cache;
11706 + int nCaches = obj->my_dev->param.n_caches;
11708 - return YAFFS_FAIL;
11709 + for (i = 0; i < nCaches; i++) {
11710 + cache = &dev->cache[i];
11711 + if (cache->object == obj &&
11719 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11721 - YFREE(in->variant.symLinkVariant.alias);
11723 - return yaffs_DoGenericObjectDeletion(in);
11726 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11727 +static void yaffs_flush_file_cache(yaffs_obj_t *obj)
11729 - /* remove this hardlink from the list assocaited with the equivalent
11732 - ylist_del_init(&in->hardLinks);
11733 - return yaffs_DoGenericObjectDeletion(in);
11735 + yaffs_dev_t *dev = obj->my_dev;
11736 + int lowest = -99; /* Stop compiler whining. */
11738 + yaffs_cache_t *cache;
11739 + int chunkWritten = 0;
11740 + int nCaches = obj->my_dev->param.n_caches;
11742 -int yaffs_DeleteObject(yaffs_Object *obj)
11745 - switch (obj->variantType) {
11746 - case YAFFS_OBJECT_TYPE_FILE:
11747 - retVal = yaffs_DeleteFile(obj);
11749 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11750 - return yaffs_DeleteDirectory(obj);
11752 - case YAFFS_OBJECT_TYPE_SYMLINK:
11753 - retVal = yaffs_DeleteSymLink(obj);
11755 - case YAFFS_OBJECT_TYPE_HARDLINK:
11756 - retVal = yaffs_DeleteHardLink(obj);
11758 - case YAFFS_OBJECT_TYPE_SPECIAL:
11759 - retVal = yaffs_DoGenericObjectDeletion(obj);
11761 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11763 - break; /* should not happen. */
11765 + if (nCaches > 0) {
11771 + /* Find the dirty cache for this object with the lowest chunk id. */
11772 + for (i = 0; i < nCaches; i++) {
11773 + if (dev->cache[i].object == obj &&
11774 + dev->cache[i].dirty) {
11776 + || dev->cache[i].chunk_id <
11778 + cache = &dev->cache[i];
11779 + lowest = cache->chunk_id;
11784 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11786 + if (cache && !cache->locked) {
11787 + /* Write it out and free it up */
11789 - int immediateDeletion = 0;
11791 + yaffs_wr_data_obj(cache->object,
11796 + cache->dirty = 0;
11797 + cache->object = NULL;
11801 - if (!obj->myInode)
11802 - immediateDeletion = 1;
11804 - if (obj->inUse <= 0)
11805 - immediateDeletion = 1;
11807 + } while (cache && chunkWritten > 0);
11809 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11810 - return yaffs_DeleteHardLink(obj);
11811 - } else if (!ylist_empty(&obj->hardLinks)) {
11812 - /* Curve ball: We're unlinking an object that has a hardlink.
11814 - * This problem arises because we are not strictly following
11815 - * The Linux link/inode model.
11817 - * We can't really delete the object.
11818 - * Instead, we do the following:
11819 - * - Select a hardlink.
11820 - * - Unhook it from the hard links
11821 - * - Unhook it from its parent directory (so that the rename can work)
11822 - * - Rename the object to the hardlink's name.
11823 - * - Delete the hardlink
11826 + /* Hoosterman, disk full while writing cache out. */
11827 + T(YAFFS_TRACE_ERROR,
11828 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11830 - yaffs_Object *hl;
11832 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11836 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11839 - ylist_del_init(&hl->hardLinks);
11840 - ylist_del_init(&hl->siblings);
11841 +/*yaffs_flush_whole_cache(dev)
11846 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11847 +void yaffs_flush_whole_cache(yaffs_dev_t *dev)
11849 + yaffs_obj_t *obj;
11850 + int nCaches = dev->param.n_caches;
11853 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11854 + /* Find a dirty object in the cache and flush it...
11855 + * until there are no further dirty objects.
11859 + for (i = 0; i < nCaches && !obj; i++) {
11860 + if (dev->cache[i].object &&
11861 + dev->cache[i].dirty)
11862 + obj = dev->cache[i].object;
11864 - if (retVal == YAFFS_OK)
11865 - retVal = yaffs_DoGenericObjectDeletion(hl);
11868 + yaffs_flush_file_cache(obj);
11873 - } else if (immediateDeletion) {
11874 - switch (obj->variantType) {
11875 - case YAFFS_OBJECT_TYPE_FILE:
11876 - return yaffs_DeleteFile(obj);
11878 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11879 - return yaffs_DeleteDirectory(obj);
11881 - case YAFFS_OBJECT_TYPE_SYMLINK:
11882 - return yaffs_DeleteSymLink(obj);
11884 - case YAFFS_OBJECT_TYPE_SPECIAL:
11885 - return yaffs_DoGenericObjectDeletion(obj);
11887 - case YAFFS_OBJECT_TYPE_HARDLINK:
11888 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11890 - return YAFFS_FAIL;
11893 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11894 - _Y("unlinked"), 0, 0);
11898 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11899 +/* Grab us a cache chunk for use.
11900 + * First look for an empty one.
11901 + * Then look for the least recently used non-dirty one.
11902 + * Then look for the least recently used dirty one...., flush and look again.
11904 +static yaffs_cache_t *yaffs_grab_chunk_worker(yaffs_dev_t *dev)
11908 - if (obj && obj->unlinkAllowed)
11909 - return yaffs_UnlinkWorker(obj);
11911 - return YAFFS_FAIL;
11914 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11916 - yaffs_Object *obj;
11917 + if (dev->param.n_caches > 0) {
11918 + for (i = 0; i < dev->param.n_caches; i++) {
11919 + if (!dev->cache[i].object)
11920 + return &dev->cache[i];
11924 - obj = yaffs_FindObjectByName(dir, name);
11925 - return yaffs_UnlinkObject(obj);
11929 -/*----------------------- Initialisation Scanning ---------------------- */
11931 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11932 - int backwardScanning)
11933 +static yaffs_cache_t *yaffs_grab_chunk_cache(yaffs_dev_t *dev)
11935 - yaffs_Object *obj;
11936 + yaffs_cache_t *cache;
11937 + yaffs_obj_t *theObj;
11942 - if (!backwardScanning) {
11943 - /* Handle YAFFS1 forward scanning case
11944 - * For YAFFS1 we always do the deletion
11946 + if (dev->param.n_caches > 0) {
11947 + /* Try find a non-dirty one... */
11950 - /* Handle YAFFS2 case (backward scanning)
11951 - * If the shadowed object exists then ignore.
11953 - if (yaffs_FindObjectByNumber(dev, objId))
11956 + cache = yaffs_grab_chunk_worker(dev);
11958 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11959 - * We put it in unlinked dir to be cleaned up after the scanning
11962 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11963 - YAFFS_OBJECT_TYPE_FILE);
11966 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11967 - obj->variant.fileVariant.shrinkSize = 0;
11968 - obj->valid = 1; /* So that we don't read any other info for this file */
11970 + /* They were all dirty, find the last recently used object and flush
11971 + * its cache, then find again.
11972 + * NB what's here is not very accurate, we actually flush the object
11973 + * the last recently used page.
11977 + /* With locking we can't assume we can use entry zero */
11982 -} yaffs_BlockIndex;
11988 + for (i = 0; i < dev->param.n_caches; i++) {
11989 + if (dev->cache[i].object &&
11990 + !dev->cache[i].locked &&
11991 + (dev->cache[i].last_use < usage || !cache)) {
11992 + usage = dev->cache[i].last_use;
11993 + theObj = dev->cache[i].object;
11994 + cache = &dev->cache[i];
11999 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
12001 - yaffs_Object *hl;
12002 - yaffs_Object *in;
12003 + if (!cache || cache->dirty) {
12004 + /* Flush and try again */
12005 + yaffs_flush_file_cache(theObj);
12006 + cache = yaffs_grab_chunk_worker(dev);
12009 - while (hardList) {
12011 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
12017 - in = yaffs_FindObjectByNumber(dev,
12018 - hl->variant.hardLinkVariant.
12019 - equivalentObjectId);
12023 - /* Add the hardlink pointers */
12024 - hl->variant.hardLinkVariant.equivalentObject = in;
12025 - ylist_add(&hl->hardLinks, &in->hardLinks);
12027 - /* Todo Need to report/handle this better.
12028 - * Got a problem... hardlink to a non-existant object
12030 - hl->variant.hardLinkVariant.equivalentObject = NULL;
12031 - YINIT_LIST_HEAD(&hl->hardLinks);
12032 +/* Find a cached chunk */
12033 +static yaffs_cache_t *yaffs_find_chunk_cache(const yaffs_obj_t *obj,
12036 + yaffs_dev_t *dev = obj->my_dev;
12038 + if (dev->param.n_caches > 0) {
12039 + for (i = 0; i < dev->param.n_caches; i++) {
12040 + if (dev->cache[i].object == obj &&
12041 + dev->cache[i].chunk_id == chunk_id) {
12042 + dev->cache_hits++;
12044 + return &dev->cache[i];
12051 +/* Mark the chunk for the least recently used algorithym */
12052 +static void yaffs_use_cache(yaffs_dev_t *dev, yaffs_cache_t *cache,
12056 + if (dev->param.n_caches > 0) {
12057 + if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) {
12058 + /* Reset the cache usages */
12060 + for (i = 1; i < dev->param.n_caches; i++)
12061 + dev->cache[i].last_use = 0;
12063 + dev->cache_last_use = 0;
12066 + dev->cache_last_use++;
12068 + cache->last_use = dev->cache_last_use;
12070 -static int ybicmp(const void *a, const void *b)
12072 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
12073 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
12074 - register int ablock = ((yaffs_BlockIndex *)a)->block;
12075 - register int bblock = ((yaffs_BlockIndex *)b)->block;
12076 - if (aseq == bseq)
12077 - return ablock - bblock;
12079 - return aseq - bseq;
12081 + cache->dirty = 1;
12085 +/* Invalidate a single cache page.
12086 + * Do this when a whole page gets written,
12087 + * ie the short cache for this page is no longer valid.
12089 +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id)
12091 + if (object->my_dev->param.n_caches > 0) {
12092 + yaffs_cache_t *cache = yaffs_find_chunk_cache(object, chunk_id);
12094 -struct yaffs_ShadowFixerStruct {
12097 - struct yaffs_ShadowFixerStruct *next;
12101 + cache->object = NULL;
12105 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
12106 +/* Invalidate all the cache pages associated with this object
12107 + * Do this whenever ther file is deleted or resized.
12109 +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in)
12112 - * Sort out state of unlinked and deleted objects after scanning.
12114 - struct ylist_head *i;
12115 - struct ylist_head *n;
12118 + yaffs_dev_t *dev = in->my_dev;
12120 - /* Soft delete all the unlinked files */
12121 - ylist_for_each_safe(i, n,
12122 - &dev->unlinkedDir->variant.directoryVariant.children) {
12124 - l = ylist_entry(i, yaffs_Object, siblings);
12125 - yaffs_DeleteObject(l);
12126 + if (dev->param.n_caches > 0) {
12127 + /* Invalidate it. */
12128 + for (i = 0; i < dev->param.n_caches; i++) {
12129 + if (dev->cache[i].object == in)
12130 + dev->cache[i].object = NULL;
12135 - ylist_for_each_safe(i, n,
12136 - &dev->deletedDir->variant.directoryVariant.children) {
12138 - l = ylist_entry(i, yaffs_Object, siblings);
12139 - yaffs_DeleteObject(l);
12144 +/*--------------------- File read/write ------------------------
12145 + * Read and write have very similar structures.
12146 + * In general the read/write has three parts to it
12147 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
12148 + * Some complete chunks
12149 + * An incomplete chunk to end off with
12151 + * Curve-balls: the first chunk might also be the last chunk.
12154 -static int yaffs_Scan(yaffs_Device *dev)
12155 +int yaffs_file_rd(yaffs_obj_t *in, __u8 *buffer, loff_t offset,
12158 - yaffs_ExtendedTags tags;
12160 - int blockIterator;
12161 - int startIterator;
12168 - yaffs_BlockState state;
12169 - yaffs_Object *hardList = NULL;
12170 - yaffs_BlockInfo *bi;
12171 - __u32 sequenceNumber;
12172 - yaffs_ObjectHeader *oh;
12173 - yaffs_Object *in;
12174 - yaffs_Object *parent;
12179 + yaffs_cache_t *cache;
12181 - int alloc_failed = 0;
12182 + yaffs_dev_t *dev;
12184 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
12185 + dev = in->my_dev;
12188 + /* chunk = offset / dev->data_bytes_per_chunk + 1; */
12189 + /* start = offset % dev->data_bytes_per_chunk; */
12190 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
12194 + /* OK now check for the curveball where the start and end are in
12195 + * the same chunk.
12197 + if ((start + n) < dev->data_bytes_per_chunk)
12200 + nToCopy = dev->data_bytes_per_chunk - start;
12202 + cache = yaffs_find_chunk_cache(in, chunk);
12204 + /* If the chunk is already in the cache or it is less than a whole chunk
12205 + * or we're using inband tags then use the cache (if there is caching)
12206 + * else bypass the cache.
12208 + if (cache || nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
12209 + if (dev->param.n_caches > 0) {
12211 - T(YAFFS_TRACE_SCAN,
12212 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
12213 - dev->internalStartBlock, dev->internalEndBlock));
12214 + /* If we can't find the data in the cache, then load it up. */
12216 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12218 + cache = yaffs_grab_chunk_cache(in->my_dev);
12219 + cache->object = in;
12220 + cache->chunk_id = chunk;
12221 + cache->dirty = 0;
12222 + cache->locked = 0;
12223 + yaffs_rd_data_obj(in, chunk,
12226 + cache->n_bytes = 0;
12229 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12230 + yaffs_use_cache(dev, cache, 0);
12232 - /* Scan all the blocks to determine their state */
12233 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12234 - bi = yaffs_GetBlockInfo(dev, blk);
12235 - yaffs_ClearChunkBits(dev, blk);
12236 - bi->pagesInUse = 0;
12237 - bi->softDeletions = 0;
12238 + cache->locked = 1;
12240 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12242 - bi->blockState = state;
12243 - bi->sequenceNumber = sequenceNumber;
12244 + memcpy(buffer, &cache->data[start], nToCopy);
12246 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12247 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12248 + cache->locked = 0;
12250 + /* Read into the local buffer then copy..*/
12252 - T(YAFFS_TRACE_SCAN_DEBUG,
12253 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12254 - state, sequenceNumber));
12255 + __u8 *localBuffer =
12256 + yaffs_get_temp_buffer(dev, __LINE__);
12257 + yaffs_rd_data_obj(in, chunk,
12260 - if (state == YAFFS_BLOCK_STATE_DEAD) {
12261 - T(YAFFS_TRACE_BAD_BLOCKS,
12262 - (TSTR("block %d is bad" TENDSTR), blk));
12263 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12264 - T(YAFFS_TRACE_SCAN_DEBUG,
12265 - (TSTR("Block empty " TENDSTR)));
12266 - dev->nErasedBlocks++;
12267 - dev->nFreeChunks += dev->nChunksPerBlock;
12270 + memcpy(buffer, &localBuffer[start], nToCopy);
12272 - startIterator = dev->internalStartBlock;
12273 - endIterator = dev->internalEndBlock;
12275 - /* For each block.... */
12276 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
12277 - blockIterator++) {
12278 + yaffs_release_temp_buffer(dev, localBuffer,
12286 + /* A full chunk. Read directly into the supplied buffer. */
12287 + yaffs_rd_data_obj(in, chunk, buffer);
12289 - blk = blockIterator;
12292 - bi = yaffs_GetBlockInfo(dev, blk);
12293 - state = bi->blockState;
12295 + offset += nToCopy;
12296 + buffer += nToCopy;
12297 + nDone += nToCopy;
12302 - /* For each chunk in each block that needs scanning....*/
12303 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
12304 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
12305 - /* Read the tags and decide what to do */
12306 - chunk = blk * dev->nChunksPerBlock + c;
12310 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12312 +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
12313 + int n_bytes, int write_trhrough)
12316 - /* Let's have a good look at this chunk... */
12322 + int nToWriteBack;
12323 + int startOfWrite = offset;
12324 + int chunkWritten = 0;
12325 + __u32 n_bytesRead;
12326 + __u32 chunkStart;
12328 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
12329 - /* YAFFS1 only...
12330 - * A deleted chunk
12333 - dev->nFreeChunks++;
12334 - /*T((" %d %d deleted\n",blk,c)); */
12335 - } else if (!tags.chunkUsed) {
12336 - /* An unassigned chunk in the block
12337 - * This means that either the block is empty or
12338 - * this is the one being allocated from
12340 + yaffs_dev_t *dev;
12343 - /* We're looking at the first chunk in the block so the block is unused */
12344 - state = YAFFS_BLOCK_STATE_EMPTY;
12345 - dev->nErasedBlocks++;
12347 - /* this is the block being allocated from */
12348 - T(YAFFS_TRACE_SCAN,
12350 - (" Allocating from %d %d" TENDSTR),
12352 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12353 - dev->allocationBlock = blk;
12354 - dev->allocationPage = c;
12355 - dev->allocationBlockFinder = blk;
12356 - /* Set it to here to encourage the allocator to go forth from here. */
12357 + dev = in->my_dev;
12360 + while (n > 0 && chunkWritten >= 0) {
12361 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
12363 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
12364 - } else if (tags.chunkId > 0) {
12365 - /* chunkId > 0 so it is a data chunk... */
12366 - unsigned int endpos;
12368 - yaffs_SetChunkBit(dev, blk, c);
12369 - bi->pagesInUse++;
12371 - in = yaffs_FindOrCreateObjectByNumber(dev,
12374 - YAFFS_OBJECT_TYPE_FILE);
12375 - /* PutChunkIntoFile checks for a clash (two data chunks with
12376 - * the same chunkId).
12378 + if (chunk * dev->data_bytes_per_chunk + start != offset ||
12379 + start >= dev->data_bytes_per_chunk) {
12380 + T(YAFFS_TRACE_ERROR, (
12381 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
12383 + (int)offset, chunk, start));
12385 + chunk++; /* File pos to chunk in file offset */
12388 - alloc_failed = 1;
12389 + /* OK now check for the curveball where the start and end are in
12390 + * the same chunk.
12394 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
12395 - alloc_failed = 1;
12397 + if ((start + n) < dev->data_bytes_per_chunk) {
12401 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
12404 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12405 - && in->variant.fileVariant.scannedFileSize <
12407 - in->variant.fileVariant.
12408 - scannedFileSize = endpos;
12409 - if (!dev->useHeaderFileSize) {
12410 - in->variant.fileVariant.
12412 - in->variant.fileVariant.
12415 + /* Now folks, to calculate how many bytes to write back....
12416 + * If we're overwriting and not writing to then end of file then
12417 + * we need to write back as much as was there before.
12421 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
12423 - /* chunkId == 0, so it is an ObjectHeader.
12424 - * Thus, we read in the object header and make the object
12426 - yaffs_SetChunkBit(dev, blk, c);
12427 - bi->pagesInUse++;
12428 + chunkStart = ((chunk - 1) * dev->data_bytes_per_chunk);
12430 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
12434 - oh = (yaffs_ObjectHeader *) chunkData;
12436 - in = yaffs_FindObjectByNumber(dev,
12438 - if (in && in->variantType != oh->type) {
12439 - /* This should not happen, but somehow
12440 - * Wev'e ended up with an objectId that has been reused but not yet
12441 - * deleted, and worse still it has changed type. Delete the old object.
12443 + if (chunkStart > in->variant.file_variant.file_size)
12444 + n_bytesRead = 0; /* Past end of file */
12446 + n_bytesRead = in->variant.file_variant.file_size - chunkStart;
12448 - yaffs_DeleteObject(in);
12449 + if (n_bytesRead > dev->data_bytes_per_chunk)
12450 + n_bytesRead = dev->data_bytes_per_chunk;
12456 + (start + n)) ? n_bytesRead : (start + n);
12458 - in = yaffs_FindOrCreateObjectByNumber(dev,
12464 - alloc_failed = 1;
12466 - if (in && oh->shadowsObject > 0) {
12468 - struct yaffs_ShadowFixerStruct *fixer;
12469 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
12471 - fixer->next = shadowFixerList;
12472 - shadowFixerList = fixer;
12473 - fixer->objectId = tags.objectId;
12474 - fixer->shadowedId = oh->shadowsObject;
12476 + if (nToWriteBack < 0 || nToWriteBack > dev->data_bytes_per_chunk)
12480 + nToCopy = dev->data_bytes_per_chunk - start;
12481 + nToWriteBack = dev->data_bytes_per_chunk;
12484 + if (nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
12485 + /* An incomplete start or end chunk (or maybe both start and end chunk),
12486 + * or we're using inband tags, so we want to use the cache buffers.
12488 + if (dev->param.n_caches > 0) {
12489 + yaffs_cache_t *cache;
12490 + /* If we can't find the data in the cache, then load the cache */
12491 + cache = yaffs_find_chunk_cache(in, chunk);
12494 + && yaffs_check_alloc_available(dev, 1)) {
12495 + cache = yaffs_grab_chunk_cache(dev);
12496 + cache->object = in;
12497 + cache->chunk_id = chunk;
12498 + cache->dirty = 0;
12499 + cache->locked = 0;
12500 + yaffs_rd_data_obj(in, chunk,
12502 + } else if (cache &&
12504 + !yaffs_check_alloc_available(dev, 1)) {
12505 + /* Drop the cache if it was a read cache item and
12506 + * no space check has been made for it.
12511 - if (in && in->valid) {
12512 - /* We have already filled this one. We have a duplicate and need to resolve it. */
12514 + yaffs_use_cache(dev, cache, 1);
12515 + cache->locked = 1;
12517 - unsigned existingSerial = in->serial;
12518 - unsigned newSerial = tags.serialNumber;
12520 - if (((existingSerial + 1) & 3) == newSerial) {
12521 - /* Use new one - destroy the exisiting one */
12522 - yaffs_DeleteChunk(dev,
12527 - /* Use existing - destroy this one. */
12528 - yaffs_DeleteChunk(dev, chunk, 1,
12530 + memcpy(&cache->data[start], buffer,
12534 + cache->locked = 0;
12535 + cache->n_bytes = nToWriteBack;
12537 + if (write_trhrough) {
12539 + yaffs_wr_data_obj
12542 + cache->data, cache->n_bytes,
12544 + cache->dirty = 0;
12548 + chunkWritten = -1; /* fail the write */
12551 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12552 + * Read into the local buffer then copy, then copy over and write back.
12555 - if (in && !in->valid &&
12556 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12557 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
12558 - /* We only load some info, don't fiddle with directory structure */
12560 - in->variantType = oh->type;
12561 + __u8 *localBuffer =
12562 + yaffs_get_temp_buffer(dev, __LINE__);
12564 - in->yst_mode = oh->yst_mode;
12565 -#ifdef CONFIG_YAFFS_WINCE
12566 - in->win_atime[0] = oh->win_atime[0];
12567 - in->win_ctime[0] = oh->win_ctime[0];
12568 - in->win_mtime[0] = oh->win_mtime[0];
12569 - in->win_atime[1] = oh->win_atime[1];
12570 - in->win_ctime[1] = oh->win_ctime[1];
12571 - in->win_mtime[1] = oh->win_mtime[1];
12573 - in->yst_uid = oh->yst_uid;
12574 - in->yst_gid = oh->yst_gid;
12575 - in->yst_atime = oh->yst_atime;
12576 - in->yst_mtime = oh->yst_mtime;
12577 - in->yst_ctime = oh->yst_ctime;
12578 - in->yst_rdev = oh->yst_rdev;
12580 - in->hdrChunk = chunk;
12581 - in->serial = tags.serialNumber;
12582 + yaffs_rd_data_obj(in, chunk,
12585 - } else if (in && !in->valid) {
12586 - /* we need to load this info */
12589 - in->variantType = oh->type;
12591 - in->yst_mode = oh->yst_mode;
12592 -#ifdef CONFIG_YAFFS_WINCE
12593 - in->win_atime[0] = oh->win_atime[0];
12594 - in->win_ctime[0] = oh->win_ctime[0];
12595 - in->win_mtime[0] = oh->win_mtime[0];
12596 - in->win_atime[1] = oh->win_atime[1];
12597 - in->win_ctime[1] = oh->win_ctime[1];
12598 - in->win_mtime[1] = oh->win_mtime[1];
12600 - in->yst_uid = oh->yst_uid;
12601 - in->yst_gid = oh->yst_gid;
12602 - in->yst_atime = oh->yst_atime;
12603 - in->yst_mtime = oh->yst_mtime;
12604 - in->yst_ctime = oh->yst_ctime;
12605 - in->yst_rdev = oh->yst_rdev;
12607 - in->hdrChunk = chunk;
12608 - in->serial = tags.serialNumber;
12609 + memcpy(&localBuffer[start], buffer, nToCopy);
12611 - yaffs_SetObjectName(in, oh->name);
12614 + yaffs_wr_data_obj(in, chunk,
12619 - /* directory stuff...
12620 - * hook up to parent
12622 + yaffs_release_temp_buffer(dev, localBuffer,
12626 - yaffs_FindOrCreateObjectByNumber
12627 - (dev, oh->parentObjectId,
12628 - YAFFS_OBJECT_TYPE_DIRECTORY);
12630 - alloc_failed = 1;
12631 - if (parent && parent->variantType ==
12632 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12633 - /* Set up as a directory */
12634 - parent->variantType =
12635 - YAFFS_OBJECT_TYPE_DIRECTORY;
12636 - YINIT_LIST_HEAD(&parent->variant.
12637 - directoryVariant.
12639 - } else if (!parent || parent->variantType !=
12640 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12641 - /* Hoosterman, another problem....
12642 - * We're trying to use a non-directory as a directory
12646 - T(YAFFS_TRACE_ERROR,
12648 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12650 - parent = dev->lostNFoundDir;
12653 + /* A full chunk. Write directly from the supplied buffer. */
12655 - yaffs_AddObjectToDirectory(parent, in);
12657 - if (0 && (parent == dev->deletedDir ||
12658 - parent == dev->unlinkedDir)) {
12659 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12660 - dev->nDeletedFiles++;
12662 - /* Note re hardlinks.
12663 - * Since we might scan a hardlink before its equivalent object is scanned
12664 - * we put them all in a list.
12665 - * After scanning is complete, we should have all the objects, so we run through this
12666 - * list and fix up all the chains.
12669 - switch (in->variantType) {
12670 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12671 - /* Todo got a problem */
12673 - case YAFFS_OBJECT_TYPE_FILE:
12674 - if (dev->useHeaderFileSize)
12676 - in->variant.fileVariant.
12681 - case YAFFS_OBJECT_TYPE_HARDLINK:
12682 - in->variant.hardLinkVariant.
12683 - equivalentObjectId =
12684 - oh->equivalentObjectId;
12685 - in->hardLinks.next =
12686 - (struct ylist_head *)
12690 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12693 - case YAFFS_OBJECT_TYPE_SPECIAL:
12696 - case YAFFS_OBJECT_TYPE_SYMLINK:
12697 - in->variant.symLinkVariant.alias =
12698 - yaffs_CloneString(oh->alias);
12699 - if (!in->variant.symLinkVariant.alias)
12700 - alloc_failed = 1;
12704 + yaffs_wr_data_obj(in, chunk, buffer,
12705 + dev->data_bytes_per_chunk,
12709 - if (parent == dev->deletedDir) {
12710 - yaffs_DestroyObject(in);
12711 - bi->hasShrinkHeader = 1;
12716 + /* Since we've overwritten the cached data, we better invalidate it. */
12717 + yaffs_invalidate_chunk_cache(in, chunk);
12720 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12721 - /* If we got this far while scanning, then the block is fully allocated.*/
12722 - state = YAFFS_BLOCK_STATE_FULL;
12723 + if (chunkWritten >= 0) {
12725 + offset += nToCopy;
12726 + buffer += nToCopy;
12727 + nDone += nToCopy;
12730 - bi->blockState = state;
12733 - /* Now let's see if it was dirty */
12734 - if (bi->pagesInUse == 0 &&
12735 - !bi->hasShrinkHeader &&
12736 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12737 - yaffs_BlockBecameDirty(dev, blk);
12739 + /* Update file object */
12742 + if ((startOfWrite + nDone) > in->variant.file_variant.file_size)
12743 + in->variant.file_variant.file_size = (startOfWrite + nDone);
12747 - /* Ok, we've done all the scanning.
12748 - * Fix up the hard link chains.
12749 - * We should now have scanned all the objects, now it's time to add these
12755 - yaffs_HardlinkFixup(dev, hardList);
12756 +int yaffs_wr_file(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
12757 + int n_bytes, int write_trhrough)
12759 + yaffs2_handle_hole(in,offset);
12760 + return yaffs_do_file_wr(in,buffer,offset,n_bytes,write_trhrough);
12763 - /* Fix up any shadowed objects */
12765 - struct yaffs_ShadowFixerStruct *fixer;
12766 - yaffs_Object *obj;
12768 - while (shadowFixerList) {
12769 - fixer = shadowFixerList;
12770 - shadowFixerList = fixer->next;
12771 - /* Complete the rename transaction by deleting the shadowed object
12772 - * then setting the object header to unshadowed.
12774 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12776 - yaffs_DeleteObject(obj);
12778 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12781 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12782 +/* ---------------------- File resizing stuff ------------------ */
12787 +static void yaffs_prune_chunks(yaffs_obj_t *in, int new_size)
12790 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12791 + yaffs_dev_t *dev = in->my_dev;
12792 + int oldFileSize = in->variant.file_variant.file_size;
12794 - if (alloc_failed)
12795 - return YAFFS_FAIL;
12796 + int lastDel = 1 + (oldFileSize - 1) / dev->data_bytes_per_chunk;
12798 + int startDel = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
12799 + dev->data_bytes_per_chunk;
12803 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12804 + /* Delete backwards so that we don't end up with holes if
12805 + * power is lost part-way through the operation.
12807 + for (i = lastDel; i >= startDel; i--) {
12808 + /* NB this could be optimised somewhat,
12809 + * eg. could retrieve the tags and write them without
12810 + * using yaffs_chunk_del
12813 + chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
12814 + if (chunk_id > 0) {
12816 + (dev->internal_start_block * dev->param.chunks_per_block)
12818 + ((dev->internal_end_block +
12819 + 1) * dev->param.chunks_per_block)) {
12820 + T(YAFFS_TRACE_ALWAYS,
12821 + (TSTR("Found daft chunk_id %d for %d" TENDSTR),
12824 + in->n_data_chunks--;
12825 + yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
12833 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12836 - yaffs_ObjectHeader *oh;
12837 - yaffs_Device *dev;
12838 - yaffs_ExtendedTags tags;
12840 - int alloc_failed = 0;
12844 +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size)
12846 + int newFullChunks;
12847 + __u32 new_sizeOfPartialChunk;
12848 + yaffs_dev_t *dev = obj->my_dev;
12851 + yaffs_addr_to_chunk(dev, new_size, &newFullChunks, &new_sizeOfPartialChunk);
12854 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12856 - in->lazyLoaded ? "not yet" : "already"));
12858 + yaffs_prune_chunks(obj, new_size);
12860 - if (in->lazyLoaded && in->hdrChunk > 0) {
12861 - in->lazyLoaded = 0;
12862 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12863 + if (new_sizeOfPartialChunk != 0) {
12864 + int lastChunk = 1 + newFullChunks;
12865 + __u8 *localBuffer = yaffs_get_temp_buffer(dev, __LINE__);
12867 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12868 - oh = (yaffs_ObjectHeader *) chunkData;
12869 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12870 + yaffs_rd_data_obj(obj, lastChunk, localBuffer);
12871 + memset(localBuffer + new_sizeOfPartialChunk, 0,
12872 + dev->data_bytes_per_chunk - new_sizeOfPartialChunk);
12874 - in->yst_mode = oh->yst_mode;
12875 -#ifdef CONFIG_YAFFS_WINCE
12876 - in->win_atime[0] = oh->win_atime[0];
12877 - in->win_ctime[0] = oh->win_ctime[0];
12878 - in->win_mtime[0] = oh->win_mtime[0];
12879 - in->win_atime[1] = oh->win_atime[1];
12880 - in->win_ctime[1] = oh->win_ctime[1];
12881 - in->win_mtime[1] = oh->win_mtime[1];
12883 - in->yst_uid = oh->yst_uid;
12884 - in->yst_gid = oh->yst_gid;
12885 - in->yst_atime = oh->yst_atime;
12886 - in->yst_mtime = oh->yst_mtime;
12887 - in->yst_ctime = oh->yst_ctime;
12888 - in->yst_rdev = oh->yst_rdev;
12889 + yaffs_wr_data_obj(obj, lastChunk, localBuffer,
12890 + new_sizeOfPartialChunk, 1);
12893 - yaffs_SetObjectName(in, oh->name);
12894 + yaffs_release_temp_buffer(dev, localBuffer, __LINE__);
12897 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12898 - in->variant.symLinkVariant.alias =
12899 - yaffs_CloneString(oh->alias);
12900 - if (!in->variant.symLinkVariant.alias)
12901 - alloc_failed = 1; /* Not returned to caller */
12903 + obj->variant.file_variant.file_size = new_size;
12905 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12907 + yaffs_prune_tree(dev, &obj->variant.file_variant);
12910 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12912 - yaffs_ExtendedTags tags;
12914 - int blockIterator;
12915 - int startIterator;
12917 - int nBlocksToScan = 0;
12923 - yaffs_BlockState state;
12924 - yaffs_Object *hardList = NULL;
12925 - yaffs_BlockInfo *bi;
12926 - __u32 sequenceNumber;
12927 - yaffs_ObjectHeader *oh;
12928 - yaffs_Object *in;
12929 - yaffs_Object *parent;
12930 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12936 - int foundChunksInBlock;
12937 - int equivalentObjectId;
12938 - int alloc_failed = 0;
12939 +int yaffs_resize_file(yaffs_obj_t *in, loff_t new_size)
12941 + yaffs_dev_t *dev = in->my_dev;
12942 + int oldFileSize = in->variant.file_variant.file_size;
12944 + yaffs_flush_file_cache(in);
12945 + yaffs_invalidate_whole_cache(in);
12947 - yaffs_BlockIndex *blockIndex = NULL;
12948 - int altBlockIndex = 0;
12949 + yaffs_check_gc(dev,0);
12951 - if (!dev->isYaffs2) {
12952 - T(YAFFS_TRACE_SCAN,
12953 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12954 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
12958 - T(YAFFS_TRACE_SCAN,
12960 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12961 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12962 + if (new_size == oldFileSize)
12965 + if(new_size > oldFileSize){
12966 + yaffs2_handle_hole(in,new_size);
12967 + in->variant.file_variant.file_size = new_size;
12969 + /* new_size < oldFileSize */
12970 + yaffs_resize_file_down(in, new_size);
12973 + /* Write a new object header to reflect the resize.
12974 + * show we've shrunk the file, if need be
12975 + * Do this only if the file is not in the deleted directories
12976 + * and is not shadowed.
12978 + if (in->parent &&
12979 + !in->is_shadowed &&
12980 + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
12981 + in->parent->obj_id != YAFFS_OBJECTID_DELETED)
12982 + yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
12984 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12986 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12990 - if (!blockIndex) {
12991 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12992 - altBlockIndex = 1;
12994 +loff_t yaffs_get_file_size(yaffs_obj_t *obj)
12996 + YCHAR *alias = NULL;
12997 + obj = yaffs_get_equivalent_obj(obj);
12999 - if (!blockIndex) {
13000 - T(YAFFS_TRACE_SCAN,
13001 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
13002 - return YAFFS_FAIL;
13003 + switch (obj->variant_type) {
13004 + case YAFFS_OBJECT_TYPE_FILE:
13005 + return obj->variant.file_variant.file_size;
13006 + case YAFFS_OBJECT_TYPE_SYMLINK:
13007 + alias = obj->variant.symlink_variant.alias;
13010 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
13016 - dev->blocksInCheckpoint = 0;
13018 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13020 - /* Scan all the blocks to determine their state */
13021 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
13022 - bi = yaffs_GetBlockInfo(dev, blk);
13023 - yaffs_ClearChunkBits(dev, blk);
13024 - bi->pagesInUse = 0;
13025 - bi->softDeletions = 0;
13027 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
13029 - bi->blockState = state;
13030 - bi->sequenceNumber = sequenceNumber;
13032 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
13033 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
13034 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
13035 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
13036 +int yaffs_flush_file(yaffs_obj_t *in, int update_time, int data_sync)
13040 + yaffs_flush_file_cache(in);
13041 + if(data_sync) /* Only sync data */
13044 + if (update_time) {
13045 +#ifdef CONFIG_YAFFS_WINCE
13046 + yfsd_win_file_time_now(in->win_mtime);
13049 - T(YAFFS_TRACE_SCAN_DEBUG,
13050 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
13051 - state, sequenceNumber));
13052 + in->yst_mtime = Y_CURRENT_TIME;
13057 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
13058 - dev->blocksInCheckpoint++;
13059 + retVal = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >=
13060 + 0) ? YAFFS_OK : YAFFS_FAIL;
13063 + retVal = YAFFS_OK;
13066 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
13067 - T(YAFFS_TRACE_BAD_BLOCKS,
13068 - (TSTR("block %d is bad" TENDSTR), blk));
13069 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
13070 - T(YAFFS_TRACE_SCAN_DEBUG,
13071 - (TSTR("Block empty " TENDSTR)));
13072 - dev->nErasedBlocks++;
13073 - dev->nFreeChunks += dev->nChunksPerBlock;
13074 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13077 - /* Determine the highest sequence number */
13078 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
13079 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
13082 - blockIndex[nBlocksToScan].seq = sequenceNumber;
13083 - blockIndex[nBlocksToScan].block = blk;
13084 +static int yaffs_generic_obj_del(yaffs_obj_t *in)
13088 + /* First off, invalidate the file's data in the cache, without flushing. */
13089 + yaffs_invalidate_whole_cache(in);
13091 - if (sequenceNumber >= dev->sequenceNumber)
13092 - dev->sequenceNumber = sequenceNumber;
13094 - /* TODO: Nasty sequence number! */
13095 - T(YAFFS_TRACE_SCAN,
13097 - ("Block scanning block %d has bad sequence number %d"
13098 - TENDSTR), blk, sequenceNumber));
13099 + if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) {
13100 + /* Move to the unlinked directory so we have a record that it was deleted. */
13101 + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, 0);
13107 - T(YAFFS_TRACE_SCAN,
13108 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
13109 + yaffs_remove_obj_from_dir(in);
13110 + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
13111 + in->hdr_chunk = 0;
13113 + yaffs_free_obj(in);
13119 +/* yaffs_del_file deletes the whole file data
13120 + * and the inode associated with the file.
13121 + * It does not delete the links associated with the file.
13123 +static int yaffs_unlink_file_if_needed(yaffs_obj_t *in)
13126 - /* Sort the blocks */
13127 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
13129 - /* Use qsort now. */
13130 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
13134 - /* Dungy old bubble sort... */
13136 + int immediateDeletion = 0;
13137 + yaffs_dev_t *dev = in->my_dev;
13139 - yaffs_BlockIndex temp;
13142 + if (!in->my_inode)
13143 + immediateDeletion = 1;
13145 - for (i = 0; i < nBlocksToScan; i++)
13146 - for (j = i + 1; j < nBlocksToScan; j++)
13147 - if (blockIndex[i].seq > blockIndex[j].seq) {
13148 - temp = blockIndex[j];
13149 - blockIndex[j] = blockIndex[i];
13150 - blockIndex[i] = temp;
13152 + if (immediateDeletion) {
13154 + yaffs_change_obj_name(in, in->my_dev->del_dir,
13155 + _Y("deleted"), 0, 0);
13156 + T(YAFFS_TRACE_TRACING,
13157 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
13160 + in->my_dev->n_deleted_files++;
13161 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
13162 + yaffs_resize_file(in, 0);
13163 + yaffs_soft_del_file(in);
13166 + yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
13167 + _Y("unlinked"), 0, 0);
13173 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
13177 - /* Now scan the blocks looking at the data. */
13178 - startIterator = 0;
13179 - endIterator = nBlocksToScan - 1;
13180 - T(YAFFS_TRACE_SCAN_DEBUG,
13181 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
13182 +int yaffs_del_file(yaffs_obj_t *in)
13184 + int retVal = YAFFS_OK;
13185 + int deleted; /* Need to cache value on stack if in is freed */
13186 + yaffs_dev_t *dev = in->my_dev;
13188 - /* For each block.... backwards */
13189 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
13190 - blockIterator--) {
13191 - /* Cooperative multitasking! This loop can run for so
13192 - long that watchdog timers expire. */
13194 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
13195 + yaffs_resize_file(in, 0);
13197 - /* get the block to scan in the correct order */
13198 - blk = blockIndex[blockIterator].block;
13199 + if (in->n_data_chunks > 0) {
13200 + /* Use soft deletion if there is data in the file.
13201 + * That won't be the case if it has been resized to zero.
13203 + if (!in->unlinked)
13204 + retVal = yaffs_unlink_file_if_needed(in);
13206 - bi = yaffs_GetBlockInfo(dev, blk);
13207 + deleted = in->deleted;
13209 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
13212 + in->my_dev->n_deleted_files++;
13213 + yaffs_soft_del_file(in);
13215 + return deleted ? YAFFS_OK : YAFFS_FAIL;
13217 + /* The file has no data chunks so we toss it immediately */
13218 + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
13219 + in->variant.file_variant.top = NULL;
13220 + yaffs_generic_obj_del(in);
13222 - state = bi->blockState;
13228 +static int yaffs_is_non_empty_dir(yaffs_obj_t *obj)
13230 + return (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
13231 + !(ylist_empty(&obj->variant.dir_variant.children));
13234 - /* For each chunk in each block that needs scanning.... */
13235 - foundChunksInBlock = 0;
13236 - for (c = dev->nChunksPerBlock - 1;
13237 - !alloc_failed && c >= 0 &&
13238 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
13239 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
13240 - /* Scan backwards...
13241 - * Read the tags and decide what to do
13243 +static int yaffs_del_dir(yaffs_obj_t *obj)
13245 + /* First check that the directory is empty. */
13246 + if (yaffs_is_non_empty_dir(obj))
13247 + return YAFFS_FAIL;
13249 - chunk = blk * dev->nChunksPerBlock + c;
13250 + return yaffs_generic_obj_del(obj);
13253 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
13255 +static int yaffs_del_symlink(yaffs_obj_t *in)
13257 + if(in->variant.symlink_variant.alias)
13258 + YFREE(in->variant.symlink_variant.alias);
13259 + in->variant.symlink_variant.alias=NULL;
13261 - /* Let's have a good look at this chunk... */
13262 + return yaffs_generic_obj_del(in);
13265 - if (!tags.chunkUsed) {
13266 - /* An unassigned chunk in the block.
13267 - * If there are used chunks after this one, then
13268 - * it is a chunk that was skipped due to failing the erased
13269 - * check. Just skip it so that it can be deleted.
13270 - * But, more typically, We get here when this is an unallocated
13271 - * chunk and his means that either the block is empty or
13272 - * this is the one being allocated from
13274 +static int yaffs_del_link(yaffs_obj_t *in)
13276 + /* remove this hardlink from the list assocaited with the equivalent
13279 + ylist_del_init(&in->hard_links);
13280 + return yaffs_generic_obj_del(in);
13283 - if (foundChunksInBlock) {
13284 - /* This is a chunk that was skipped due to failing the erased check */
13285 - } else if (c == 0) {
13286 - /* We're looking at the first chunk in the block so the block is unused */
13287 - state = YAFFS_BLOCK_STATE_EMPTY;
13288 - dev->nErasedBlocks++;
13290 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
13291 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
13292 - if (dev->sequenceNumber == bi->sequenceNumber) {
13293 - /* this is the block being allocated from */
13295 - T(YAFFS_TRACE_SCAN,
13297 - (" Allocating from %d %d"
13298 - TENDSTR), blk, c));
13300 - state = YAFFS_BLOCK_STATE_ALLOCATING;
13301 - dev->allocationBlock = blk;
13302 - dev->allocationPage = c;
13303 - dev->allocationBlockFinder = blk;
13305 - /* This is a partially written block that is not
13306 - * the current allocation block. This block must have
13307 - * had a write failure, so set up for retirement.
13310 - /* bi->needsRetiring = 1; ??? TODO */
13311 - bi->gcPrioritise = 1;
13313 - T(YAFFS_TRACE_ALWAYS,
13314 - (TSTR("Partially written block %d detected" TENDSTR),
13319 +int yaffs_del_obj(yaffs_obj_t *obj)
13322 + switch (obj->variant_type) {
13323 + case YAFFS_OBJECT_TYPE_FILE:
13324 + retVal = yaffs_del_file(obj);
13326 + case YAFFS_OBJECT_TYPE_DIRECTORY:
13327 + if(!ylist_empty(&obj->variant.dir_variant.dirty)){
13328 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->obj_id));
13329 + ylist_del_init(&obj->variant.dir_variant.dirty);
13331 + return yaffs_del_dir(obj);
13333 + case YAFFS_OBJECT_TYPE_SYMLINK:
13334 + retVal = yaffs_del_symlink(obj);
13336 + case YAFFS_OBJECT_TYPE_HARDLINK:
13337 + retVal = yaffs_del_link(obj);
13339 + case YAFFS_OBJECT_TYPE_SPECIAL:
13340 + retVal = yaffs_generic_obj_del(obj);
13342 + case YAFFS_OBJECT_TYPE_UNKNOWN:
13344 + break; /* should not happen. */
13347 - dev->nFreeChunks++;
13351 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
13352 - T(YAFFS_TRACE_SCAN,
13353 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
13356 - dev->nFreeChunks++;
13358 - } else if (tags.chunkId > 0) {
13359 - /* chunkId > 0 so it is a data chunk... */
13360 - unsigned int endpos;
13361 - __u32 chunkBase =
13362 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
13364 - foundChunksInBlock = 1;
13367 - yaffs_SetChunkBit(dev, blk, c);
13368 - bi->pagesInUse++;
13370 - in = yaffs_FindOrCreateObjectByNumber(dev,
13373 - YAFFS_OBJECT_TYPE_FILE);
13375 - /* Out of memory */
13376 - alloc_failed = 1;
13378 +static int yaffs_unlink_worker(yaffs_obj_t *obj)
13382 - in->variantType == YAFFS_OBJECT_TYPE_FILE
13384 - in->variant.fileVariant.shrinkSize) {
13385 - /* This has not been invalidated by a resize */
13386 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
13388 - alloc_failed = 1;
13390 + int immediateDeletion = 0;
13392 - /* File size is calculated by looking at the data chunks if we have not
13393 - * seen an object header yet. Stop this practice once we find an object header.
13397 - 1) * dev->nDataBytesPerChunk +
13400 - if (!in->valid && /* have not got an object header yet */
13401 - in->variant.fileVariant.
13402 - scannedFileSize < endpos) {
13403 - in->variant.fileVariant.
13404 - scannedFileSize = endpos;
13405 - in->variant.fileVariant.
13407 - in->variant.fileVariant.
13410 + if (!obj->my_inode)
13411 + immediateDeletion = 1;
13414 - /* This chunk has been invalidated by a resize, so delete */
13415 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13417 + yaffs_update_parent(obj->parent);
13421 - /* chunkId == 0, so it is an ObjectHeader.
13422 - * Thus, we read in the object header and make the object
13424 - foundChunksInBlock = 1;
13425 + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
13426 + return yaffs_del_link(obj);
13427 + } else if (!ylist_empty(&obj->hard_links)) {
13428 + /* Curve ball: We're unlinking an object that has a hardlink.
13430 + * This problem arises because we are not strictly following
13431 + * The Linux link/inode model.
13433 + * We can't really delete the object.
13434 + * Instead, we do the following:
13435 + * - Select a hardlink.
13436 + * - Unhook it from the hard links
13437 + * - Move it from its parent directory (so that the rename can work)
13438 + * - Rename the object to the hardlink's name.
13439 + * - Delete the hardlink
13442 - yaffs_SetChunkBit(dev, blk, c);
13443 - bi->pagesInUse++;
13445 + yaffs_obj_t *parent;
13447 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
13451 + hl = ylist_entry(obj->hard_links.next, yaffs_obj_t, hard_links);
13453 - if (tags.extraHeaderInfoAvailable) {
13454 - in = yaffs_FindOrCreateObjectByNumber
13455 - (dev, tags.objectId,
13456 - tags.extraObjectType);
13458 - alloc_failed = 1;
13460 + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
13461 + parent = hl->parent;
13464 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
13467 - tags.extraShadows ||
13469 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13470 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
13472 - /* If we don't have valid info then we need to read the chunk
13473 - * TODO In future we can probably defer reading the chunk and
13474 - * living with invalid data until needed.
13476 + ylist_del_init(&hl->hard_links);
13478 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
13483 - oh = (yaffs_ObjectHeader *) chunkData;
13485 - if (dev->inbandTags) {
13486 - /* Fix up the header if they got corrupted by inband tags */
13487 - oh->shadowsObject = oh->inbandShadowsObject;
13488 - oh->isShrink = oh->inbandIsShrink;
13490 + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
13493 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
13495 - alloc_failed = 1;
13497 + retVal = yaffs_change_obj_name(obj,parent, name, 0, 0);
13500 + if (retVal == YAFFS_OK)
13501 + retVal = yaffs_generic_obj_del(hl);
13504 - /* TODO Hoosterman we have a problem! */
13505 - T(YAFFS_TRACE_ERROR,
13507 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
13508 - TENDSTR), tags.objectId, chunk));
13514 - /* We have already filled this one.
13515 - * We have a duplicate that will be discarded, but
13516 - * we first have to suck out resize info if it is a file.
13518 + } else if (immediateDeletion) {
13519 + switch (obj->variant_type) {
13520 + case YAFFS_OBJECT_TYPE_FILE:
13521 + return yaffs_del_file(obj);
13523 + case YAFFS_OBJECT_TYPE_DIRECTORY:
13524 + ylist_del_init(&obj->variant.dir_variant.dirty);
13525 + return yaffs_del_dir(obj);
13527 + case YAFFS_OBJECT_TYPE_SYMLINK:
13528 + return yaffs_del_symlink(obj);
13530 + case YAFFS_OBJECT_TYPE_SPECIAL:
13531 + return yaffs_generic_obj_del(obj);
13533 + case YAFFS_OBJECT_TYPE_HARDLINK:
13534 + case YAFFS_OBJECT_TYPE_UNKNOWN:
13536 + return YAFFS_FAIL;
13538 + } else if(yaffs_is_non_empty_dir(obj))
13539 + return YAFFS_FAIL;
13541 + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
13542 + _Y("unlinked"), 0, 0);
13545 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
13547 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
13548 - (tags.extraHeaderInfoAvailable &&
13549 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
13551 - (oh) ? oh->fileSize : tags.
13553 - __u32 parentObjectId =
13555 - parentObjectId : tags.
13556 - extraParentObjectId;
13560 - (oh) ? oh->isShrink : tags.
13561 - extraIsShrinkHeader;
13563 - /* If it is deleted (unlinked at start also means deleted)
13564 - * we treat the file size as being zeroed at this point.
13566 - if (parentObjectId ==
13567 - YAFFS_OBJECTID_DELETED
13568 - || parentObjectId ==
13569 - YAFFS_OBJECTID_UNLINKED) {
13573 +static int yaffs_unlink_obj(yaffs_obj_t *obj)
13577 - in->variant.fileVariant.
13578 - shrinkSize > thisSize) {
13579 - in->variant.fileVariant.
13583 + if (obj && obj->unlink_allowed)
13584 + return yaffs_unlink_worker(obj);
13587 - bi->hasShrinkHeader = 1;
13588 + return YAFFS_FAIL;
13591 - /* Use existing - destroy this one. */
13592 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13594 +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name)
13596 + yaffs_obj_t *obj;
13599 + obj = yaffs_find_by_name(dir, name);
13600 + return yaffs_unlink_obj(obj);
13603 - if (!in->valid && in->variantType !=
13604 - (oh ? oh->type : tags.extraObjectType))
13605 - T(YAFFS_TRACE_ERROR, (
13606 - TSTR("yaffs tragedy: Bad object type, "
13607 - TCONT("%d != %d, for object %d at chunk ")
13608 - TCONT("%d during scan")
13610 - oh->type : tags.extraObjectType,
13611 - in->variantType, tags.objectId,
13614 - if (!in->valid &&
13615 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13617 - YAFFS_OBJECTID_LOSTNFOUND)) {
13618 - /* We only load some info, don't fiddle with directory structure */
13620 +/*----------------------- Initialisation Scanning ---------------------- */
13623 - in->variantType = oh->type;
13624 +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
13625 + int backward_scanning)
13627 + yaffs_obj_t *obj;
13629 - in->yst_mode = oh->yst_mode;
13630 -#ifdef CONFIG_YAFFS_WINCE
13631 - in->win_atime[0] = oh->win_atime[0];
13632 - in->win_ctime[0] = oh->win_ctime[0];
13633 - in->win_mtime[0] = oh->win_mtime[0];
13634 - in->win_atime[1] = oh->win_atime[1];
13635 - in->win_ctime[1] = oh->win_ctime[1];
13636 - in->win_mtime[1] = oh->win_mtime[1];
13638 - in->yst_uid = oh->yst_uid;
13639 - in->yst_gid = oh->yst_gid;
13640 - in->yst_atime = oh->yst_atime;
13641 - in->yst_mtime = oh->yst_mtime;
13642 - in->yst_ctime = oh->yst_ctime;
13643 - in->yst_rdev = oh->yst_rdev;
13644 + if (!backward_scanning) {
13645 + /* Handle YAFFS1 forward scanning case
13646 + * For YAFFS1 we always do the deletion
13651 - in->variantType = tags.extraObjectType;
13652 - in->lazyLoaded = 1;
13655 + /* Handle YAFFS2 case (backward scanning)
13656 + * If the shadowed object exists then ignore.
13658 + obj = yaffs_find_by_number(dev, obj_id);
13663 - in->hdrChunk = chunk;
13664 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13665 + * We put it in unlinked dir to be cleaned up after the scanning
13668 + yaffs_find_or_create_by_number(dev, obj_id,
13669 + YAFFS_OBJECT_TYPE_FILE);
13672 + obj->is_shadowed = 1;
13673 + yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
13674 + obj->variant.file_variant.shrink_size = 0;
13675 + obj->valid = 1; /* So that we don't read any other info for this file */
13677 - } else if (!in->valid) {
13678 - /* we need to load this info */
13682 - in->hdrChunk = chunk;
13685 - in->variantType = oh->type;
13686 +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list)
13691 - in->yst_mode = oh->yst_mode;
13692 -#ifdef CONFIG_YAFFS_WINCE
13693 - in->win_atime[0] = oh->win_atime[0];
13694 - in->win_ctime[0] = oh->win_ctime[0];
13695 - in->win_mtime[0] = oh->win_mtime[0];
13696 - in->win_atime[1] = oh->win_atime[1];
13697 - in->win_ctime[1] = oh->win_ctime[1];
13698 - in->win_mtime[1] = oh->win_mtime[1];
13700 - in->yst_uid = oh->yst_uid;
13701 - in->yst_gid = oh->yst_gid;
13702 - in->yst_atime = oh->yst_atime;
13703 - in->yst_mtime = oh->yst_mtime;
13704 - in->yst_ctime = oh->yst_ctime;
13705 - in->yst_rdev = oh->yst_rdev;
13707 + while (hard_list) {
13709 + hard_list = (yaffs_obj_t *) (hard_list->hard_links.next);
13711 + in = yaffs_find_by_number(dev,
13712 + hl->variant.hardlink_variant.
13715 - if (oh->shadowsObject > 0)
13716 - yaffs_HandleShadowedObject(dev,
13722 - yaffs_SetObjectName(in, oh->name);
13724 - yaffs_FindOrCreateObjectByNumber
13725 - (dev, oh->parentObjectId,
13726 - YAFFS_OBJECT_TYPE_DIRECTORY);
13728 - fileSize = oh->fileSize;
13729 - isShrink = oh->isShrink;
13730 - equivalentObjectId = oh->equivalentObjectId;
13732 + /* Add the hardlink pointers */
13733 + hl->variant.hardlink_variant.equiv_obj = in;
13734 + ylist_add(&hl->hard_links, &in->hard_links);
13736 + /* Todo Need to report/handle this better.
13737 + * Got a problem... hardlink to a non-existant object
13739 + hl->variant.hardlink_variant.equiv_obj = NULL;
13740 + YINIT_LIST_HEAD(&hl->hard_links);
13743 - in->variantType = tags.extraObjectType;
13745 - yaffs_FindOrCreateObjectByNumber
13746 - (dev, tags.extraParentObjectId,
13747 - YAFFS_OBJECT_TYPE_DIRECTORY);
13748 - fileSize = tags.extraFileLength;
13749 - isShrink = tags.extraIsShrinkHeader;
13750 - equivalentObjectId = tags.extraEquivalentObjectId;
13751 - in->lazyLoaded = 1;
13760 - alloc_failed = 1;
13761 +static void yaffs_strip_deleted_objs(yaffs_dev_t *dev)
13764 + * Sort out state of unlinked and deleted objects after scanning.
13766 + struct ylist_head *i;
13767 + struct ylist_head *n;
13770 - /* directory stuff...
13771 - * hook up to parent
13773 + if (dev->read_only)
13776 - if (parent && parent->variantType ==
13777 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13778 - /* Set up as a directory */
13779 - parent->variantType =
13780 - YAFFS_OBJECT_TYPE_DIRECTORY;
13781 - YINIT_LIST_HEAD(&parent->variant.
13782 - directoryVariant.
13784 - } else if (!parent || parent->variantType !=
13785 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13786 - /* Hoosterman, another problem....
13787 - * We're trying to use a non-directory as a directory
13789 + /* Soft delete all the unlinked files */
13790 + ylist_for_each_safe(i, n,
13791 + &dev->unlinked_dir->variant.dir_variant.children) {
13793 + l = ylist_entry(i, yaffs_obj_t, siblings);
13794 + yaffs_del_obj(l);
13798 - T(YAFFS_TRACE_ERROR,
13800 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13802 - parent = dev->lostNFoundDir;
13804 + ylist_for_each_safe(i, n,
13805 + &dev->del_dir->variant.dir_variant.children) {
13807 + l = ylist_entry(i, yaffs_obj_t, siblings);
13808 + yaffs_del_obj(l);
13812 - yaffs_AddObjectToDirectory(parent, in);
13815 - itsUnlinked = (parent == dev->deletedDir) ||
13816 - (parent == dev->unlinkedDir);
13818 + * This code iterates through all the objects making sure that they are rooted.
13819 + * Any unrooted objects are re-rooted in lost+found.
13820 + * An object needs to be in one of:
13821 + * - Directly under deleted, unlinked
13822 + * - Directly or indirectly under root.
13825 + * This code assumes that we don't ever change the current relationships between
13827 + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
13828 + * lostNfound->parent == root_dir
13830 + * This fixes the problem where directories might have inadvertently been deleted
13831 + * leaving the object "hanging" without being rooted in the directory tree.
13834 +static int yaffs_has_null_parent(yaffs_dev_t *dev, yaffs_obj_t *obj)
13836 + return (obj == dev->del_dir ||
13837 + obj == dev->unlinked_dir||
13838 + obj == dev->root_dir);
13842 - /* Mark the block as having a shrinkHeader */
13843 - bi->hasShrinkHeader = 1;
13845 +static void yaffs_fix_hanging_objs(yaffs_dev_t *dev)
13847 + yaffs_obj_t *obj;
13848 + yaffs_obj_t *parent;
13850 + struct ylist_head *lh;
13851 + struct ylist_head *n;
13855 - /* Note re hardlinks.
13856 - * Since we might scan a hardlink before its equivalent object is scanned
13857 - * we put them all in a list.
13858 - * After scanning is complete, we should have all the objects, so we run
13859 - * through this list and fix up all the chains.
13861 + if (dev->read_only)
13864 - switch (in->variantType) {
13865 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13866 - /* Todo got a problem */
13868 - case YAFFS_OBJECT_TYPE_FILE:
13870 - if (in->variant.fileVariant.
13871 - scannedFileSize < fileSize) {
13872 - /* This covers the case where the file size is greater
13873 - * than where the data is
13874 - * This will happen if the file is resized to be larger
13875 - * than its current data extents.
13877 - in->variant.fileVariant.fileSize = fileSize;
13878 - in->variant.fileVariant.scannedFileSize =
13879 - in->variant.fileVariant.fileSize;
13881 + /* Iterate through the objects in each hash entry,
13882 + * looking at each object.
13883 + * Make sure it is rooted.
13887 - in->variant.fileVariant.shrinkSize > fileSize) {
13888 - in->variant.fileVariant.shrinkSize = fileSize;
13890 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13891 + ylist_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
13893 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
13894 + parent= obj->parent;
13896 + if(yaffs_has_null_parent(dev,obj)){
13897 + /* These directories are not hanging */
13900 + else if(!parent || parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
13902 + else if(yaffs_has_null_parent(dev,parent))
13906 + * Need to follow the parent chain to see if it is hanging.
13912 - case YAFFS_OBJECT_TYPE_HARDLINK:
13913 - if (!itsUnlinked) {
13914 - in->variant.hardLinkVariant.equivalentObjectId =
13915 - equivalentObjectId;
13916 - in->hardLinks.next =
13917 - (struct ylist_head *) hardList;
13921 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13924 - case YAFFS_OBJECT_TYPE_SPECIAL:
13927 - case YAFFS_OBJECT_TYPE_SYMLINK:
13929 - in->variant.symLinkVariant.alias =
13930 - yaffs_CloneString(oh->alias);
13931 - if (!in->variant.symLinkVariant.alias)
13932 - alloc_failed = 1;
13935 + while(parent != dev->root_dir &&
13936 + parent->parent &&
13937 + parent->parent->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
13939 + parent = parent->parent;
13943 + if(parent != dev->root_dir)
13947 + T(YAFFS_TRACE_SCAN,
13948 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13950 + yaffs_add_obj_to_dir(dev->lost_n_found,obj);
13958 - } /* End of scanning for each chunk */
13960 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13961 - /* If we got this far while scanning, then the block is fully allocated. */
13962 - state = YAFFS_BLOCK_STATE_FULL;
13965 + * Delete directory contents for cleaning up lost and found.
13967 +static void yaffs_del_dir_contents(yaffs_obj_t *dir)
13969 + yaffs_obj_t *obj;
13970 + struct ylist_head *lh;
13971 + struct ylist_head *n;
13973 - bi->blockState = state;
13974 + if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
13977 + ylist_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
13979 + obj = ylist_entry(lh, yaffs_obj_t, siblings);
13980 + if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
13981 + yaffs_del_dir_contents(obj);
13983 + T(YAFFS_TRACE_SCAN,
13984 + (TSTR("Deleting lost_found object %d" TENDSTR),
13987 - /* Now let's see if it was dirty */
13988 - if (bi->pagesInUse == 0 &&
13989 - !bi->hasShrinkHeader &&
13990 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13991 - yaffs_BlockBecameDirty(dev, blk);
13992 + /* Need to use UnlinkObject since Delete would not handle
13993 + * hardlinked objects correctly.
13995 + yaffs_unlink_obj(obj);
14002 - if (altBlockIndex)
14003 - YFREE_ALT(blockIndex);
14005 - YFREE(blockIndex);
14006 +static void yaffs_empty_l_n_f(yaffs_dev_t *dev)
14008 + yaffs_del_dir_contents(dev->lost_n_found);
14011 - /* Ok, we've done all the scanning.
14012 - * Fix up the hard link chains.
14013 - * We should now have scanned all the objects, now it's time to add these
14016 - yaffs_HardlinkFixup(dev, hardList);
14017 +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in)
14020 + yaffs_obj_header *oh;
14021 + yaffs_dev_t *dev;
14022 + yaffs_ext_tags tags;
14024 + int alloc_failed = 0;
14029 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
14030 + dev = in->my_dev;
14032 - if (alloc_failed)
14033 - return YAFFS_FAIL;
14035 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
14037 + in->lazy_loaded ? "not yet" : "already"));
14040 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
14041 + if (in->lazy_loaded && in->hdr_chunk > 0) {
14042 + in->lazy_loaded = 0;
14043 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
14047 + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunkData, &tags);
14048 + oh = (yaffs_obj_header *) chunkData;
14050 -/*------------------------------ Directory Functions ----------------------------- */
14051 + in->yst_mode = oh->yst_mode;
14052 +#ifdef CONFIG_YAFFS_WINCE
14053 + in->win_atime[0] = oh->win_atime[0];
14054 + in->win_ctime[0] = oh->win_ctime[0];
14055 + in->win_mtime[0] = oh->win_mtime[0];
14056 + in->win_atime[1] = oh->win_atime[1];
14057 + in->win_ctime[1] = oh->win_ctime[1];
14058 + in->win_mtime[1] = oh->win_mtime[1];
14060 + in->yst_uid = oh->yst_uid;
14061 + in->yst_gid = oh->yst_gid;
14062 + in->yst_atime = oh->yst_atime;
14063 + in->yst_mtime = oh->yst_mtime;
14064 + in->yst_ctime = oh->yst_ctime;
14065 + in->yst_rdev = oh->yst_rdev;
14067 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
14069 - struct ylist_head *lh;
14070 - yaffs_Object *listObj;
14072 + yaffs_set_obj_name_from_oh(in, oh);
14075 + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
14076 + in->variant.symlink_variant.alias =
14077 + yaffs_clone_str(oh->alias);
14078 + if (!in->variant.symlink_variant.alias)
14079 + alloc_failed = 1; /* Not returned to caller */
14083 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
14086 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
14090 - if (yaffs_SkipVerification(obj->myDev))
14092 +/*------------------------------ Directory Functions ----------------------------- */
14094 - if (!obj->parent) {
14095 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
14098 + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
14099 + * link (ie. name) is created or deleted in the directory.
14102 + * create dir/a : update dir's mtime/ctime
14103 + * rm dir/a: update dir's mtime/ctime
14104 + * modify dir/a: don't update dir's mtimme/ctime
14106 + * This can be handled immediately or defered. Defering helps reduce the number
14107 + * of updates when many files in a directory are changed within a brief period.
14109 + * If the directory updating is defered then yaffs_update_dirty_dirs must be
14110 + * called periodically.
14113 +static void yaffs_update_parent(yaffs_obj_t *obj)
14115 + yaffs_dev_t *dev;
14120 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14121 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
14125 - /* Iterate through the objects in each hash entry */
14126 +#ifndef CONFIG_YAFFS_WINCE
14128 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
14130 - listObj = ylist_entry(lh, yaffs_Object, siblings);
14131 - yaffs_VerifyObject(listObj);
14132 - if (obj == listObj)
14134 + dev = obj->my_dev;
14136 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
14137 + if(dev->param.defered_dir_update){
14138 + struct ylist_head *link = &obj->variant.dir_variant.dirty;
14140 + if(ylist_empty(link)){
14141 + ylist_add(link,&dev->dirty_dirs);
14142 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->obj_id));
14146 - if (count != 1) {
14147 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
14151 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
14155 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
14156 +void yaffs_update_dirty_dirs(yaffs_dev_t *dev)
14158 - struct ylist_head *lh;
14159 - yaffs_Object *listObj;
14161 - if (!directory) {
14165 + struct ylist_head *link;
14166 + yaffs_obj_t *obj;
14168 + yaffs_obj_variant *oV;
14170 - if (yaffs_SkipFullVerification(directory->myDev))
14172 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
14174 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14175 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
14178 + while(!ylist_empty(&dev->dirty_dirs)){
14179 + link = dev->dirty_dirs.next;
14180 + ylist_del_init(link);
14182 + dS=ylist_entry(link,yaffs_dir_s,dirty);
14183 + oV = ylist_entry(dS,yaffs_obj_variant,dir_variant);
14184 + obj = ylist_entry(oV,yaffs_obj_t,variant);
14186 - /* Iterate through the objects in each hash entry */
14187 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->obj_id));
14189 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
14191 - listObj = ylist_entry(lh, yaffs_Object, siblings);
14192 - if (listObj->parent != directory) {
14193 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
14196 - yaffs_VerifyObjectInDirectory(listObj);
14199 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
14204 -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
14205 +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj)
14207 - yaffs_Device *dev = obj->myDev;
14208 - yaffs_Object *parent;
14209 + yaffs_dev_t *dev = obj->my_dev;
14210 + yaffs_obj_t *parent;
14212 - yaffs_VerifyObjectInDirectory(obj);
14213 + yaffs_verify_obj_in_dir(obj);
14214 parent = obj->parent;
14216 - yaffs_VerifyDirectory(parent);
14217 + yaffs_verify_dir(parent);
14219 - if (dev && dev->removeObjectCallback)
14220 - dev->removeObjectCallback(obj);
14221 + if (dev && dev->param.remove_obj_fn)
14222 + dev->param.remove_obj_fn(obj);
14225 ylist_del_init(&obj->siblings);
14226 obj->parent = NULL;
14228 - yaffs_VerifyDirectory(parent);
14230 + yaffs_verify_dir(parent);
14234 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14235 - yaffs_Object *obj)
14236 +void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
14237 + yaffs_obj_t *obj)
14240 T(YAFFS_TRACE_ALWAYS,
14241 @@ -6699,7 +4495,7 @@ static void yaffs_AddObjectToDirectory(y
14245 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14246 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14247 T(YAFFS_TRACE_ALWAYS,
14249 ("tragedy: Trying to add an object to a non-directory"
14250 @@ -6713,27 +4509,27 @@ static void yaffs_AddObjectToDirectory(y
14254 - yaffs_VerifyDirectory(directory);
14255 + yaffs_verify_dir(directory);
14257 - yaffs_RemoveObjectFromDirectory(obj);
14258 + yaffs_remove_obj_from_dir(obj);
14262 - ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
14263 + ylist_add(&obj->siblings, &directory->variant.dir_variant.children);
14264 obj->parent = directory;
14266 - if (directory == obj->myDev->unlinkedDir
14267 - || directory == obj->myDev->deletedDir) {
14268 + if (directory == obj->my_dev->unlinked_dir
14269 + || directory == obj->my_dev->del_dir) {
14271 - obj->myDev->nUnlinkedFiles++;
14272 - obj->renameAllowed = 0;
14273 + obj->my_dev->n_unlinked_files++;
14274 + obj->rename_allowed = 0;
14277 - yaffs_VerifyDirectory(directory);
14278 - yaffs_VerifyObjectInDirectory(obj);
14279 + yaffs_verify_dir(directory);
14280 + yaffs_verify_obj_in_dir(obj);
14283 -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,
14284 +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *directory,
14288 @@ -6741,7 +4537,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14289 struct ylist_head *i;
14290 YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
14297 @@ -6749,39 +4545,39 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14299 T(YAFFS_TRACE_ALWAYS,
14301 - ("tragedy: yaffs_FindObjectByName: null pointer directory"
14302 + ("tragedy: yaffs_find_by_name: null pointer directory"
14307 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14308 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14309 T(YAFFS_TRACE_ALWAYS,
14311 - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
14312 + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
14316 - sum = yaffs_CalcNameSum(name);
14317 + sum = yaffs_calc_name_sum(name);
14319 - ylist_for_each(i, &directory->variant.directoryVariant.children) {
14320 + ylist_for_each(i, &directory->variant.dir_variant.children) {
14322 - l = ylist_entry(i, yaffs_Object, siblings);
14323 + l = ylist_entry(i, yaffs_obj_t, siblings);
14325 if (l->parent != directory)
14328 - yaffs_CheckObjectDetailsLoaded(l);
14329 + yaffs_check_obj_details_loaded(l);
14331 /* Special case for lost-n-found */
14332 - if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
14333 + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
14334 if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
14336 - } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {
14337 + } else if (yaffs_sum_cmp(l->sum, sum) || l->hdr_chunk <= 0) {
14338 /* LostnFound chunk called Objxxx
14341 - yaffs_GetObjectName(l, buffer,
14342 - YAFFS_MAX_NAME_LENGTH);
14343 + yaffs_get_obj_name(l, buffer,
14344 + YAFFS_MAX_NAME_LENGTH + 1);
14345 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
14348 @@ -6793,31 +4589,31 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14352 -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
14353 - int (*fn) (yaffs_Object *))
14354 +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
14355 + int (*fn) (yaffs_obj_t *))
14357 struct ylist_head *i;
14363 T(YAFFS_TRACE_ALWAYS,
14365 - ("tragedy: yaffs_FindObjectByName: null pointer directory"
14366 + ("tragedy: yaffs_find_by_name: null pointer directory"
14371 - if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14372 + if (the_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14373 T(YAFFS_TRACE_ALWAYS,
14375 - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
14376 + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
14381 - ylist_for_each(i, &theDir->variant.directoryVariant.children) {
14382 + ylist_for_each(i, &the_dir->variant.dir_variant.children) {
14384 - l = ylist_entry(i, yaffs_Object, siblings);
14385 + l = ylist_entry(i, yaffs_obj_t, siblings);
14389 @@ -6832,82 +4628,175 @@ int yaffs_ApplyToDirectoryChildren(yaffs
14393 -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
14394 +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj)
14396 - if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
14397 + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
14398 /* We want the object id of the equivalent object, not this one */
14399 - obj = obj->variant.hardLinkVariant.equivalentObject;
14400 - yaffs_CheckObjectDetailsLoaded(obj);
14401 + obj = obj->variant.hardlink_variant.equiv_obj;
14402 + yaffs_check_obj_details_loaded(obj);
14407 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
14409 - memset(name, 0, buffSize * sizeof(YCHAR));
14411 - yaffs_CheckObjectDetailsLoaded(obj);
14413 + * A note or two on object names.
14414 + * * If the object name is missing, we then make one up in the form objnnn
14416 + * * ASCII names are stored in the object header's name field from byte zero
14417 + * * Unicode names are historically stored starting from byte zero.
14419 + * Then there are automatic Unicode names...
14420 + * The purpose of these is to save names in a way that can be read as
14421 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
14422 + * system to share files.
14424 + * These automatic unicode are stored slightly differently...
14425 + * - If the name can fit in the ASCII character space then they are saved as
14426 + * ascii names as per above.
14427 + * - If the name needs Unicode then the name is saved in Unicode
14428 + * starting at oh->name[1].
14430 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
14431 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
14432 - } else if (obj->hdrChunk <= 0) {
14434 +static void yaffs_fix_null_name(yaffs_obj_t * obj,YCHAR * name, int buffer_size)
14436 + /* Create an object name if we could not find one. */
14437 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
14439 YCHAR numString[20];
14440 YCHAR *x = &numString[19];
14441 - unsigned v = obj->objectId;
14442 + unsigned v = obj->obj_id;
14447 *x = '0' + (v % 10);
14450 /* make up a name */
14451 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
14452 - yaffs_strcat(locName, x);
14453 - yaffs_strncpy(name, locName, buffSize - 1);
14454 + yaffs_strcat(locName,x);
14455 + yaffs_strncpy(name, locName, buffer_size - 1);
14459 +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
14461 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14462 + if(dev->param.auto_unicode){
14464 + /* It is an ASCII name, so do an ASCII to unicode conversion */
14465 + const char *asciiOhName = (const char *)ohName;
14466 + int n = bufferSize - 1;
14467 + while(n > 0 && *asciiOhName){
14468 + *name = *asciiOhName;
14474 + yaffs_strncpy(name,ohName+1, bufferSize -1);
14477 + yaffs_strncpy(name, ohName, bufferSize - 1);
14481 +static void yaffs_load_oh_from_name(yaffs_dev_t *dev, YCHAR *ohName, const YCHAR *name)
14483 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14488 + if(dev->param.auto_unicode){
14493 + /* Figure out if the name will fit in ascii character set */
14494 + while(isAscii && *w){
14495 + if((*w) & 0xff00)
14501 + /* It is an ASCII name, so do a unicode to ascii conversion */
14502 + char *asciiOhName = (char *)ohName;
14503 + int n = YAFFS_MAX_NAME_LENGTH - 1;
14504 + while(n > 0 && *name){
14505 + *asciiOhName= *name;
14511 + /* It is a unicode name, so save starting at the second YCHAR */
14513 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
14518 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
14522 +int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size)
14524 + memset(name, 0, buffer_size * sizeof(YCHAR));
14526 + yaffs_check_obj_details_loaded(obj);
14528 + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
14529 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
14531 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
14532 - else if (obj->shortName[0])
14533 - yaffs_strcpy(name, obj->shortName);
14534 + else if (obj->short_name[0]) {
14535 + yaffs_strcpy(name, obj->short_name);
14539 + else if(obj->hdr_chunk > 0) {
14541 - __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
14542 + __u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__);
14544 - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
14545 + yaffs_obj_header *oh = (yaffs_obj_header *) buffer;
14547 - memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
14548 + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
14550 - if (obj->hdrChunk > 0) {
14551 - result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
14552 - obj->hdrChunk, buffer,
14553 + if (obj->hdr_chunk > 0) {
14554 + result = yaffs_rd_chunk_tags_nand(obj->my_dev,
14555 + obj->hdr_chunk, buffer,
14558 - yaffs_strncpy(name, oh->name, buffSize - 1);
14559 + yaffs_load_name_from_oh(obj->my_dev,name,oh->name,buffer_size);
14561 - yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
14562 + yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__);
14565 - return yaffs_strlen(name);
14566 + yaffs_fix_null_name(obj,name,buffer_size);
14568 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
14571 -int yaffs_GetObjectFileLength(yaffs_Object *obj)
14573 +int yaffs_get_obj_length(yaffs_obj_t *obj)
14575 /* Dereference any hard linking */
14576 - obj = yaffs_GetEquivalentObject(obj);
14577 + obj = yaffs_get_equivalent_obj(obj);
14579 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
14580 - return obj->variant.fileVariant.fileSize;
14581 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
14582 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
14584 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
14585 + return obj->variant.file_variant.file_size;
14586 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
14587 + if(!obj->variant.symlink_variant.alias)
14589 + return yaffs_strnlen(obj->variant.symlink_variant.alias,YAFFS_MAX_ALIAS_LENGTH);
14591 /* Only a directory should drop through to here */
14592 - return obj->myDev->nDataBytesPerChunk;
14593 + return obj->my_dev->data_bytes_per_chunk;
14597 -int yaffs_GetObjectLinkCount(yaffs_Object *obj)
14598 +int yaffs_get_obj_link_count(yaffs_obj_t *obj)
14601 struct ylist_head *i;
14602 @@ -6915,24 +4804,24 @@ int yaffs_GetObjectLinkCount(yaffs_Objec
14603 if (!obj->unlinked)
14604 count++; /* the object itself */
14606 - ylist_for_each(i, &obj->hardLinks)
14607 + ylist_for_each(i, &obj->hard_links)
14608 count++; /* add the hard links; */
14613 -int yaffs_GetObjectInode(yaffs_Object *obj)
14614 +int yaffs_get_obj_inode(yaffs_obj_t *obj)
14616 - obj = yaffs_GetEquivalentObject(obj);
14617 + obj = yaffs_get_equivalent_obj(obj);
14619 - return obj->objectId;
14620 + return obj->obj_id;
14623 -unsigned yaffs_GetObjectType(yaffs_Object *obj)
14624 +unsigned yaffs_get_obj_type(yaffs_obj_t *obj)
14626 - obj = yaffs_GetEquivalentObject(obj);
14627 + obj = yaffs_get_equivalent_obj(obj);
14629 - switch (obj->variantType) {
14630 + switch (obj->variant_type) {
14631 case YAFFS_OBJECT_TYPE_FILE:
14634 @@ -6960,18 +4849,18 @@ unsigned yaffs_GetObjectType(yaffs_Objec
14638 -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
14639 +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj)
14641 - obj = yaffs_GetEquivalentObject(obj);
14642 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
14643 - return yaffs_CloneString(obj->variant.symLinkVariant.alias);
14644 + obj = yaffs_get_equivalent_obj(obj);
14645 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
14646 + return yaffs_clone_str(obj->variant.symlink_variant.alias);
14648 - return yaffs_CloneString(_Y(""));
14649 + return yaffs_clone_str(_Y(""));
14652 #ifndef CONFIG_YAFFS_WINCE
14654 -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
14655 +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr)
14657 unsigned int valid = attr->ia_valid;
14659 @@ -6990,14 +4879,14 @@ int yaffs_SetAttributes(yaffs_Object *ob
14660 obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
14662 if (valid & ATTR_SIZE)
14663 - yaffs_ResizeFile(obj, attr->ia_size);
14664 + yaffs_resize_file(obj, attr->ia_size);
14666 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
14667 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
14672 -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
14673 +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr)
14675 unsigned int valid = 0;
14677 @@ -7015,7 +4904,7 @@ int yaffs_GetAttributes(yaffs_Object *ob
14678 Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
14679 valid |= ATTR_MTIME;
14681 - attr->ia_size = yaffs_GetFileSize(obj);
14682 + attr->ia_size = yaffs_get_file_size(obj);
14683 valid |= ATTR_SIZE;
14685 attr->ia_valid = valid;
14686 @@ -7025,20 +4914,137 @@ int yaffs_GetAttributes(yaffs_Object *ob
14691 +static int yaffs_do_xattrib_mod(yaffs_obj_t *obj, int set, const YCHAR *name, const void *value, int size, int flags)
14693 + yaffs_xattr_mod xmod;
14698 + xmod.name = name;
14699 + xmod.data = value;
14700 + xmod.size = size;
14701 + xmod.flags = flags;
14702 + xmod.result = -ENOSPC;
14704 + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
14707 + return xmod.result;
14712 +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod)
14715 + int x_offs = sizeof(yaffs_obj_header);
14716 + yaffs_dev_t *dev = obj->my_dev;
14717 + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
14719 + char * x_buffer = buffer + x_offs;
14722 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
14724 + retval = nval_del(x_buffer, x_size, xmod->name);
14726 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
14727 + obj->xattr_known = 1;
14729 + xmod->result = retval;
14734 +static int yaffs_do_xattrib_fetch(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
14736 + char *buffer = NULL;
14738 + yaffs_ext_tags tags;
14739 + yaffs_dev_t *dev = obj->my_dev;
14740 + int x_offs = sizeof(yaffs_obj_header);
14741 + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
14747 + if(obj->hdr_chunk < 1)
14750 + /* If we know that the object has no xattribs then don't do all the
14751 + * reading and parsing.
14753 + if(obj->xattr_known && !obj->has_xattr){
14760 + buffer = (char *) yaffs_get_temp_buffer(dev, __LINE__);
14764 + result = yaffs_rd_chunk_tags_nand(dev,obj->hdr_chunk, (__u8 *)buffer, &tags);
14766 + if(result != YAFFS_OK)
14767 + retval = -ENOENT;
14769 + x_buffer = buffer + x_offs;
14771 + if (!obj->xattr_known){
14772 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
14773 + obj->xattr_known = 1;
14777 + retval = nval_get(x_buffer, x_size, name, value, size);
14779 + retval = nval_list(x_buffer, x_size, value,size);
14781 + yaffs_release_temp_buffer(dev,(__u8 *)buffer,__LINE__);
14785 +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags)
14787 + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
14790 +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name)
14792 + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
14795 +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
14797 + return yaffs_do_xattrib_fetch(obj, name, value, size);
14800 +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size)
14802 + return yaffs_do_xattrib_fetch(obj, NULL, buffer,size);
14808 -int yaffs_DumpObject(yaffs_Object *obj)
14809 +int yaffs_dump_obj(yaffs_obj_t *obj)
14813 - yaffs_GetObjectName(obj, name, 256);
14814 + yaffs_get_obj_name(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
14816 T(YAFFS_TRACE_ALWAYS,
14818 ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
14819 " chunk %d type %d size %d\n"
14820 - TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
14821 - obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
14822 - yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
14823 + TENDSTR), obj->obj_id, yaffs_get_obj_inode(obj), name,
14824 + obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdr_chunk,
14825 + yaffs_get_obj_type(obj), yaffs_get_obj_length(obj)));
14829 @@ -7046,72 +5052,74 @@ int yaffs_DumpObject(yaffs_Object *obj)
14831 /*---------------------------- Initialisation code -------------------------------------- */
14833 -static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
14834 +static int yaffs_cehck_dev_fns(const yaffs_dev_t *dev)
14837 /* Common functions, gotta have */
14838 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
14839 + if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
14842 #ifdef CONFIG_YAFFS_YAFFS2
14844 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
14845 - if (dev->writeChunkWithTagsToNAND &&
14846 - dev->readChunkWithTagsFromNAND &&
14847 - !dev->writeChunkToNAND &&
14848 - !dev->readChunkFromNAND &&
14849 - dev->markNANDBlockBad && dev->queryNANDBlock)
14850 + if (dev->param.write_chunk_tags_fn &&
14851 + dev->param.read_chunk_tags_fn &&
14852 + !dev->param.write_chunk_fn &&
14853 + !dev->param.read_chunk_fn &&
14854 + dev->param.bad_block_fn &&
14855 + dev->param.query_block_fn)
14859 /* Can use the "spare" style interface for yaffs1 */
14860 - if (!dev->isYaffs2 &&
14861 - !dev->writeChunkWithTagsToNAND &&
14862 - !dev->readChunkWithTagsFromNAND &&
14863 - dev->writeChunkToNAND &&
14864 - dev->readChunkFromNAND &&
14865 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
14866 + if (!dev->param.is_yaffs2 &&
14867 + !dev->param.write_chunk_tags_fn &&
14868 + !dev->param.read_chunk_tags_fn &&
14869 + dev->param.write_chunk_fn &&
14870 + dev->param.read_chunk_fn &&
14871 + !dev->param.bad_block_fn &&
14872 + !dev->param.query_block_fn)
14875 - return 0; /* bad */
14876 + return 0; /* bad */
14880 -static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
14881 +static int yaffs_create_initial_dir(yaffs_dev_t *dev)
14883 /* Initialise the unlinked, deleted, root and lost and found directories */
14885 - dev->lostNFoundDir = dev->rootDir = NULL;
14886 - dev->unlinkedDir = dev->deletedDir = NULL;
14887 + dev->lost_n_found = dev->root_dir = NULL;
14888 + dev->unlinked_dir = dev->del_dir = NULL;
14890 - dev->unlinkedDir =
14891 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
14892 + dev->unlinked_dir =
14893 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
14895 - dev->deletedDir =
14896 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
14898 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
14901 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
14903 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
14904 YAFFS_ROOT_MODE | S_IFDIR);
14905 - dev->lostNFoundDir =
14906 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
14907 + dev->lost_n_found =
14908 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
14909 YAFFS_LOSTNFOUND_MODE | S_IFDIR);
14911 - if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) {
14912 - yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
14913 + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir && dev->del_dir) {
14914 + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
14921 -int yaffs_GutsInitialise(yaffs_Device *dev)
14922 +int yaffs_guts_initialise(yaffs_dev_t *dev)
14924 int init_failed = 0;
14928 - T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
14929 + T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR)));
14931 /* Check stuff that must be set */
14933 @@ -7120,52 +5128,52 @@ int yaffs_GutsInitialise(yaffs_Device *d
14937 - dev->internalStartBlock = dev->startBlock;
14938 - dev->internalEndBlock = dev->endBlock;
14939 - dev->blockOffset = 0;
14940 - dev->chunkOffset = 0;
14941 - dev->nFreeChunks = 0;
14943 - dev->gcBlock = -1;
14945 - if (dev->startBlock == 0) {
14946 - dev->internalStartBlock = dev->startBlock + 1;
14947 - dev->internalEndBlock = dev->endBlock + 1;
14948 - dev->blockOffset = 1;
14949 - dev->chunkOffset = dev->nChunksPerBlock;
14950 + dev->internal_start_block = dev->param.start_block;
14951 + dev->internal_end_block = dev->param.end_block;
14952 + dev->block_offset = 0;
14953 + dev->chunk_offset = 0;
14954 + dev->n_free_chunks = 0;
14956 + dev->gc_block = 0;
14958 + if (dev->param.start_block == 0) {
14959 + dev->internal_start_block = dev->param.start_block + 1;
14960 + dev->internal_end_block = dev->param.end_block + 1;
14961 + dev->block_offset = 1;
14962 + dev->chunk_offset = dev->param.chunks_per_block;
14965 /* Check geometry parameters. */
14967 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14968 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14969 - (dev->inbandTags && !dev->isYaffs2) ||
14970 - dev->nChunksPerBlock < 2 ||
14971 - dev->nReservedBlocks < 2 ||
14972 - dev->internalStartBlock <= 0 ||
14973 - dev->internalEndBlock <= 0 ||
14974 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14975 + if ((!dev->param.inband_tags && dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 1024) ||
14976 + (!dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 512) ||
14977 + (dev->param.inband_tags && !dev->param.is_yaffs2) ||
14978 + dev->param.chunks_per_block < 2 ||
14979 + dev->param.n_reserved_blocks < 2 ||
14980 + dev->internal_start_block <= 0 ||
14981 + dev->internal_end_block <= 0 ||
14982 + dev->internal_end_block <= (dev->internal_start_block + dev->param.n_reserved_blocks + 2)) { /* otherwise it is too small */
14983 T(YAFFS_TRACE_ALWAYS,
14985 - ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14986 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14987 + ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d "
14988 + TENDSTR), dev->param.total_bytes_per_chunk, dev->param.is_yaffs2 ? "2" : "", dev->param.inband_tags));
14992 - if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
14993 + if (yaffs_init_nand(dev) != YAFFS_OK) {
14994 T(YAFFS_TRACE_ALWAYS,
14995 (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
14999 /* Sort out space for inband tags, if required */
15000 - if (dev->inbandTags)
15001 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
15002 + if (dev->param.inband_tags)
15003 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk - sizeof(yaffs_PackedTags2TagsPart);
15005 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
15006 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
15008 /* Got the right mix of functions? */
15009 - if (!yaffs_CheckDevFunctions(dev)) {
15010 + if (!yaffs_cehck_dev_fns(dev)) {
15011 /* Function missing */
15012 T(YAFFS_TRACE_ALWAYS,
15014 @@ -7175,13 +5183,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
15017 /* This is really a compilation check. */
15018 - if (!yaffs_CheckStructures()) {
15019 + if (!yaffs_check_structures()) {
15020 T(YAFFS_TRACE_ALWAYS,
15021 - (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
15022 + (TSTR("yaffs_check_structures failed\n" TENDSTR)));
15026 - if (dev->isMounted) {
15027 + if (dev->is_mounted) {
15028 T(YAFFS_TRACE_ALWAYS,
15029 (TSTR("yaffs: device already mounted\n" TENDSTR)));
15031 @@ -7189,59 +5197,62 @@ int yaffs_GutsInitialise(yaffs_Device *d
15033 /* Finished with most checks. One or two more checks happen later on too. */
15035 - dev->isMounted = 1;
15036 + dev->is_mounted = 1;
15038 /* OK now calculate a few things for the device */
15041 * Calculate all the chunk size manipulation numbers:
15043 - x = dev->nDataBytesPerChunk;
15044 - /* We always use dev->chunkShift and dev->chunkDiv */
15045 - dev->chunkShift = Shifts(x);
15046 - x >>= dev->chunkShift;
15047 - dev->chunkDiv = x;
15048 - /* We only use chunk mask if chunkDiv is 1 */
15049 - dev->chunkMask = (1<<dev->chunkShift) - 1;
15050 + x = dev->data_bytes_per_chunk;
15051 + /* We always use dev->chunk_shift and dev->chunk_div */
15052 + dev->chunk_shift = Shifts(x);
15053 + x >>= dev->chunk_shift;
15054 + dev->chunk_div = x;
15055 + /* We only use chunk mask if chunk_div is 1 */
15056 + dev->chunk_mask = (1<<dev->chunk_shift) - 1;
15059 - * Calculate chunkGroupBits.
15060 - * We need to find the next power of 2 > than internalEndBlock
15061 + * Calculate chunk_grp_bits.
15062 + * We need to find the next power of 2 > than internal_end_block
15065 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
15066 + x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
15068 bits = ShiftsGE(x);
15070 /* Set up tnode width if wide tnodes are enabled. */
15071 - if (!dev->wideTnodesDisabled) {
15072 + if (!dev->param.wide_tnodes_disabled) {
15073 /* bits must be even so that we end up with 32-bit words */
15077 - dev->tnodeWidth = 16;
15078 + dev->tnode_width = 16;
15080 - dev->tnodeWidth = bits;
15081 + dev->tnode_width = bits;
15083 - dev->tnodeWidth = 16;
15084 + dev->tnode_width = 16;
15086 - dev->tnodeMask = (1<<dev->tnodeWidth)-1;
15087 + dev->tnode_mask = (1<<dev->tnode_width)-1;
15089 /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
15090 * so if the bitwidth of the
15091 * chunk range we're using is greater than 16 we need
15092 - * to figure out chunk shift and chunkGroupSize
15093 + * to figure out chunk shift and chunk_grp_size
15096 - if (bits <= dev->tnodeWidth)
15097 - dev->chunkGroupBits = 0;
15098 + if (bits <= dev->tnode_width)
15099 + dev->chunk_grp_bits = 0;
15101 - dev->chunkGroupBits = bits - dev->tnodeWidth;
15102 + dev->chunk_grp_bits = bits - dev->tnode_width;
15104 + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8;
15105 + if(dev->tnode_size < sizeof(yaffs_tnode_t))
15106 + dev->tnode_size = sizeof(yaffs_tnode_t);
15108 - dev->chunkGroupSize = 1 << dev->chunkGroupBits;
15109 + dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
15111 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
15112 + if (dev->param.chunks_per_block < dev->chunk_grp_size) {
15113 /* We have a problem because the soft delete won't work if
15114 * the chunk group size > chunks per block.
15115 * This can be remedied by using larger "virtual blocks".
15116 @@ -7255,85 +5266,89 @@ int yaffs_GutsInitialise(yaffs_Device *d
15117 /* OK, we've finished verifying the device, lets continue with initialisation */
15119 /* More device initialisation */
15120 - dev->garbageCollections = 0;
15121 - dev->passiveGarbageCollections = 0;
15122 - dev->currentDirtyChecker = 0;
15123 - dev->bufferedBlock = -1;
15124 - dev->doingBufferedBlockRewrite = 0;
15125 - dev->nDeletedFiles = 0;
15126 - dev->nBackgroundDeletions = 0;
15127 - dev->nUnlinkedFiles = 0;
15128 - dev->eccFixed = 0;
15129 - dev->eccUnfixed = 0;
15130 - dev->tagsEccFixed = 0;
15131 - dev->tagsEccUnfixed = 0;
15132 - dev->nErasureFailures = 0;
15133 - dev->nErasedBlocks = 0;
15134 - dev->isDoingGC = 0;
15135 - dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
15136 + dev->all_gcs = 0;
15137 + dev->passive_gc_count = 0;
15138 + dev->oldest_dirty_gc_count = 0;
15140 + dev->gc_block_finder = 0;
15141 + dev->buffered_block = -1;
15142 + dev->doing_buffered_block_rewrite = 0;
15143 + dev->n_deleted_files = 0;
15144 + dev->n_bg_deletions = 0;
15145 + dev->n_unlinked_files = 0;
15146 + dev->n_ecc_fixed = 0;
15147 + dev->n_ecc_unfixed = 0;
15148 + dev->n_tags_ecc_fixed = 0;
15149 + dev->n_tags_ecc_unfixed = 0;
15150 + dev->n_erase_failures = 0;
15151 + dev->n_erased_blocks = 0;
15152 + dev->gc_disable= 0;
15153 + dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */
15154 + YINIT_LIST_HEAD(&dev->dirty_dirs);
15155 + dev->oldest_dirty_seq = 0;
15156 + dev->oldest_dirty_block = 0;
15158 /* Initialise temporary buffers and caches. */
15159 - if (!yaffs_InitialiseTempBuffers(dev))
15160 + if (!yaffs_init_tmp_buffers(dev))
15163 - dev->srCache = NULL;
15164 - dev->gcCleanupList = NULL;
15165 + dev->cache = NULL;
15166 + dev->gc_cleanup_list = NULL;
15169 if (!init_failed &&
15170 - dev->nShortOpCaches > 0) {
15171 + dev->param.n_caches > 0) {
15174 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
15175 + int cacheBytes = dev->param.n_caches * sizeof(yaffs_cache_t);
15177 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
15178 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
15179 + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
15180 + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
15182 - dev->srCache = YMALLOC(srCacheBytes);
15183 + dev->cache = YMALLOC(cacheBytes);
15185 - buf = (__u8 *) dev->srCache;
15186 + buf = (__u8 *) dev->cache;
15188 - if (dev->srCache)
15189 - memset(dev->srCache, 0, srCacheBytes);
15191 + memset(dev->cache, 0, cacheBytes);
15193 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
15194 - dev->srCache[i].object = NULL;
15195 - dev->srCache[i].lastUse = 0;
15196 - dev->srCache[i].dirty = 0;
15197 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
15198 + for (i = 0; i < dev->param.n_caches && buf; i++) {
15199 + dev->cache[i].object = NULL;
15200 + dev->cache[i].last_use = 0;
15201 + dev->cache[i].dirty = 0;
15202 + dev->cache[i].data = buf = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
15207 - dev->srLastUse = 0;
15208 + dev->cache_last_use = 0;
15211 - dev->cacheHits = 0;
15212 + dev->cache_hits = 0;
15214 if (!init_failed) {
15215 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
15216 - if (!dev->gcCleanupList)
15217 + dev->gc_cleanup_list = YMALLOC(dev->param.chunks_per_block * sizeof(__u32));
15218 + if (!dev->gc_cleanup_list)
15222 - if (dev->isYaffs2)
15223 - dev->useHeaderFileSize = 1;
15224 + if (dev->param.is_yaffs2)
15225 + dev->param.use_header_file_size = 1;
15227 - if (!init_failed && !yaffs_InitialiseBlocks(dev))
15228 + if (!init_failed && !yaffs_init_blocks(dev))
15231 - yaffs_InitialiseTnodes(dev);
15232 - yaffs_InitialiseObjects(dev);
15233 + yaffs_init_tnodes_and_objs(dev);
15235 - if (!init_failed && !yaffs_CreateInitialDirectories(dev))
15236 + if (!init_failed && !yaffs_create_initial_dir(dev))
15240 if (!init_failed) {
15241 /* Now scan the flash. */
15242 - if (dev->isYaffs2) {
15243 - if (yaffs_CheckpointRestore(dev)) {
15244 - yaffs_CheckObjectDetailsLoaded(dev->rootDir);
15245 + if (dev->param.is_yaffs2) {
15246 + if (yaffs2_checkpt_restore(dev)) {
15247 + yaffs_check_obj_details_loaded(dev->root_dir);
15248 T(YAFFS_TRACE_ALWAYS,
15249 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
15251 @@ -7341,128 +5356,129 @@ int yaffs_GutsInitialise(yaffs_Device *d
15252 /* Clean up the mess caused by an aborted checkpoint load
15253 * and scan backwards.
15255 - yaffs_DeinitialiseBlocks(dev);
15256 - yaffs_DeinitialiseTnodes(dev);
15257 - yaffs_DeinitialiseObjects(dev);
15258 + yaffs_deinit_blocks(dev);
15260 + yaffs_deinit_tnodes_and_objs(dev);
15262 - dev->nErasedBlocks = 0;
15263 - dev->nFreeChunks = 0;
15264 - dev->allocationBlock = -1;
15265 - dev->allocationPage = -1;
15266 - dev->nDeletedFiles = 0;
15267 - dev->nUnlinkedFiles = 0;
15268 - dev->nBackgroundDeletions = 0;
15269 - dev->oldestDirtySequence = 0;
15270 + dev->n_erased_blocks = 0;
15271 + dev->n_free_chunks = 0;
15272 + dev->alloc_block = -1;
15273 + dev->alloc_page = -1;
15274 + dev->n_deleted_files = 0;
15275 + dev->n_unlinked_files = 0;
15276 + dev->n_bg_deletions = 0;
15278 - if (!init_failed && !yaffs_InitialiseBlocks(dev))
15279 + if (!init_failed && !yaffs_init_blocks(dev))
15282 - yaffs_InitialiseTnodes(dev);
15283 - yaffs_InitialiseObjects(dev);
15284 + yaffs_init_tnodes_and_objs(dev);
15286 - if (!init_failed && !yaffs_CreateInitialDirectories(dev))
15287 + if (!init_failed && !yaffs_create_initial_dir(dev))
15290 - if (!init_failed && !yaffs_ScanBackwards(dev))
15291 + if (!init_failed && !yaffs2_scan_backwards(dev))
15294 - } else if (!yaffs_Scan(dev))
15295 + } else if (!yaffs1_scan(dev))
15298 - yaffs_StripDeletedObjects(dev);
15299 + yaffs_strip_deleted_objs(dev);
15300 + yaffs_fix_hanging_objs(dev);
15301 + if(dev->param.empty_lost_n_found)
15302 + yaffs_empty_l_n_f(dev);
15306 /* Clean up the mess */
15307 T(YAFFS_TRACE_TRACING,
15308 - (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
15309 + (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR)));
15311 - yaffs_Deinitialise(dev);
15312 + yaffs_deinitialise(dev);
15316 /* Zero out stats */
15317 - dev->nPageReads = 0;
15318 - dev->nPageWrites = 0;
15319 - dev->nBlockErasures = 0;
15320 - dev->nGCCopies = 0;
15321 - dev->nRetriedWrites = 0;
15323 - dev->nRetiredBlocks = 0;
15325 - yaffs_VerifyFreeChunks(dev);
15326 - yaffs_VerifyBlocks(dev);
15328 + dev->n_page_reads = 0;
15329 + dev->n_page_writes = 0;
15330 + dev->n_erasures = 0;
15331 + dev->n_gc_copies = 0;
15332 + dev->n_retired_writes = 0;
15334 + dev->n_retired_blocks = 0;
15336 + yaffs_verify_free_chunks(dev);
15337 + yaffs_verify_blocks(dev);
15339 + /* Clean up any aborted checkpoint data */
15340 + if(!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
15341 + yaffs2_checkpt_invalidate(dev);
15343 T(YAFFS_TRACE_TRACING,
15344 - (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
15345 + (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR)));
15350 -void yaffs_Deinitialise(yaffs_Device *dev)
15351 +void yaffs_deinitialise(yaffs_dev_t *dev)
15353 - if (dev->isMounted) {
15354 + if (dev->is_mounted) {
15357 - yaffs_DeinitialiseBlocks(dev);
15358 - yaffs_DeinitialiseTnodes(dev);
15359 - yaffs_DeinitialiseObjects(dev);
15360 - if (dev->nShortOpCaches > 0 &&
15362 + yaffs_deinit_blocks(dev);
15363 + yaffs_deinit_tnodes_and_objs(dev);
15364 + if (dev->param.n_caches > 0 &&
15367 - for (i = 0; i < dev->nShortOpCaches; i++) {
15368 - if (dev->srCache[i].data)
15369 - YFREE(dev->srCache[i].data);
15370 - dev->srCache[i].data = NULL;
15371 + for (i = 0; i < dev->param.n_caches; i++) {
15372 + if (dev->cache[i].data)
15373 + YFREE(dev->cache[i].data);
15374 + dev->cache[i].data = NULL;
15377 - YFREE(dev->srCache);
15378 - dev->srCache = NULL;
15379 + YFREE(dev->cache);
15380 + dev->cache = NULL;
15383 - YFREE(dev->gcCleanupList);
15384 + YFREE(dev->gc_cleanup_list);
15386 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
15387 - YFREE(dev->tempBuffer[i].buffer);
15388 + YFREE(dev->temp_buffer[i].buffer);
15390 - dev->isMounted = 0;
15391 + dev->is_mounted = 0;
15393 - if (dev->deinitialiseNAND)
15394 - dev->deinitialiseNAND(dev);
15395 + if (dev->param.deinitialise_flash_fn)
15396 + dev->param.deinitialise_flash_fn(dev);
15400 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
15401 +int yaffs_count_free_chunks(yaffs_dev_t *dev)
15407 - yaffs_BlockInfo *blk;
15409 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
15411 - blk = yaffs_GetBlockInfo(dev, b);
15412 + yaffs_block_info_t *blk;
15414 - switch (blk->blockState) {
15415 + blk = dev->block_info;
15416 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
15417 + switch (blk->block_state) {
15418 case YAFFS_BLOCK_STATE_EMPTY:
15419 case YAFFS_BLOCK_STATE_ALLOCATING:
15420 case YAFFS_BLOCK_STATE_COLLECTING:
15421 case YAFFS_BLOCK_STATE_FULL:
15423 - (dev->nChunksPerBlock - blk->pagesInUse +
15424 - blk->softDeletions);
15425 + (dev->param.chunks_per_block - blk->pages_in_use +
15426 + blk->soft_del_pages);
15437 -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
15438 +int yaffs_get_n_free_chunks(yaffs_dev_t *dev)
15440 /* This is what we report to the outside world */
15442 @@ -7472,30 +5488,28 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
15446 - nFree = dev->nFreeChunks;
15447 + nFree = dev->n_free_chunks;
15449 - nFree = yaffs_CountFreeChunks(dev);
15450 + nFree = yaffs_count_free_chunks(dev);
15453 - nFree += dev->nDeletedFiles;
15454 + nFree += dev->n_deleted_files;
15456 /* Now count the number of dirty chunks in the cache and subtract those */
15458 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
15459 - if (dev->srCache[i].dirty)
15460 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.n_caches; i++) {
15461 + if (dev->cache[i].dirty)
15462 nDirtyCacheChunks++;
15465 nFree -= nDirtyCacheChunks;
15467 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
15468 + nFree -= ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
15470 /* Now we figure out how much to reserve for the checkpoint and report that... */
15471 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
15472 - if (blocksForCheckpoint < 0)
15473 - blocksForCheckpoint = 0;
15474 + blocksForCheckpoint = yaffs_calc_checkpt_blocks_required(dev);
15476 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
15477 + nFree -= (blocksForCheckpoint * dev->param.chunks_per_block);
15481 @@ -7504,49 +5518,27 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
15485 -static int yaffs_freeVerificationFailures;
15487 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
15492 - if (yaffs_SkipVerification(dev))
15495 - counted = yaffs_CountFreeChunks(dev);
15497 - difference = dev->nFreeChunks - counted;
15499 - if (difference) {
15500 - T(YAFFS_TRACE_ALWAYS,
15501 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
15502 - dev->nFreeChunks, counted, difference));
15503 - yaffs_freeVerificationFailures++;
15507 /*---------------------------------------- YAFFS test code ----------------------*/
15509 -#define yaffs_CheckStruct(structure, syze, name) \
15510 +#define yaffs_check_struct(structure, syze, name) \
15512 if (sizeof(structure) != syze) { \
15513 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
15514 - name, syze, sizeof(structure))); \
15515 + name, syze, (int) sizeof(structure))); \
15516 return YAFFS_FAIL; \
15520 -static int yaffs_CheckStructures(void)
15521 +static int yaffs_check_structures(void)
15523 -/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
15524 -/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
15525 -/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
15526 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
15527 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
15529 +/* yaffs_check_struct(yaffs_tags_t,8,"yaffs_tags_t"); */
15530 +/* yaffs_check_struct(yaffs_tags_union_t,8,"yaffs_tags_union_t"); */
15531 +/* yaffs_check_struct(yaffs_spare,16,"yaffs_spare"); */
15532 +/* yaffs_check_struct(yaffs_tnode_t, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_tnode_t"); */
15534 #ifndef CONFIG_YAFFS_WINCE
15535 - yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
15536 + yaffs_check_struct(yaffs_obj_header, 512, "yaffs_obj_header");
15540 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.h
15541 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.h 2010-10-20 13:17:58.954000294 +0300
15542 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.h 2010-10-20 13:28:16.061000294 +0300
15545 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15547 - * Copyright (C) 2002-2007 Aleph One Ltd.
15548 + * Copyright (C) 2002-2010 Aleph One Ltd.
15549 * for Toby Churchill Ltd and Brightstar Engineering
15551 * Created by Charles Manning <charles@aleph1.co.uk>
15553 #ifndef __YAFFS_GUTS_H__
15554 #define __YAFFS_GUTS_H__
15556 -#include "devextras.h"
15557 #include "yportenv.h"
15558 +#include "devextras.h"
15559 +#include "yaffs_list.h"
15562 #define YAFFS_FAIL 0
15565 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
15567 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
15569 #define YAFFS_ALLOCATION_NOBJECTS 100
15570 #define YAFFS_ALLOCATION_NTNODES 100
15574 #define YAFFS_OBJECT_SPACE 0x40000
15575 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
15577 -#define YAFFS_CHECKPOINT_VERSION 3
15578 +#define YAFFS_CHECKPOINT_VERSION 4
15580 #ifdef CONFIG_YAFFS_UNICODE
15581 #define YAFFS_MAX_NAME_LENGTH 127
15582 @@ -81,12 +82,11 @@
15583 #define YAFFS_OBJECTID_UNLINKED 3
15584 #define YAFFS_OBJECTID_DELETED 4
15586 -/* Sseudo object ids for checkpointing */
15587 +/* Pseudo object ids for checkpointing */
15588 #define YAFFS_OBJECTID_SB_HEADER 0x10
15589 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
15590 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
15594 #define YAFFS_MAX_SHORT_OP_CACHES 20
15596 @@ -113,18 +113,14 @@
15598 /* ChunkCache is used for short read/write operations.*/
15600 - struct yaffs_ObjectStruct *object;
15603 + struct yaffs_obj_s *object;
15607 - int nBytes; /* Only valid if the cache is dirty */
15608 + int n_bytes; /* Only valid if the cache is dirty */
15609 int locked; /* Can't push out or flush while locked. */
15610 -#ifdef CONFIG_YAFFS_YAFFS2
15613 - __u8 data[YAFFS_BYTES_PER_CHUNK];
15615 -} yaffs_ChunkCache;
15620 @@ -135,18 +131,18 @@ typedef struct {
15622 #ifndef CONFIG_YAFFS_NO_YAFFS1
15624 - unsigned chunkId:20;
15625 - unsigned serialNumber:2;
15626 - unsigned byteCountLSB:10;
15627 - unsigned objectId:18;
15628 + unsigned chunk_id:20;
15629 + unsigned serial_number:2;
15630 + unsigned n_bytes_lsb:10;
15631 + unsigned obj_id:18;
15633 - unsigned byteCountMSB:2;
15635 + unsigned n_bytes_msb:2;
15639 - yaffs_Tags asTags;
15641 -} yaffs_TagsUnion;
15642 + yaffs_tags_t as_tags;
15643 + __u8 as_bytes[8];
15644 +} yaffs_tags_union_t;
15648 @@ -157,7 +153,7 @@ typedef enum {
15649 YAFFS_ECC_RESULT_NO_ERROR,
15650 YAFFS_ECC_RESULT_FIXED,
15651 YAFFS_ECC_RESULT_UNFIXED
15652 -} yaffs_ECCResult;
15653 +} yaffs_ecc_result;
15656 YAFFS_OBJECT_TYPE_UNKNOWN,
15657 @@ -166,64 +162,64 @@ typedef enum {
15658 YAFFS_OBJECT_TYPE_DIRECTORY,
15659 YAFFS_OBJECT_TYPE_HARDLINK,
15660 YAFFS_OBJECT_TYPE_SPECIAL
15661 -} yaffs_ObjectType;
15664 #define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
15668 - unsigned validMarker0;
15669 - unsigned chunkUsed; /* Status of the chunk: used or unused */
15670 - unsigned objectId; /* If 0 then this is not part of an object (unused) */
15671 - unsigned chunkId; /* If 0 then this is a header, else a data chunk */
15672 - unsigned byteCount; /* Only valid for data chunks */
15673 + unsigned validity1;
15674 + unsigned chunk_used; /* Status of the chunk: used or unused */
15675 + unsigned obj_id; /* If 0 then this is not part of an object (unused) */
15676 + unsigned chunk_id; /* If 0 then this is a header, else a data chunk */
15677 + unsigned n_bytes; /* Only valid for data chunks */
15679 /* The following stuff only has meaning when we read */
15680 - yaffs_ECCResult eccResult;
15681 - unsigned blockBad;
15682 + yaffs_ecc_result ecc_result;
15683 + unsigned block_bad;
15685 /* YAFFS 1 stuff */
15686 - unsigned chunkDeleted; /* The chunk is marked deleted */
15687 - unsigned serialNumber; /* Yaffs1 2-bit serial number */
15688 + unsigned is_deleted; /* The chunk is marked deleted */
15689 + unsigned serial_number; /* Yaffs1 2-bit serial number */
15692 - unsigned sequenceNumber; /* The sequence number of this block */
15693 + unsigned seq_number; /* The sequence number of this block */
15695 /* Extra info if this is an object header (YAFFS2 only) */
15697 - unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
15698 - unsigned extraParentObjectId; /* The parent object */
15699 - unsigned extraIsShrinkHeader; /* Is it a shrink header? */
15700 - unsigned extraShadows; /* Does this shadow another object? */
15701 + unsigned extra_available; /* There is extra info available if this is not zero */
15702 + unsigned extra_parent_id; /* The parent object */
15703 + unsigned extra_is_shrink; /* Is it a shrink header? */
15704 + unsigned extra_shadows; /* Does this shadow another object? */
15706 - yaffs_ObjectType extraObjectType; /* What object type? */
15707 + yaffs_obj_type extra_obj_type; /* What object type? */
15709 - unsigned extraFileLength; /* Length if it is a file */
15710 - unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
15711 + unsigned extra_length; /* Length if it is a file */
15712 + unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */
15714 - unsigned validMarker1;
15715 + unsigned validty1;
15717 -} yaffs_ExtendedTags;
15720 /* Spare structure for YAFFS1 */
15726 - __u8 pageStatus; /* set to 0 to delete the chunk */
15727 - __u8 blockStatus;
15734 + __u8 page_status; /* set to 0 to delete the chunk */
15735 + __u8 block_status;
15747 /*Special structure for passing through to mtd */
15748 -struct yaffs_NANDSpare {
15749 - yaffs_Spare spare;
15750 +struct yaffs_nand_spare {
15751 + yaffs_spare spare;
15755 @@ -234,6 +230,8 @@ typedef enum {
15756 YAFFS_BLOCK_STATE_UNKNOWN = 0,
15758 YAFFS_BLOCK_STATE_SCANNING,
15759 + /* Being scanned */
15761 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
15762 /* The block might have something on it (ie it is allocating or full, perhaps empty)
15763 * but it needs to be scanned to determine its true state.
15764 @@ -249,67 +247,69 @@ typedef enum {
15765 /* This block is partially allocated.
15766 * At least one page holds valid data.
15767 * This is the one currently being used for page
15768 - * allocation. Should never be more than one of these
15769 + * allocation. Should never be more than one of these.
15770 + * If a block is only partially allocated at mount it is treated as full.
15773 YAFFS_BLOCK_STATE_FULL,
15774 /* All the pages in this block have been allocated.
15775 + * If a block was only partially allocated when mounted we treat
15776 + * it as fully allocated.
15779 YAFFS_BLOCK_STATE_DIRTY,
15780 - /* All pages have been allocated and deleted.
15781 + /* The block was full and now all chunks have been deleted.
15782 * Erase me, reuse me.
15785 YAFFS_BLOCK_STATE_CHECKPOINT,
15786 - /* This block is assigned to holding checkpoint data.
15788 + /* This block is assigned to holding checkpoint data. */
15790 YAFFS_BLOCK_STATE_COLLECTING,
15791 /* This block is being garbage collected */
15793 YAFFS_BLOCK_STATE_DEAD
15794 /* This block has failed and is not in use */
15795 -} yaffs_BlockState;
15796 +} yaffs_block_state_t;
15798 #define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
15803 - int softDeletions:10; /* number of soft deleted pages */
15804 - int pagesInUse:10; /* number of pages in use */
15805 - unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
15806 - __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
15807 + int soft_del_pages:10; /* number of soft deleted pages */
15808 + int pages_in_use:10; /* number of pages in use */
15809 + unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
15810 + __u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */
15811 /* and retire the block. */
15812 - __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */
15813 - __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block.
15814 + __u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */
15815 + __u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block.
15816 It should be prioritised for GC */
15817 - __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
15818 + __u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
15820 #ifdef CONFIG_YAFFS_YAFFS2
15821 - __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
15822 - __u32 sequenceNumber; /* block sequence number for yaffs2 */
15823 + __u32 has_shrink_hdr:1; /* This block has at least one shrink object header */
15824 + __u32 seq_number; /* block sequence number for yaffs2 */
15827 -} yaffs_BlockInfo;
15828 +} yaffs_block_info_t;
15830 /* -------------------------- Object structure -------------------------------*/
15831 /* This is the object structure as stored on NAND */
15834 - yaffs_ObjectType type;
15835 + yaffs_obj_type type;
15837 /* Apply to everything */
15838 - int parentObjectId;
15839 - __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
15840 + int parent_obj_id;
15841 + __u16 sum_no_longer_used; /* checksum of name. No longer used */
15842 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
15844 /* The following apply to directories, files, symlinks - not hard links */
15845 __u32 yst_mode; /* protection */
15847 #ifdef CONFIG_YAFFS_WINCE
15848 - __u32 notForWinCE[5];
15849 + __u32 not_for_wince[5];
15853 @@ -319,10 +319,10 @@ typedef struct {
15856 /* File size applies to files only */
15860 /* Equivalent object id applies to hard links only. */
15861 - int equivalentObjectId;
15864 /* Alias is for symlinks only. */
15865 YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
15866 @@ -334,40 +334,29 @@ typedef struct {
15867 __u32 win_atime[2];
15868 __u32 win_mtime[2];
15870 - __u32 roomToGrow[6];
15871 + __u32 room_to_grow[6];
15874 - __u32 inbandShadowsObject;
15875 - __u32 inbandIsShrink;
15876 + __u32 inband_shadowed_obj_id;
15877 + __u32 inband_is_shrink;
15879 - __u32 reservedSpace[2];
15880 - int shadowsObject; /* This object header shadows the specified object if > 0 */
15881 + __u32 reserved[2];
15882 + int shadows_obj; /* This object header shadows the specified object if > 0 */
15884 - /* isShrink applies to object headers written when we shrink the file (ie resize) */
15886 + /* is_shrink applies to object headers written when we shrink the file (ie resize) */
15889 -} yaffs_ObjectHeader;
15890 +} yaffs_obj_header;
15892 /*--------------------------- Tnode -------------------------- */
15894 -union yaffs_Tnode_union {
15895 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
15896 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
15898 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
15900 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
15901 +union yaffs_tnode_union {
15902 + union yaffs_tnode_union *internal[YAFFS_NTNODES_INTERNAL];
15906 -typedef union yaffs_Tnode_union yaffs_Tnode;
15907 +typedef union yaffs_tnode_union yaffs_tnode_t;
15909 -struct yaffs_TnodeList_struct {
15910 - struct yaffs_TnodeList_struct *next;
15911 - yaffs_Tnode *tnodes;
15914 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
15916 /*------------------------ Object -----------------------------*/
15917 /* An object can be one of:
15918 @@ -378,82 +367,85 @@ typedef struct yaffs_TnodeList_struct ya
15923 - __u32 scannedFileSize;
15924 - __u32 shrinkSize;
15926 - yaffs_Tnode *top;
15927 -} yaffs_FileStructure;
15929 + __u32 scanned_size;
15930 + __u32 shrink_size;
15932 + yaffs_tnode_t *top;
15936 struct ylist_head children; /* list of child links */
15937 -} yaffs_DirectoryStructure;
15938 + struct ylist_head dirty; /* Entry for list of dirty directories */
15943 -} yaffs_SymLinkStructure;
15944 +} yaffs_symlink_t;
15947 - struct yaffs_ObjectStruct *equivalentObject;
15948 - __u32 equivalentObjectId;
15949 -} yaffs_HardLinkStructure;
15950 + struct yaffs_obj_s *equiv_obj;
15952 +} yaffs_hard_link_s;
15955 - yaffs_FileStructure fileVariant;
15956 - yaffs_DirectoryStructure directoryVariant;
15957 - yaffs_SymLinkStructure symLinkVariant;
15958 - yaffs_HardLinkStructure hardLinkVariant;
15959 -} yaffs_ObjectVariant;
15960 + yaffs_file_s file_variant;
15961 + yaffs_dir_s dir_variant;
15962 + yaffs_symlink_t symlink_variant;
15963 + yaffs_hard_link_s hardlink_variant;
15964 +} yaffs_obj_variant;
15968 -struct yaffs_ObjectStruct {
15969 +struct yaffs_obj_s {
15970 __u8 deleted:1; /* This should only apply to unlinked files. */
15971 - __u8 softDeleted:1; /* it has also been soft deleted */
15972 + __u8 soft_del:1; /* it has also been soft deleted */
15973 __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
15974 __u8 fake:1; /* A fake object has no presence on NAND. */
15975 - __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
15976 - __u8 unlinkAllowed:1;
15977 + __u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */
15978 + __u8 unlink_allowed:1;
15979 __u8 dirty:1; /* the object needs to be written to flash */
15980 __u8 valid:1; /* When the file system is being loaded up, this
15981 * object might be created before the data
15982 * is available (ie. file data records appear before the header).
15984 - __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
15985 + __u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */
15987 - __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
15988 + __u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is
15989 * still in the inode cache. Free of object is defered.
15990 * until the inode is released.
15992 - __u8 beingCreated:1; /* This object is still being created so skip some checks. */
15993 + __u8 being_created:1; /* This object is still being created so skip some checks. */
15994 + __u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */
15996 + __u8 xattr_known:1; /* We know if this has object has xattribs or not. */
15997 + __u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */
15999 __u8 serial; /* serial number of chunk in NAND. Cached here */
16000 __u16 sum; /* sum of the name to speed searching */
16002 - struct yaffs_DeviceStruct *myDev; /* The device I'm on */
16003 + struct yaffs_dev_s *my_dev; /* The device I'm on */
16005 - struct ylist_head hashLink; /* list of objects in this hash bucket */
16006 + struct ylist_head hash_link; /* list of objects in this hash bucket */
16008 - struct ylist_head hardLinks; /* all the equivalent hard linked objects */
16009 + struct ylist_head hard_links; /* all the equivalent hard linked objects */
16011 /* directory structure stuff */
16012 /* also used for linking up the free list */
16013 - struct yaffs_ObjectStruct *parent;
16014 + struct yaffs_obj_s *parent;
16015 struct ylist_head siblings;
16017 /* Where's my object header in NAND? */
16021 - int nDataChunks; /* Number of data chunks attached to the file. */
16022 + int n_data_chunks; /* Number of data chunks attached to the file. */
16024 - __u32 objectId; /* the object id value */
16025 + __u32 obj_id; /* the object id value */
16029 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
16030 - YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
16033 -#ifndef __KERNEL__
16035 + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
16038 #ifdef CONFIG_YAFFS_WINCE
16039 @@ -470,53 +462,43 @@ struct yaffs_ObjectStruct {
16044 - struct inode *myInode;
16048 + yaffs_obj_type variant_type;
16050 - yaffs_ObjectType variantType;
16051 + yaffs_obj_variant variant;
16053 - yaffs_ObjectVariant variant;
16057 -typedef struct yaffs_ObjectStruct yaffs_Object;
16059 -struct yaffs_ObjectList_struct {
16060 - yaffs_Object *objects;
16061 - struct yaffs_ObjectList_struct *next;
16064 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
16065 +typedef struct yaffs_obj_s yaffs_obj_t;
16068 struct ylist_head list;
16070 -} yaffs_ObjectBucket;
16071 +} yaffs_obj_bucket;
16074 -/* yaffs_CheckpointObject holds the definition of an object as dumped
16075 +/* yaffs_checkpt_obj_t holds the definition of an object as dumped
16076 * by checkpointing.
16084 - yaffs_ObjectType variantType:3;
16089 + yaffs_obj_type variant_type:3;
16091 - __u8 softDeleted:1;
16095 - __u8 renameAllowed:1;
16096 - __u8 unlinkAllowed:1;
16097 + __u8 rename_allowed:1;
16098 + __u8 unlink_allowed:1;
16102 - __u32 fileSizeOrEquivalentObjectId;
16103 -} yaffs_CheckpointObject;
16104 + int n_data_chunks;
16105 + __u32 size_or_equiv_obj;
16106 +} yaffs_checkpt_obj_t;
16108 /*--------------------- Temporary buffers ----------------
16110 @@ -526,379 +508,462 @@ typedef struct {
16113 int line; /* track from whence this buffer was allocated */
16115 -} yaffs_TempBuffer;
16119 /*----------------- Device ---------------------------------*/
16121 -struct yaffs_DeviceStruct {
16122 - struct ylist_head devList;
16123 - const char *name;
16125 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
16126 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
16127 - int nChunksPerBlock; /* does not need to be a power of 2 */
16128 - int spareBytesPerChunk; /* spare area size */
16129 - int startBlock; /* Start block we're allowed to use */
16130 - int endBlock; /* End block we're allowed to use */
16131 - int nReservedBlocks; /* We want this tuneable so that we can reduce */
16132 - /* reserved blocks on NOR and RAM. */
16135 - /* Stuff used by the shared space checkpointing mechanism */
16136 - /* If this value is zero, then this mechanism is disabled */
16137 +struct yaffs_param_s {
16138 + const YCHAR *name;
16140 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
16142 + * Entry parameters set up way early. Yaffs sets up the rest.
16143 + * The structure should be zeroed out before use so that unused
16144 + * and defualt values are zero.
16147 + int inband_tags; /* Use unband tags */
16148 + __u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */
16149 + int chunks_per_block; /* does not need to be a power of 2 */
16150 + int spare_bytes_per_chunk; /* spare area size */
16151 + int start_block; /* Start block we're allowed to use */
16152 + int end_block; /* End block we're allowed to use */
16153 + int n_reserved_blocks; /* We want this tuneable so that we can reduce */
16154 + /* reserved blocks on NOR and RAM. */
16157 - int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
16158 - * the number of short op caches (don't use too many)
16159 + int n_caches; /* If <= 0, then short op caching is disabled, else
16160 + * the number of short op caches (don't use too many).
16161 + * 10 to 20 is a good bet.
16163 + int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
16164 + int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
16166 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
16167 + int is_yaffs2; /* Use yaffs2 mode on this device */
16169 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
16170 + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
16172 - void *genericDevice; /* Pointer to device context
16173 - * On an mtd this holds the mtd pointer.
16175 - void *superBlock;
16176 + int refresh_period; /* How often we should check to do a block refresh */
16178 + /* Checkpoint control. Can be set before or after initialisation */
16179 + __u8 skip_checkpt_rd;
16180 + __u8 skip_checkpt_wr;
16182 + int enable_xattr; /* Enable xattribs */
16184 /* NAND access functions (Must be set before calling YAFFS)*/
16186 - int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,
16187 - int chunkInNAND, const __u8 *data,
16188 - const yaffs_Spare *spare);
16189 - int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev,
16190 - int chunkInNAND, __u8 *data,
16191 - yaffs_Spare *spare);
16192 - int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev,
16193 - int blockInNAND);
16194 - int (*initialiseNAND) (struct yaffs_DeviceStruct *dev);
16195 - int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev);
16196 + int (*write_chunk_fn) (struct yaffs_dev_s *dev,
16197 + int nand_chunk, const __u8 *data,
16198 + const yaffs_spare *spare);
16199 + int (*read_chunk_fn) (struct yaffs_dev_s *dev,
16200 + int nand_chunk, __u8 *data,
16201 + yaffs_spare *spare);
16202 + int (*erase_fn) (struct yaffs_dev_s *dev,
16203 + int flash_block);
16204 + int (*initialise_flash_fn) (struct yaffs_dev_s *dev);
16205 + int (*deinitialise_flash_fn) (struct yaffs_dev_s *dev);
16207 #ifdef CONFIG_YAFFS_YAFFS2
16208 - int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev,
16209 - int chunkInNAND, const __u8 *data,
16210 - const yaffs_ExtendedTags *tags);
16211 - int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev,
16212 - int chunkInNAND, __u8 *data,
16213 - yaffs_ExtendedTags *tags);
16214 - int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo);
16215 - int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo,
16216 - yaffs_BlockState *state, __u32 *sequenceNumber);
16221 - /* The removeObjectCallback function must be supplied by OS flavours that
16222 - * need it. The Linux kernel does not use this, but yaffs direct does use
16223 - * it to implement the faster readdir
16224 + int (*write_chunk_tags_fn) (struct yaffs_dev_s *dev,
16225 + int nand_chunk, const __u8 *data,
16226 + const yaffs_ext_tags *tags);
16227 + int (*read_chunk_tags_fn) (struct yaffs_dev_s *dev,
16228 + int nand_chunk, __u8 *data,
16229 + yaffs_ext_tags *tags);
16230 + int (*bad_block_fn) (struct yaffs_dev_s *dev, int block_no);
16231 + int (*query_block_fn) (struct yaffs_dev_s *dev, int block_no,
16232 + yaffs_block_state_t *state, __u32 *seq_number);
16235 + /* The remove_obj_fn function must be supplied by OS flavours that
16237 + * yaffs direct uses it to implement the faster readdir.
16238 + * Linux uses it to protect the directory during unlocking.
16240 - void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
16241 + void (*remove_obj_fn)(struct yaffs_obj_s *obj);
16243 - /* Callback to mark the superblock dirsty */
16244 - void (*markSuperBlockDirty)(void *superblock);
16245 + /* Callback to mark the superblock dirty */
16246 + void (*sb_dirty_fn)(struct yaffs_dev_s *dev);
16248 + /* Callback to control garbage collection. */
16249 + unsigned (*gc_control)(struct yaffs_dev_s *dev);
16251 + /* Debug control flags. Don't use unless you know what you're doing */
16252 + int use_header_file_size; /* Flag to determine if we should use file sizes from the header */
16253 + int disable_lazy_load; /* Disable lazy loading on this device */
16254 + int wide_tnodes_disabled; /* Set to disable wide tnodes */
16255 + int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */
16257 + int defered_dir_update; /* Set to defer directory updates */
16259 - int wideTnodesDisabled; /* Set to disable wide tnodes */
16260 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
16261 + int auto_unicode;
16263 + int always_check_erased; /* Force chunk erased check always on */
16266 - YCHAR *pathDividers; /* String of legal path dividers */
16267 +typedef struct yaffs_param_s yaffs_param_t;
16269 +struct yaffs_dev_s {
16270 + struct yaffs_param_s param;
16272 - /* End of stuff that must be set before initialisation. */
16273 + /* Context storage. Holds extra OS specific data for this device */
16275 - /* Checkpoint control. Can be set before or after initialisation */
16276 - __u8 skipCheckpointRead;
16277 - __u8 skipCheckpointWrite;
16278 + void *os_context;
16279 + void *driver_context;
16281 + struct ylist_head dev_list;
16283 /* Runtime parameters. Set up by YAFFS. */
16284 + int data_bytes_per_chunk;
16286 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
16287 - __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
16288 + /* Non-wide tnode stuff */
16289 + __u16 chunk_grp_bits; /* Number of bits that need to be resolved if
16290 + * the tnodes are not wide enough.
16292 + __u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
16294 /* Stuff to support wide tnodes */
16295 - __u32 tnodeWidth;
16297 + __u32 tnode_width;
16298 + __u32 tnode_mask;
16299 + __u32 tnode_size;
16301 /* Stuff for figuring out file offset to chunk conversions */
16302 - __u32 chunkShift; /* Shift value */
16303 - __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
16304 - __u32 chunkMask; /* Mask to use for power-of-2 case */
16306 - /* Stuff to handle inband tags */
16308 - __u32 totalBytesPerChunk;
16312 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
16313 - struct semaphore grossLock; /* Gross locking semaphore */
16314 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
16315 - * at compile time so we have to allocate it.
16317 - void (*putSuperFunc) (struct super_block *sb);
16319 + __u32 chunk_shift; /* Shift value */
16320 + __u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */
16321 + __u32 chunk_mask; /* Mask to use for power-of-2 case */
16325 - int isCheckpointed;
16329 + int is_checkpointed;
16332 /* Stuff to support block offsetting to support start block zero */
16333 - int internalStartBlock;
16334 - int internalEndBlock;
16337 + int internal_start_block;
16338 + int internal_end_block;
16339 + int block_offset;
16340 + int chunk_offset;
16343 /* Runtime checkpointing stuff */
16344 - int checkpointPageSequence; /* running sequence number of checkpoint pages */
16345 - int checkpointByteCount;
16346 - int checkpointByteOffset;
16347 - __u8 *checkpointBuffer;
16348 - int checkpointOpenForWrite;
16349 - int blocksInCheckpoint;
16350 - int checkpointCurrentChunk;
16351 - int checkpointCurrentBlock;
16352 - int checkpointNextBlock;
16353 - int *checkpointBlockList;
16354 - int checkpointMaxBlocks;
16355 - __u32 checkpointSum;
16356 - __u32 checkpointXor;
16357 + int checkpt_page_seq; /* running sequence number of checkpoint pages */
16358 + int checkpt_byte_count;
16359 + int checkpt_byte_offs;
16360 + __u8 *checkpt_buffer;
16361 + int checkpt_open_write;
16362 + int blocks_in_checkpt;
16363 + int checkpt_cur_chunk;
16364 + int checkpt_cur_block;
16365 + int checkpt_next_block;
16366 + int *checkpt_block_list;
16367 + int checkpt_max_blocks;
16368 + __u32 checkpt_sum;
16369 + __u32 checkpt_xor;
16371 - int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
16372 + int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */
16375 - yaffs_BlockInfo *blockInfo;
16376 - __u8 *chunkBits; /* bitmap of chunks in use */
16377 - unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
16378 - unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
16379 - int chunkBitmapStride; /* Number of bytes of chunkBits per block.
16380 - * Must be consistent with nChunksPerBlock.
16381 + yaffs_block_info_t *block_info;
16382 + __u8 *chunk_bits; /* bitmap of chunks in use */
16383 + unsigned block_info_alt:1; /* was allocated using alternative strategy */
16384 + unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */
16385 + int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
16386 + * Must be consistent with chunks_per_block.
16389 - int nErasedBlocks;
16390 - int allocationBlock; /* Current block being allocated off */
16391 - __u32 allocationPage;
16392 - int allocationBlockFinder; /* Used to search for next allocation block */
16394 - /* Runtime state */
16395 - int nTnodesCreated;
16396 - yaffs_Tnode *freeTnodes;
16398 - yaffs_TnodeList *allocatedTnodeList;
16404 - int nObjectsCreated;
16405 - yaffs_Object *freeObjects;
16406 - int nFreeObjects;
16410 - yaffs_ObjectList *allocatedObjectList;
16412 - yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
16416 - int currentDirtyChecker; /* Used to find current dirtiest block */
16418 - __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
16419 - int nonAggressiveSkip; /* GC state/mode */
16424 - int nBlockErasures;
16425 - int nErasureFailures;
16427 - int garbageCollections;
16428 - int passiveGarbageCollections;
16429 - int nRetriedWrites;
16430 - int nRetiredBlocks;
16433 - int tagsEccFixed;
16434 - int tagsEccUnfixed;
16436 - int nUnmarkedDeletions;
16438 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
16439 + int n_erased_blocks;
16440 + int alloc_block; /* Current block being allocated off */
16441 + __u32 alloc_page;
16442 + int alloc_block_finder; /* Used to search for next allocation block */
16444 + /* Object and Tnode memory management */
16451 + yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
16452 + __u32 bucket_finder;
16454 + int n_free_chunks;
16456 + /* Garbage collection control */
16457 + __u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
16458 + __u32 n_clean_ups;
16460 + unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */
16461 + unsigned gc_disable;
16462 + unsigned gc_block_finder;
16463 + unsigned gc_dirtiest;
16464 + unsigned gc_pages_in_use;
16465 + unsigned gc_not_done;
16466 + unsigned gc_block;
16467 + unsigned gc_chunk;
16468 + unsigned gc_skip;
16470 /* Special directories */
16471 - yaffs_Object *rootDir;
16472 - yaffs_Object *lostNFoundDir;
16473 + yaffs_obj_t *root_dir;
16474 + yaffs_obj_t *lost_n_found;
16476 /* Buffer areas for storing data to recover from write failures TODO
16477 - * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
16478 - * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
16479 + * __u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
16480 + * yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK];
16483 - int bufferedBlock; /* Which block is buffered here? */
16484 - int doingBufferedBlockRewrite;
16486 - yaffs_ChunkCache *srCache;
16488 + int buffered_block; /* Which block is buffered here? */
16489 + int doing_buffered_block_rewrite;
16492 + yaffs_cache_t *cache;
16493 + int cache_last_use;
16495 /* Stuff for background deletion and unlinked files.*/
16496 - yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
16497 - yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
16498 - yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
16499 - int nDeletedFiles; /* Count of files awaiting deletion;*/
16500 - int nUnlinkedFiles; /* Count of unlinked files. */
16501 - int nBackgroundDeletions; /* Count of background deletions. */
16503 + yaffs_obj_t *unlinked_dir; /* Directory where unlinked and deleted files live. */
16504 + yaffs_obj_t *del_dir; /* Directory where deleted objects are sent to disappear. */
16505 + yaffs_obj_t *unlinked_deletion; /* Current file being background deleted.*/
16506 + int n_deleted_files; /* Count of files awaiting deletion;*/
16507 + int n_unlinked_files; /* Count of unlinked files. */
16508 + int n_bg_deletions; /* Count of background deletions. */
16510 /* Temporary buffer management */
16511 - yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
16514 - int unmanagedTempAllocations;
16515 - int unmanagedTempDeallocations;
16516 + yaffs_buffer_t temp_buffer[YAFFS_N_TEMP_BUFFERS];
16519 + int unmanaged_buffer_allocs;
16520 + int unmanaged_buffer_deallocs;
16522 /* yaffs2 runtime stuff */
16523 - unsigned sequenceNumber; /* Sequence number of currently allocating block */
16524 - unsigned oldestDirtySequence;
16525 + unsigned seq_number; /* Sequence number of currently allocating block */
16526 + unsigned oldest_dirty_seq;
16527 + unsigned oldest_dirty_block;
16529 + /* Block refreshing */
16530 + int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */
16532 + /* Dirty directory handling */
16533 + struct ylist_head dirty_dirs; /* List of dirty directories */
16537 + __u32 n_page_writes;
16538 + __u32 n_page_reads;
16539 + __u32 n_erasures;
16540 + __u32 n_erase_failures;
16541 + __u32 n_gc_copies;
16543 + __u32 passive_gc_count;
16544 + __u32 oldest_dirty_gc_count;
16545 + __u32 n_gc_blocks;
16547 + __u32 n_retired_writes;
16548 + __u32 n_retired_blocks;
16549 + __u32 n_ecc_fixed;
16550 + __u32 n_ecc_unfixed;
16551 + __u32 n_tags_ecc_fixed;
16552 + __u32 n_tags_ecc_unfixed;
16553 + __u32 n_deletions;
16554 + __u32 n_unmarked_deletions;
16555 + __u32 refresh_count;
16556 + __u32 cache_hits;
16560 -typedef struct yaffs_DeviceStruct yaffs_Device;
16561 +typedef struct yaffs_dev_s yaffs_dev_t;
16563 /* The static layout of block usage etc is stored in the super block header */
16567 - int checkpointStartBlock;
16568 - int checkpointEndBlock;
16571 + int checkpt_start_block;
16572 + int checkpt_end_block;
16576 -} yaffs_SuperBlockHeader;
16577 +} yaffs_sb_header;
16579 /* The CheckpointDevice structure holds the device information that changes at runtime and
16580 * must be preserved over unmount/mount cycles.
16584 - int nErasedBlocks;
16585 - int allocationBlock; /* Current block being allocated off */
16586 - __u32 allocationPage;
16589 - int nDeletedFiles; /* Count of files awaiting deletion;*/
16590 - int nUnlinkedFiles; /* Count of unlinked files. */
16591 - int nBackgroundDeletions; /* Count of background deletions. */
16593 + int n_erased_blocks;
16594 + int alloc_block; /* Current block being allocated off */
16595 + __u32 alloc_page;
16596 + int n_free_chunks;
16598 + int n_deleted_files; /* Count of files awaiting deletion;*/
16599 + int n_unlinked_files; /* Count of unlinked files. */
16600 + int n_bg_deletions; /* Count of background deletions. */
16602 /* yaffs2 runtime stuff */
16603 - unsigned sequenceNumber; /* Sequence number of currently allocating block */
16604 - unsigned oldestDirtySequence;
16605 + unsigned seq_number; /* Sequence number of currently allocating block */
16607 -} yaffs_CheckpointDevice;
16608 +} yaffs_checkpt_dev_t;
16617 -} yaffs_CheckpointValidity;
16618 +} yaffs_checkpt_validty_t;
16621 +struct yaffs_shadow_fixer_s {
16624 + struct yaffs_shadow_fixer_s *next;
16627 +/* Structure for doing xattr modifications */
16629 + int set; /* If 0 then this is a deletion */
16630 + const YCHAR *name;
16631 + const void *data;
16638 /*----------------------- YAFFS Functions -----------------------*/
16640 -int yaffs_GutsInitialise(yaffs_Device *dev);
16641 -void yaffs_Deinitialise(yaffs_Device *dev);
16642 +int yaffs_guts_initialise(yaffs_dev_t *dev);
16643 +void yaffs_deinitialise(yaffs_dev_t *dev);
16645 -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
16646 +int yaffs_get_n_free_chunks(yaffs_dev_t *dev);
16648 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
16649 - yaffs_Object *newDir, const YCHAR *newName);
16650 +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
16651 + yaffs_obj_t *new_dir, const YCHAR *new_name);
16653 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
16654 -int yaffs_DeleteObject(yaffs_Object *obj);
16655 +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name);
16656 +int yaffs_del_obj(yaffs_obj_t *obj);
16658 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize);
16659 -int yaffs_GetObjectFileLength(yaffs_Object *obj);
16660 -int yaffs_GetObjectInode(yaffs_Object *obj);
16661 -unsigned yaffs_GetObjectType(yaffs_Object *obj);
16662 -int yaffs_GetObjectLinkCount(yaffs_Object *obj);
16663 +int yaffs_get_obj_name(yaffs_obj_t *obj, YCHAR *name, int buffer_size);
16664 +int yaffs_get_obj_length(yaffs_obj_t *obj);
16665 +int yaffs_get_obj_inode(yaffs_obj_t *obj);
16666 +unsigned yaffs_get_obj_type(yaffs_obj_t *obj);
16667 +int yaffs_get_obj_link_count(yaffs_obj_t *obj);
16669 -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
16670 -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
16671 +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr);
16672 +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr);
16674 /* File operations */
16675 -int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset,
16677 -int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset,
16678 - int nBytes, int writeThrough);
16679 -int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize);
16680 +int yaffs_file_rd(yaffs_obj_t *obj, __u8 *buffer, loff_t offset,
16682 +int yaffs_wr_file(yaffs_obj_t *obj, const __u8 *buffer, loff_t offset,
16683 + int n_bytes, int write_trhrough);
16684 +int yaffs_resize_file(yaffs_obj_t *obj, loff_t new_size);
16686 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
16687 +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
16688 __u32 mode, __u32 uid, __u32 gid);
16689 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
16691 +int yaffs_flush_file(yaffs_obj_t *obj, int update_time, int data_sync);
16693 /* Flushing and checkpointing */
16694 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
16695 +void yaffs_flush_whole_cache(yaffs_dev_t *dev);
16697 -int yaffs_CheckpointSave(yaffs_Device *dev);
16698 -int yaffs_CheckpointRestore(yaffs_Device *dev);
16699 +int yaffs_checkpoint_save(yaffs_dev_t *dev);
16700 +int yaffs_checkpoint_restore(yaffs_dev_t *dev);
16702 /* Directory operations */
16703 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
16704 +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
16705 __u32 mode, __u32 uid, __u32 gid);
16706 -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name);
16707 -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
16708 - int (*fn) (yaffs_Object *));
16709 +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *the_dir, const YCHAR *name);
16710 +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
16711 + int (*fn) (yaffs_obj_t *));
16713 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number);
16714 +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number);
16716 /* Link operations */
16717 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
16718 - yaffs_Object *equivalentObject);
16719 +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
16720 + yaffs_obj_t *equiv_obj);
16722 -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
16723 +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj);
16725 /* Symlink operations */
16726 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
16727 +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
16728 __u32 mode, __u32 uid, __u32 gid,
16729 const YCHAR *alias);
16730 -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
16731 +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj);
16733 /* Special inodes (fifos, sockets and devices) */
16734 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
16735 +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
16736 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
16739 +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags);
16740 +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size);
16741 +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size);
16742 +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name);
16744 /* Special directories */
16745 -yaffs_Object *yaffs_Root(yaffs_Device *dev);
16746 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
16747 +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev);
16748 +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev);
16750 #ifdef CONFIG_YAFFS_WINCE
16751 /* CONFIG_YAFFS_WINCE special stuff */
16752 -void yfsd_WinFileTimeNow(__u32 target[2]);
16753 +void yfsd_win_file_time_now(__u32 target[2]);
16757 +void yaffs_handle_defered_free(yaffs_obj_t *obj);
16759 -void yaffs_HandleDeferedFree(yaffs_Object *obj);
16761 +void yaffs_update_dirty_dirs(yaffs_dev_t *dev);
16763 +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency);
16766 -int yaffs_DumpObject(yaffs_Object *obj);
16767 +int yaffs_dump_obj(yaffs_obj_t *obj);
16769 -void yaffs_GutsTest(yaffs_Device *dev);
16770 +void yaffs_guts_test(yaffs_dev_t *dev);
16772 -/* A few useful functions */
16773 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
16774 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
16775 -int yaffs_CheckFF(__u8 *buffer, int nBytes);
16776 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
16777 +/* A few useful functions to be used within the core files*/
16778 +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn);
16779 +int yaffs_check_ff(__u8 *buffer, int n_bytes);
16780 +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi);
16782 +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no);
16783 +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer, int line_no);
16785 +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
16787 + yaffs_obj_type type);
16788 +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
16789 + int nand_chunk, int in_scan);
16790 +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name);
16791 +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh);
16792 +void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
16793 + yaffs_obj_t *obj);
16794 +YCHAR *yaffs_clone_str(const YCHAR *str);
16795 +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list);
16796 +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no);
16797 +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name,
16798 + int force, int is_shrink, int shadows,
16799 + yaffs_xattr_mod *xop);
16800 +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
16801 + int backward_scanning);
16802 +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks);
16803 +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev);
16804 +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
16805 + yaffs_file_s *file_struct,
16807 + yaffs_tnode_t *passed_tn);
16809 +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
16810 + int n_bytes, int write_trhrough);
16811 +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size);
16812 +void yaffs_skip_rest_of_block(yaffs_dev_t *dev);
16814 +int yaffs_count_free_chunks(yaffs_dev_t *dev);
16816 +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
16817 + yaffs_file_s *file_struct,
16820 -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
16821 -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
16822 +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos);
16825 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffsinterface.h linux-2.6.36-rc8.new/fs/yaffs2/yaffsinterface.h
16826 --- linux-2.6.36-rc8/fs/yaffs2/yaffsinterface.h 2010-10-20 13:17:58.955000294 +0300
16827 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffsinterface.h 2010-10-20 13:28:16.061000294 +0300
16830 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16832 - * Copyright (C) 2002-2007 Aleph One Ltd.
16833 + * Copyright (C) 2002-2010 Aleph One Ltd.
16834 * for Toby Churchill Ltd and Brightstar Engineering
16836 * Created by Charles Manning <charles@aleph1.co.uk>
16838 #ifndef __YAFFSINTERFACE_H__
16839 #define __YAFFSINTERFACE_H__
16841 -int yaffs_Initialise(unsigned nBlocks);
16842 +int yaffs_initialise(unsigned nBlocks);
16845 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_linux_allocator.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux_allocator.c
16846 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_linux_allocator.c 1970-01-01 02:00:00.000000000 +0200
16847 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux_allocator.c 2010-10-20 13:28:16.028000294 +0300
16850 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16852 + * Copyright (C) 2002-2010 Aleph One Ltd.
16853 + * for Toby Churchill Ltd and Brightstar Engineering
16855 + * Created by Charles Manning <charles@aleph1.co.uk>
16857 + * This program is free software; you can redistribute it and/or modify
16858 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16859 + * published by the Free Software Foundation.
16861 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16863 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
16867 +#include "yaffs_allocator.h"
16868 +#include "yaffs_guts.h"
16869 +#include "yaffs_trace.h"
16870 +#include "yportenv.h"
16871 +#include "yaffs_linux.h"
16873 + * Start out with the same allocator as yaffs direct.
16874 + * Todo: Change to Linux slab allocator.
16879 +#define NAMELEN 20
16880 +struct yaffs_AllocatorStruct {
16881 + char tnode_name[NAMELEN+1];
16882 + char object_name[NAMELEN+1];
16883 + struct kmem_cache *tnode_cache;
16884 + struct kmem_cache *object_cache;
16887 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
16891 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
16893 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
16895 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
16898 + if(allocator->tnode_cache){
16899 + kmem_cache_destroy(allocator->tnode_cache);
16900 + allocator->tnode_cache = NULL;
16902 + T(YAFFS_TRACE_ALWAYS,
16903 + (TSTR("NULL tnode cache\n")));
16907 + if(allocator->object_cache){
16908 + kmem_cache_destroy(allocator->object_cache);
16909 + allocator->object_cache = NULL;
16911 + T(YAFFS_TRACE_ALWAYS,
16912 + (TSTR("NULL object cache\n")));
16916 + YFREE(allocator);
16919 + T(YAFFS_TRACE_ALWAYS,
16920 + (TSTR("Deinitialising NULL allocator\n")));
16923 + dev->allocator = NULL;
16927 +static void fake_ctor0(void *data){data = data;}
16928 +static void fake_ctor1(void *data){data = data;}
16929 +static void fake_ctor2(void *data){data = data;}
16930 +static void fake_ctor3(void *data){data = data;}
16931 +static void fake_ctor4(void *data){data = data;}
16932 +static void fake_ctor5(void *data){data = data;}
16933 +static void fake_ctor6(void *data){data = data;}
16934 +static void fake_ctor7(void *data){data = data;}
16935 +static void fake_ctor8(void *data){data = data;}
16936 +static void fake_ctor9(void *data){data = data;}
16938 +static void (*fake_ctor_list[10]) (void *) = {
16951 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
16953 + yaffs_Allocator *allocator;
16954 + unsigned mount_id = yaffs_dev_to_lc(dev)->mount_id;
16956 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
16958 + if(dev->allocator)
16960 + else if(mount_id >= 10){
16961 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
16963 + allocator = YMALLOC(sizeof(yaffs_Allocator));
16964 + memset(allocator,0,sizeof(yaffs_Allocator));
16965 + dev->allocator = allocator;
16967 + if(!dev->allocator){
16968 + T(YAFFS_TRACE_ALWAYS,
16969 + (TSTR("yaffs allocator creation failed\n")));
16975 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
16976 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
16978 + allocator->tnode_cache =
16979 + kmem_cache_create(allocator->tnode_name,
16982 + fake_ctor_list[mount_id]);
16983 + if(allocator->tnode_cache)
16984 + T(YAFFS_TRACE_ALLOCATE,
16985 + (TSTR("tnode cache \"%s\" %p\n"),
16986 + allocator->tnode_name,allocator->tnode_cache));
16988 + T(YAFFS_TRACE_ALWAYS,
16989 + (TSTR("yaffs cache creation failed\n")));
16994 + allocator->object_cache =
16995 + kmem_cache_create(allocator->object_name,
16996 + sizeof(yaffs_obj_t),
16998 + fake_ctor_list[mount_id]);
17000 + if(allocator->object_cache)
17001 + T(YAFFS_TRACE_ALLOCATE,
17002 + (TSTR("object cache \"%s\" %p\n"),
17003 + allocator->object_name,allocator->object_cache));
17006 + T(YAFFS_TRACE_ALWAYS,
17007 + (TSTR("yaffs cache creation failed\n")));
17014 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
17016 + yaffs_Allocator *allocator = dev->allocator;
17017 + if(!allocator || !allocator->tnode_cache){
17021 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
17024 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
17026 + yaffs_Allocator *allocator = dev->allocator;
17027 + kmem_cache_free(allocator->tnode_cache,tn);
17030 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
17032 + yaffs_Allocator *allocator = dev->allocator;
17037 + if(!allocator->object_cache){
17041 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
17044 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
17046 + yaffs_Allocator *allocator = dev->allocator;
17047 + kmem_cache_free(allocator->object_cache,obj);
17049 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_linux.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux.h
17050 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_linux.h 1970-01-01 02:00:00.000000000 +0200
17051 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux.h 2010-10-20 13:28:16.061000294 +0300
17054 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17056 + * Copyright (C) 2002-2010 Aleph One Ltd.
17057 + * for Toby Churchill Ltd and Brightstar Engineering
17059 + * Created by Charles Manning <charles@aleph1.co.uk>
17061 + * This program is free software; you can redistribute it and/or modify
17062 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17063 + * published by the Free Software Foundation.
17065 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17068 +#ifndef __YAFFS_LINUX_H__
17069 +#define __YAFFS_LINUX_H__
17071 +#include "devextras.h"
17072 +#include "yportenv.h"
17074 +struct yaffs_LinuxContext {
17075 + struct ylist_head contextList; /* List of these we have mounted */
17076 + struct yaffs_dev_s *dev;
17077 + struct super_block * superBlock;
17078 + struct task_struct *bgThread; /* Background thread for this device */
17080 + struct semaphore grossLock; /* Gross locking semaphore */
17081 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
17082 + * at compile time so we have to allocate it.
17084 + struct ylist_head searchContexts;
17085 + void (*putSuperFunc)(struct super_block *sb);
17087 + struct task_struct *readdirProcess;
17088 + unsigned mount_id;
17091 +#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
17092 +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
17096 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_list.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_list.h
17097 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_list.h 1970-01-01 02:00:00.000000000 +0200
17098 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_list.h 2010-10-20 13:28:16.062000294 +0300
17101 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17103 + * Copyright (C) 2002-2010 Aleph One Ltd.
17104 + * for Toby Churchill Ltd and Brightstar Engineering
17106 + * Created by Charles Manning <charles@aleph1.co.uk>
17108 + * This program is free software; you can redistribute it and/or modify
17109 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17110 + * published by the Free Software Foundation.
17112 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17116 + * This file is just holds extra declarations of macros that would normally
17117 + * be providesd in the Linux kernel. These macros have been written from
17118 + * scratch but are functionally equivalent to the Linux ones.
17122 +#ifndef __YAFFS_LIST_H__
17123 +#define __YAFFS_LIST_H__
17126 +#include "yportenv.h"
17129 + * This is a simple doubly linked list implementation that matches the
17130 + * way the Linux kernel doubly linked list implementation works.
17133 +struct ylist_head {
17134 + struct ylist_head *next; /* next in chain */
17135 + struct ylist_head *prev; /* previous in chain */
17139 +/* Initialise a static list */
17140 +#define YLIST_HEAD(name) \
17141 +struct ylist_head name = { &(name), &(name)}
17145 +/* Initialise a list head to an empty list */
17146 +#define YINIT_LIST_HEAD(p) \
17148 + (p)->next = (p);\
17149 + (p)->prev = (p); \
17153 +/* Add an element to a list */
17154 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
17155 + struct ylist_head *list)
17157 + struct ylist_head *listNext = list->next;
17159 + list->next = newEntry;
17160 + newEntry->prev = list;
17161 + newEntry->next = listNext;
17162 + listNext->prev = newEntry;
17166 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
17167 + struct ylist_head *list)
17169 + struct ylist_head *listPrev = list->prev;
17171 + list->prev = newEntry;
17172 + newEntry->next = list;
17173 + newEntry->prev = listPrev;
17174 + listPrev->next = newEntry;
17179 +/* Take an element out of its current list, with or without
17180 + * reinitialising the links.of the entry*/
17181 +static Y_INLINE void ylist_del(struct ylist_head *entry)
17183 + struct ylist_head *listNext = entry->next;
17184 + struct ylist_head *listPrev = entry->prev;
17186 + listNext->prev = listPrev;
17187 + listPrev->next = listNext;
17191 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
17193 + ylist_del(entry);
17194 + entry->next = entry->prev = entry;
17198 +/* Test if the list is empty */
17199 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
17201 + return (entry->next == entry);
17205 +/* ylist_entry takes a pointer to a list entry and offsets it to that
17206 + * we can find a pointer to the object it is embedded in.
17210 +#define ylist_entry(entry, type, member) \
17211 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
17214 +/* ylist_for_each and list_for_each_safe iterate over lists.
17215 + * ylist_for_each_safe uses temporary storage to make the list delete safe
17218 +#define ylist_for_each(itervar, list) \
17219 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
17221 +#define ylist_for_each_safe(itervar, saveVar, list) \
17222 + for (itervar = (list)->next, saveVar = (list)->next->next; \
17223 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
17227 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.c
17228 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.c 2010-10-20 13:17:58.956000294 +0300
17229 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.c 2010-10-20 13:28:16.028000294 +0300
17231 * YAFFS: Yet another FFS. A NAND-flash specific file system.
17232 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
17234 - * Copyright (C) 2002 Aleph One Ltd.
17235 + * Copyright (C) 2002-2010 Aleph One Ltd.
17236 * for Toby Churchill Ltd and Brightstar Engineering
17238 * This program is free software; you can redistribute it and/or modify
17239 @@ -18,15 +18,17 @@
17241 * These functions are invoked via function pointers in yaffs_nand.c.
17242 * This replaces functionality provided by functions in yaffs_mtdif.c
17243 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
17244 + * and the yaffs_tags_tCompatability functions in yaffs_tagscompat.c that are
17245 * called in yaffs_mtdif.c when the function pointers are NULL.
17246 - * We assume the MTD layer is performing ECC (useNANDECC is true).
17247 + * We assume the MTD layer is performing ECC (use_nand_ecc is true).
17250 #include "yportenv.h"
17251 +#include "yaffs_trace.h"
17252 #include "yaffs_guts.h"
17253 #include "yaffs_packedtags1.h"
17254 -#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
17255 +#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
17256 +#include "yaffs_linux.h"
17258 #include "linux/kernel.h"
17259 #include "linux/version.h"
17261 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
17262 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
17264 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
17266 #ifndef CONFIG_YAFFS_9BYTE_TAGS
17267 # define YTAG1_SIZE 8
17269 @@ -51,12 +51,12 @@ const char *yaffs_mtdif1_c_version = "$I
17270 * adjust 'oobfree' to match your existing Yaffs data.
17272 * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
17273 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
17274 + * page_status byte (at NAND spare offset 4) scattered/gathered from/to
17277 * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
17278 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
17279 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
17280 + * We have/need PackedTags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
17281 + * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
17282 * byte and B is the small-page bad-block indicator byte.
17284 static struct nand_ecclayout nand_oob_16 = {
17285 @@ -88,42 +88,40 @@ static struct nand_ecclayout nand_oob_16
17286 * Any underlying MTD error results in YAFFS_FAIL.
17287 * Returns YAFFS_OK or YAFFS_FAIL.
17289 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
17290 - int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
17291 +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev,
17292 + int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
17294 - struct mtd_info *mtd = dev->genericDevice;
17295 - int chunkBytes = dev->nDataBytesPerChunk;
17296 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17297 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17298 + int chunkBytes = dev->data_bytes_per_chunk;
17299 + loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
17300 struct mtd_oob_ops ops;
17301 yaffs_PackedTags1 pt1;
17304 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
17305 + /* we assume that PackedTags1 and yaffs_tags_t are compatible */
17306 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
17307 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
17309 - dev->nPageWrites++;
17310 + compile_time_assertion(sizeof(yaffs_tags_t) == 8);
17312 yaffs_PackTags1(&pt1, etags);
17313 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
17314 + yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1);
17316 /* When deleting a chunk, the upper layer provides only skeletal
17317 - * etags, one with chunkDeleted set. However, we need to update the
17318 + * etags, one with is_deleted set. However, we need to update the
17319 * tags, not erase them completely. So we use the NAND write property
17320 * that only zeroed-bits stick and set tag bytes to all-ones and
17321 * zero just the (not) deleted bit.
17323 #ifndef CONFIG_YAFFS_9BYTE_TAGS
17324 - if (etags->chunkDeleted) {
17325 + if (etags->is_deleted) {
17326 memset(&pt1, 0xff, 8);
17327 /* clear delete status bit to indicate deleted */
17331 ((__u8 *)&pt1)[8] = 0xff;
17332 - if (etags->chunkDeleted) {
17333 + if (etags->is_deleted) {
17334 memset(&pt1, 0xff, 8);
17335 - /* zero pageStatus byte to indicate deleted */
17336 + /* zero page_status byte to indicate deleted */
17337 ((__u8 *)&pt1)[8] = 0;
17340 @@ -137,20 +135,20 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
17342 retval = mtd->write_oob(mtd, addr, &ops);
17344 - yaffs_trace(YAFFS_TRACE_MTD,
17345 - "write_oob failed, chunk %d, mtd error %d\n",
17346 - chunkInNAND, retval);
17347 + T(YAFFS_TRACE_MTD,
17348 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
17349 + nand_chunk, retval));
17351 return retval ? YAFFS_FAIL : YAFFS_OK;
17354 -/* Return with empty ExtendedTags but add eccResult.
17355 +/* Return with empty ExtendedTags but add ecc_result.
17357 -static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
17358 +static int rettags(yaffs_ext_tags *etags, int ecc_result, int retval)
17361 memset(etags, 0, sizeof(*etags));
17362 - etags->eccResult = eccResult;
17363 + etags->ecc_result = ecc_result;
17367 @@ -158,30 +156,28 @@ static int rettags(yaffs_ExtendedTags *e
17368 /* Read a chunk (page) from NAND.
17370 * Caller expects ExtendedTags data to be usable even on error; that is,
17371 - * all members except eccResult and blockBad are zeroed.
17372 + * all members except ecc_result and block_bad are zeroed.
17374 * - Check ECC results for data (if applicable)
17375 * - Check for blank/erased block (return empty ExtendedTags if blank)
17376 * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
17377 * - Convert PackedTags1 to ExtendedTags
17378 - * - Update eccResult and blockBad members to refect state.
17379 + * - Update ecc_result and block_bad members to refect state.
17381 * Returns YAFFS_OK or YAFFS_FAIL.
17383 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
17384 - int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
17385 +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev,
17386 + int nand_chunk, __u8 *data, yaffs_ext_tags *etags)
17388 - struct mtd_info *mtd = dev->genericDevice;
17389 - int chunkBytes = dev->nDataBytesPerChunk;
17390 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17391 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17392 + int chunkBytes = dev->data_bytes_per_chunk;
17393 + loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
17394 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
17395 struct mtd_oob_ops ops;
17396 yaffs_PackedTags1 pt1;
17400 - dev->nPageReads++;
17402 memset(&ops, 0, sizeof(ops));
17403 ops.mode = MTD_OOB_AUTO;
17404 ops.len = (data) ? chunkBytes : 0;
17405 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17407 retval = mtd->read_oob(mtd, addr, &ops);
17409 - yaffs_trace(YAFFS_TRACE_MTD,
17410 - "read_oob failed, chunk %d, mtd error %d\n",
17411 - chunkInNAND, retval);
17412 + T(YAFFS_TRACE_MTD,
17413 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
17414 + nand_chunk, retval));
17418 @@ -213,23 +209,23 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17420 /* MTD's ECC fixed the data */
17421 eccres = YAFFS_ECC_RESULT_FIXED;
17423 + dev->n_ecc_fixed++;
17427 /* MTD's ECC could not fix the data */
17428 - dev->eccUnfixed++;
17429 + dev->n_ecc_unfixed++;
17432 rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
17433 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
17434 + etags->block_bad = (mtd->block_isbad)(mtd, addr);
17438 /* Check for a blank/erased chunk.
17440 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
17441 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
17442 + if (yaffs_check_ff((__u8 *)&pt1, 8)) {
17443 + /* when blank, upper layers want ecc_result to be <= NO_ERROR */
17444 return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
17447 @@ -241,37 +237,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17448 deleted = !pt1.deleted;
17451 - deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
17452 + deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7);
17455 /* Check the packed tags mini-ECC and correct if necessary/possible.
17457 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
17458 + retval = yaffs_check_tags_ecc((yaffs_tags_t *)&pt1);
17461 /* no tags error, use MTD result */
17464 /* recovered tags-ECC error */
17465 - dev->tagsEccFixed++;
17466 + dev->n_tags_ecc_fixed++;
17467 if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
17468 eccres = YAFFS_ECC_RESULT_FIXED;
17471 /* unrecovered tags-ECC error */
17472 - dev->tagsEccUnfixed++;
17473 + dev->n_tags_ecc_unfixed++;
17474 return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
17477 /* Unpack the tags to extended form and set ECC result.
17478 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
17479 + * [set shouldBeFF just to keep yaffs_unpack_tags1 happy]
17481 pt1.shouldBeFF = 0xFFFFFFFF;
17482 - yaffs_UnpackTags1(etags, &pt1);
17483 - etags->eccResult = eccres;
17484 + yaffs_unpack_tags1(etags, &pt1);
17485 + etags->ecc_result = eccres;
17487 /* Set deleted state */
17488 - etags->chunkDeleted = deleted;
17489 + etags->is_deleted = deleted;
17493 @@ -282,15 +278,15 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17495 * Returns YAFFS_OK or YAFFS_FAIL.
17497 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
17498 +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
17500 - struct mtd_info *mtd = dev->genericDevice;
17501 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
17502 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17503 + int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
17506 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
17507 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
17509 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
17510 + retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
17511 return (retval) ? YAFFS_FAIL : YAFFS_OK;
17514 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
17515 int oobavail = mtd->ecclayout->oobavail;
17517 if (oobavail < YTAG1_SIZE) {
17518 - yaffs_trace(YAFFS_TRACE_ERROR,
17519 - "mtd device has only %d bytes for tags, need %d\n",
17520 - oobavail, YTAG1_SIZE);
17521 + T(YAFFS_TRACE_ERROR,
17522 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
17523 + oobavail, YTAG1_SIZE));
17527 @@ -322,13 +318,13 @@ static int nandmtd1_TestPrerequists(stru
17529 * Always returns YAFFS_OK.
17531 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
17532 - yaffs_BlockState *pState, __u32 *pSequenceNumber)
17533 +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
17534 + yaffs_block_state_t *pState, __u32 *pSequenceNumber)
17536 - struct mtd_info *mtd = dev->genericDevice;
17537 - int chunkNo = blockNo * dev->nChunksPerBlock;
17538 - loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
17539 - yaffs_ExtendedTags etags;
17540 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17541 + int chunkNo = block_no * dev->param.chunks_per_block;
17542 + loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk;
17543 + yaffs_ext_tags etags;
17544 int state = YAFFS_BLOCK_STATE_DEAD;
17547 @@ -340,17 +336,17 @@ int nandmtd1_QueryNANDBlock(struct yaffs
17550 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
17551 - etags.blockBad = (mtd->block_isbad)(mtd, addr);
17552 - if (etags.blockBad) {
17553 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
17554 - "block %d is marked bad\n", blockNo);
17555 + etags.block_bad = (mtd->block_isbad)(mtd, addr);
17556 + if (etags.block_bad) {
17557 + T(YAFFS_TRACE_BAD_BLOCKS,
17558 + (TSTR("block %d is marked bad"TENDSTR), block_no));
17559 state = YAFFS_BLOCK_STATE_DEAD;
17560 - } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
17561 + } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
17562 /* bad tags, need to look more closely */
17563 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17564 - } else if (etags.chunkUsed) {
17565 + } else if (etags.chunk_used) {
17566 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17567 - seqnum = etags.sequenceNumber;
17568 + seqnum = etags.seq_number;
17570 state = YAFFS_BLOCK_STATE_EMPTY;
17572 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1-compat.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1-compat.c
17573 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1-compat.c 2010-10-20 13:17:58.956000294 +0300
17574 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1-compat.c 1970-01-01 02:00:00.000000000 +0200
17576 -From ian@brightstareng.com Fri May 18 15:06:49 2007
17577 -From ian@brightstareng.com Fri May 18 15:08:21 2007
17578 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
17579 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
17580 - (envelope-from <ian@brightstareng.com>)
17581 - id 1Hp380-00011e-T6
17582 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
17583 -Received: from localhost (localhost.localdomain [127.0.0.1])
17584 - by zebra.brightstareng.com (Postfix) with ESMTP
17585 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
17586 -Received: from zebra.brightstareng.com ([127.0.0.1])
17587 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
17588 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
17589 -Received: from pippin (unknown [192.168.1.25])
17590 - by zebra.brightstareng.com (Postfix) with ESMTP
17591 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
17592 -From: Ian McDonnell <ian@brightstareng.com>
17593 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
17594 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
17595 -Date: Fri, 18 May 2007 10:06:49 -0400
17596 -User-Agent: KMail/1.9.1
17597 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
17598 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
17599 -Cc: Andrea Conti <alyf@alyf.net>,
17600 - Charles Manning <manningc2@actrix.gen.nz>
17602 -Content-Type: Multipart/Mixed;
17603 - boundary="Boundary-00=_5LbTGmt62YoutxM"
17604 -Message-Id: <200705181006.49860.ian@brightstareng.com>
17605 -X-Virus-Scanned: by amavisd-new at brightstareng.com
17608 -X-KMail-EncryptionState:
17609 -X-KMail-SignatureState:
17612 ---Boundary-00=_5LbTGmt62YoutxM
17613 -Content-Type: text/plain;
17614 - charset="iso-8859-15"
17615 -Content-Transfer-Encoding: 7bit
17616 -Content-Disposition: inline
17620 -On Friday 18 May 2007 08:34, you wrote:
17621 -> Yea team. With this fix in place (I put it in the wrong place
17622 -> at first) I can now mount and ls the Yaffs partition without
17623 -> an error messages!
17627 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
17628 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
17629 -See the LINUX_VERSION_CODE conditional in
17630 -nandmtd1_ReadChunkWithTagsFromNAND.
17634 ---Boundary-00=_5LbTGmt62YoutxM
17635 -Content-Type: text/x-csrc;
17636 - charset="iso-8859-15";
17637 - name="yaffs_mtdif1.c"
17638 -Content-Transfer-Encoding: 7bit
17639 -Content-Disposition: attachment;
17640 - filename="yaffs_mtdif1.c"
17643 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
17644 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
17646 - * Copyright (C) 2002 Aleph One Ltd.
17647 - * for Toby Churchill Ltd and Brightstar Engineering
17649 - * This program is free software; you can redistribute it and/or modify
17650 - * it under the terms of the GNU General Public License version 2 as
17651 - * published by the Free Software Foundation.
17655 - * This module provides the interface between yaffs_nand.c and the
17656 - * MTD API. This version is used when the MTD interface supports the
17657 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
17658 - * and we have small-page NAND device.
17660 - * These functions are invoked via function pointers in yaffs_nand.c.
17661 - * This replaces functionality provided by functions in yaffs_mtdif.c
17662 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
17663 - * called in yaffs_mtdif.c when the function pointers are NULL.
17664 - * We assume the MTD layer is performing ECC (useNANDECC is true).
17667 -#include "yportenv.h"
17668 -#include "yaffs_guts.h"
17669 -#include "yaffs_packedtags1.h"
17670 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
17672 -#include "linux/kernel.h"
17673 -#include "linux/version.h"
17674 -#include "linux/types.h"
17675 -#include "linux/mtd/mtd.h"
17677 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
17678 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
17680 -const char *yaffs_mtdif1_c_version = "$Id$";
17682 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17683 -# define YTAG1_SIZE 8
17685 -# define YTAG1_SIZE 9
17689 -/* Use the following nand_ecclayout with MTD when using
17690 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
17691 - * If you have existing Yaffs images and the byte order differs from this,
17692 - * adjust 'oobfree' to match your existing Yaffs data.
17694 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
17695 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
17698 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
17699 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
17700 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
17701 - * byte and B is the small-page bad-block indicator byte.
17703 -static struct nand_ecclayout nand_oob_16 = {
17705 - .eccpos = { 8, 9, 10, 13, 14, 15 },
17707 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
17711 -/* Write a chunk (page) of data to NAND.
17713 - * Caller always provides ExtendedTags data which are converted to a more
17714 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
17715 - * contents of the tags meta-data; used to valid the tags when read.
17717 - * - Pack ExtendedTags to PackedTags1 form
17718 - * - Compute mini-ECC for PackedTags1
17719 - * - Write data and packed tags to NAND.
17721 - * Note: Due to the use of the PackedTags1 meta-data which does not include
17722 - * a full sequence number (as found in the larger PackedTags2 form) it is
17723 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
17724 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
17725 - * to be written just once. When Yaffs performs this operation, this
17726 - * function is called with a NULL data pointer -- calling MTD write_oob
17727 - * without data is valid usage (2.6.17).
17729 - * Any underlying MTD error results in YAFFS_FAIL.
17730 - * Returns YAFFS_OK or YAFFS_FAIL.
17732 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
17733 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
17735 - struct mtd_info * mtd = dev->genericDevice;
17736 - int chunkBytes = dev->nDataBytesPerChunk;
17737 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17738 - struct mtd_oob_ops ops;
17739 - yaffs_PackedTags1 pt1;
17742 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
17743 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
17744 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
17746 - yaffs_PackTags1(&pt1, etags);
17747 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
17749 - /* When deleting a chunk, the upper layer provides only skeletal
17750 - * etags, one with chunkDeleted set. However, we need to update the
17751 - * tags, not erase them completely. So we use the NAND write property
17752 - * that only zeroed-bits stick and set tag bytes to all-ones and
17753 - * zero just the (not) deleted bit.
17755 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17756 - if (etags->chunkDeleted) {
17757 - memset(&pt1, 0xff, 8);
17758 - /* clear delete status bit to indicate deleted */
17762 - ((__u8 *)&pt1)[8] = 0xff;
17763 - if (etags->chunkDeleted) {
17764 - memset(&pt1, 0xff, 8);
17765 - /* zero pageStatus byte to indicate deleted */
17766 - ((__u8 *)&pt1)[8] = 0;
17770 - memset(&ops, 0, sizeof(ops));
17771 - ops.mode = MTD_OOB_AUTO;
17772 - ops.len = (data) ? chunkBytes : 0;
17773 - ops.ooblen = YTAG1_SIZE;
17774 - ops.datbuf = (__u8 *)data;
17775 - ops.oobbuf = (__u8 *)&pt1;
17777 - retval = mtd->write_oob(mtd, addr, &ops);
17779 - yaffs_trace(YAFFS_TRACE_MTD,
17780 - "write_oob failed, chunk %d, mtd error %d\n",
17781 - chunkInNAND, retval);
17783 - return retval ? YAFFS_FAIL : YAFFS_OK;
17786 -/* Return with empty ExtendedTags but add eccResult.
17788 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
17791 - memset(etags, 0, sizeof(*etags));
17792 - etags->eccResult = eccResult;
17797 -/* Read a chunk (page) from NAND.
17799 - * Caller expects ExtendedTags data to be usable even on error; that is,
17800 - * all members except eccResult and blockBad are zeroed.
17802 - * - Check ECC results for data (if applicable)
17803 - * - Check for blank/erased block (return empty ExtendedTags if blank)
17804 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
17805 - * - Convert PackedTags1 to ExtendedTags
17806 - * - Update eccResult and blockBad members to refect state.
17808 - * Returns YAFFS_OK or YAFFS_FAIL.
17810 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
17811 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
17813 - struct mtd_info * mtd = dev->genericDevice;
17814 - int chunkBytes = dev->nDataBytesPerChunk;
17815 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17816 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
17817 - struct mtd_oob_ops ops;
17818 - yaffs_PackedTags1 pt1;
17822 - memset(&ops, 0, sizeof(ops));
17823 - ops.mode = MTD_OOB_AUTO;
17824 - ops.len = (data) ? chunkBytes : 0;
17825 - ops.ooblen = YTAG1_SIZE;
17826 - ops.datbuf = data;
17827 - ops.oobbuf = (__u8 *)&pt1;
17829 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
17830 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
17831 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
17833 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
17835 - /* Read page and oob using MTD.
17836 - * Check status and determine ECC result.
17838 - retval = mtd->read_oob(mtd, addr, &ops);
17840 - yaffs_trace(YAFFS_TRACE_MTD,
17841 - "read_oob failed, chunk %d, mtd error %d\n",
17842 - chunkInNAND, retval);
17845 - switch (retval) {
17851 - /* MTD's ECC fixed the data */
17852 - eccres = YAFFS_ECC_RESULT_FIXED;
17857 - /* MTD's ECC could not fix the data */
17858 - dev->eccUnfixed++;
17859 - /* fall into... */
17861 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
17862 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
17863 - return YAFFS_FAIL;
17866 - /* Check for a blank/erased chunk.
17868 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
17869 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
17870 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
17873 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17874 - /* Read deleted status (bit) then return it to it's non-deleted
17875 - * state before performing tags mini-ECC check. pt1.deleted is
17878 - deleted = !pt1.deleted;
17881 - (void) deleted; /* not used */
17884 - /* Check the packed tags mini-ECC and correct if necessary/possible.
17886 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
17887 - switch (retval) {
17889 - /* no tags error, use MTD result */
17892 - /* recovered tags-ECC error */
17893 - dev->tagsEccFixed++;
17894 - eccres = YAFFS_ECC_RESULT_FIXED;
17897 - /* unrecovered tags-ECC error */
17898 - dev->tagsEccUnfixed++;
17899 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
17902 - /* Unpack the tags to extended form and set ECC result.
17903 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
17905 - pt1.shouldBeFF = 0xFFFFFFFF;
17906 - yaffs_UnpackTags1(etags, &pt1);
17907 - etags->eccResult = eccres;
17909 - /* Set deleted state.
17911 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17912 - etags->chunkDeleted = deleted;
17914 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
17919 -/* Mark a block bad.
17921 - * This is a persistant state.
17922 - * Use of this function should be rare.
17924 - * Returns YAFFS_OK or YAFFS_FAIL.
17926 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
17928 - struct mtd_info * mtd = dev->genericDevice;
17929 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
17932 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
17934 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
17935 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
17938 -/* Check any MTD prerequists.
17940 - * Returns YAFFS_OK or YAFFS_FAIL.
17942 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
17944 - /* 2.6.18 has mtd->ecclayout->oobavail */
17945 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
17946 - int oobavail = mtd->ecclayout->oobavail;
17948 - if (oobavail < YTAG1_SIZE) {
17949 - yaffs_trace(YAFFS_TRACE_ERROR,
17950 - "mtd device has only %d bytes for tags, need %d",
17951 - oobavail, YTAG1_SIZE);
17952 - return YAFFS_FAIL;
17957 -/* Query for the current state of a specific block.
17959 - * Examine the tags of the first chunk of the block and return the state:
17960 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
17961 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
17962 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
17964 - * Always returns YAFFS_OK.
17966 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
17967 - yaffs_BlockState * pState, int *pSequenceNumber)
17969 - struct mtd_info * mtd = dev->genericDevice;
17970 - int chunkNo = blockNo * dev->nChunksPerBlock;
17971 - yaffs_ExtendedTags etags;
17972 - int state = YAFFS_BLOCK_STATE_DEAD;
17976 - /* We don't yet have a good place to test for MTD config prerequists.
17977 - * Do it here as we are called during the initial scan.
17979 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
17980 - return YAFFS_FAIL;
17983 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
17984 - if (etags.blockBad) {
17985 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
17986 - "block %d is marked bad", blockNo);
17987 - state = YAFFS_BLOCK_STATE_DEAD;
17989 - else if (etags.chunkUsed) {
17990 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17991 - seqnum = etags.sequenceNumber;
17994 - state = YAFFS_BLOCK_STATE_EMPTY;
17998 - *pSequenceNumber = seqnum;
18000 - /* query always succeeds */
18004 -#endif /*KERNEL_VERSION*/
18006 ---Boundary-00=_5LbTGmt62YoutxM--
18010 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.h
18011 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.h 2010-10-20 13:17:58.957000294 +0300
18012 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.h 2010-10-20 13:28:16.062000294 +0300
18015 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
18017 - * Copyright (C) 2002-2007 Aleph One Ltd.
18018 + * Copyright (C) 2002-2010 Aleph One Ltd.
18019 * for Toby Churchill Ltd and Brightstar Engineering
18021 * This program is free software; you can redistribute it and/or modify
18022 @@ -14,15 +14,15 @@
18023 #ifndef __YAFFS_MTDIF1_H__
18024 #define __YAFFS_MTDIF1_H__
18026 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18027 - const __u8 *data, const yaffs_ExtendedTags *tags);
18028 +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18029 + const __u8 *data, const yaffs_ext_tags *tags);
18031 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18032 - __u8 *data, yaffs_ExtendedTags *tags);
18033 +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18034 + __u8 *data, yaffs_ext_tags *tags);
18036 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
18037 +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
18039 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18040 - yaffs_BlockState *state, __u32 *sequenceNumber);
18041 +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18042 + yaffs_block_state_t *state, __u32 *seq_number);
18045 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.c
18046 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.c 2010-10-20 13:17:58.957000294 +0300
18047 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.c 2010-10-20 13:28:16.028000294 +0300
18050 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18052 - * Copyright (C) 2002-2007 Aleph One Ltd.
18053 + * Copyright (C) 2002-2010 Aleph One Ltd.
18054 * for Toby Churchill Ltd and Brightstar Engineering
18056 * Created by Charles Manning <charles@aleph1.co.uk>
18059 /* mtd interface for YAFFS2 */
18061 -const char *yaffs_mtdif2_c_version =
18062 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
18064 #include "yportenv.h"
18066 +#include "yaffs_trace.h"
18068 #include "yaffs_mtdif2.h"
18070 @@ -27,15 +24,17 @@ const char *yaffs_mtdif2_c_version =
18072 #include "yaffs_packedtags2.h"
18074 +#include "yaffs_linux.h"
18076 /* NB For use with inband tags....
18077 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
18078 * use it to load the tags.
18080 -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18081 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18083 - const yaffs_ExtendedTags *tags)
18084 + const yaffs_ext_tags *tags)
18086 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18087 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18088 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18089 struct mtd_oob_ops ops;
18091 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18093 yaffs_PackedTags2 pt;
18095 + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
18096 + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t : (void *)&pt;
18100 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
18101 - TENDSTR), chunkInNAND, data, tags));
18102 + TENDSTR), nand_chunk, data, tags));
18105 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
18106 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
18108 /* For yaffs2 writing there must be both data and tags.
18109 * If we're using inband tags, then the tags are stuffed into
18110 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18112 if (!data || !tags)
18114 - else if (dev->inbandTags) {
18115 + else if (dev->param.inband_tags) {
18116 yaffs_PackedTags2TagsPart *pt2tp;
18117 - pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
18118 + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk);
18119 yaffs_PackTags2TagsPart(pt2tp, tags);
18121 - yaffs_PackTags2(&pt, tags);
18122 + yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
18124 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18125 ops.mode = MTD_OOB_AUTO;
18126 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
18127 - ops.len = dev->totalBytesPerChunk;
18128 + ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
18129 + ops.len = dev->param.total_bytes_per_chunk;
18131 ops.datbuf = (__u8 *)data;
18132 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
18133 + ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
18134 retval = mtd->write_oob(mtd, addr, &ops);
18137 - if (!dev->inbandTags) {
18138 + if (!dev->param.inband_tags) {
18140 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18141 - &dummy, data, (__u8 *) &pt, NULL);
18142 + mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
18143 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
18146 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
18147 + mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy,
18151 @@ -95,10 +97,10 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18155 -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18156 - __u8 *data, yaffs_ExtendedTags *tags)
18157 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18158 + __u8 *data, yaffs_ext_tags *tags)
18160 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18161 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18162 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18163 struct mtd_oob_ops ops;
18165 @@ -106,20 +108,23 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18169 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
18170 + loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
18172 yaffs_PackedTags2 pt;
18174 + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
18175 + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t: (void *)&pt;
18179 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
18180 - TENDSTR), chunkInNAND, data, tags));
18181 + TENDSTR), nand_chunk, data, tags));
18183 - if (dev->inbandTags) {
18184 + if (dev->param.inband_tags) {
18188 - data = yaffs_GetTempBuffer(dev, __LINE__);
18189 + data = yaffs_get_temp_buffer(dev, __LINE__);
18193 @@ -127,30 +132,30 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18196 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18197 - if (dev->inbandTags || (data && !tags))
18198 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
18199 + if (dev->param.inband_tags || (data && !tags))
18200 + retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
18203 ops.mode = MTD_OOB_AUTO;
18204 - ops.ooblen = sizeof(pt);
18205 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
18206 + ops.ooblen = packed_tags_size;
18207 + ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
18210 - ops.oobbuf = dev->spareBuffer;
18211 + ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
18212 retval = mtd->read_oob(mtd, addr, &ops);
18215 - if (!dev->inbandTags && data && tags) {
18216 + if (!dev->param.inband_tags && data && tags) {
18218 - retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18219 + retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
18220 &dummy, data, dev->spareBuffer,
18225 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18226 + mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
18228 - if (!dev->inbandTags && tags)
18229 + if (!dev->param.inband_tags && tags)
18231 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
18233 @@ -158,41 +163,47 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18237 - if (dev->inbandTags) {
18238 + if (dev->param.inband_tags) {
18240 yaffs_PackedTags2TagsPart *pt2tp;
18241 - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
18242 - yaffs_UnpackTags2TagsPart(tags, pt2tp);
18243 + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk];
18244 + yaffs_unpack_tags2tags_part(tags, pt2tp);
18248 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
18249 - yaffs_UnpackTags2(tags, &pt);
18250 + memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size);
18251 + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
18256 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
18257 + yaffs_release_temp_buffer(dev, data, __LINE__);
18259 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
18260 - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
18261 + if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
18262 + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
18263 + dev->n_ecc_unfixed++;
18265 + if(tags && retval == -EUCLEAN && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
18266 + tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
18267 + dev->n_ecc_fixed++;
18275 -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
18276 +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
18278 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18279 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18282 - (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
18283 + (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
18286 mtd->block_markbad(mtd,
18287 - blockNo * dev->nChunksPerBlock *
18288 - dev->totalBytesPerChunk);
18289 + block_no * dev->param.chunks_per_block *
18290 + dev->param.total_bytes_per_chunk);
18294 @@ -201,41 +212,41 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
18298 -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18299 - yaffs_BlockState *state, __u32 *sequenceNumber)
18300 +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18301 + yaffs_block_state_t *state, __u32 *seq_number)
18303 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18304 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18308 - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
18309 + (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
18311 mtd->block_isbad(mtd,
18312 - blockNo * dev->nChunksPerBlock *
18313 - dev->totalBytesPerChunk);
18314 + block_no * dev->param.chunks_per_block *
18315 + dev->param.total_bytes_per_chunk);
18318 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
18320 *state = YAFFS_BLOCK_STATE_DEAD;
18321 - *sequenceNumber = 0;
18324 - yaffs_ExtendedTags t;
18325 + yaffs_ext_tags t;
18326 nandmtd2_ReadChunkWithTagsFromNAND(dev,
18328 - dev->nChunksPerBlock, NULL,
18330 + dev->param.chunks_per_block, NULL,
18333 - if (t.chunkUsed) {
18334 - *sequenceNumber = t.sequenceNumber;
18335 + if (t.chunk_used) {
18336 + *seq_number = t.seq_number;
18337 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
18339 - *sequenceNumber = 0;
18341 *state = YAFFS_BLOCK_STATE_EMPTY;
18345 - (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
18346 + (TSTR("block is bad seq %d state %d" TENDSTR), *seq_number,
18350 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.h
18351 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.h 2010-10-20 13:17:58.957000294 +0300
18352 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.h 2010-10-20 13:28:16.062000294 +0300
18355 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18357 - * Copyright (C) 2002-2007 Aleph One Ltd.
18358 + * Copyright (C) 2002-2010 Aleph One Ltd.
18359 * for Toby Churchill Ltd and Brightstar Engineering
18361 * Created by Charles Manning <charles@aleph1.co.uk>
18362 @@ -17,13 +17,13 @@
18363 #define __YAFFS_MTDIF2_H__
18365 #include "yaffs_guts.h"
18366 -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18367 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18369 - const yaffs_ExtendedTags *tags);
18370 -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18371 - __u8 *data, yaffs_ExtendedTags *tags);
18372 -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
18373 -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18374 - yaffs_BlockState *state, __u32 *sequenceNumber);
18375 + const yaffs_ext_tags *tags);
18376 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18377 + __u8 *data, yaffs_ext_tags *tags);
18378 +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
18379 +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18380 + yaffs_block_state_t *state, __u32 *seq_number);
18383 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.c
18384 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.c 2010-10-20 13:17:58.958000294 +0300
18385 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.c 2010-10-20 13:28:16.029000294 +0300
18388 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18390 - * Copyright (C) 2002-2007 Aleph One Ltd.
18391 + * Copyright (C) 2002-2010 Aleph One Ltd.
18392 * for Toby Churchill Ltd and Brightstar Engineering
18394 * Created by Charles Manning <charles@aleph1.co.uk>
18396 * published by the Free Software Foundation.
18399 -const char *yaffs_mtdif_c_version =
18400 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
18402 #include "yportenv.h"
18405 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
18406 #include "linux/time.h"
18407 #include "linux/mtd/nand.h"
18409 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
18410 -static struct nand_oobinfo yaffs_oobinfo = {
18413 - .eccpos = {8, 9, 10, 13, 14, 15}
18416 -static struct nand_oobinfo yaffs_noeccinfo = {
18421 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18422 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
18424 - oob[0] = spare->tagByte0;
18425 - oob[1] = spare->tagByte1;
18426 - oob[2] = spare->tagByte2;
18427 - oob[3] = spare->tagByte3;
18428 - oob[4] = spare->tagByte4;
18429 - oob[5] = spare->tagByte5 & 0x3f;
18430 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
18431 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
18432 - oob[6] = spare->tagByte6;
18433 - oob[7] = spare->tagByte7;
18436 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
18438 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
18439 - spare->tagByte0 = oob[0];
18440 - spare->tagByte1 = oob[1];
18441 - spare->tagByte2 = oob[2];
18442 - spare->tagByte3 = oob[3];
18443 - spare->tagByte4 = oob[4];
18444 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
18445 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
18446 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
18447 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
18448 - spare->tagByte6 = oob[6];
18449 - spare->tagByte7 = oob[7];
18450 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
18452 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
18456 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
18457 - const __u8 *data, const yaffs_Spare *spare)
18459 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18460 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18461 - struct mtd_oob_ops ops;
18466 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
18467 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18468 - __u8 spareAsBytes[8]; /* OOB */
18470 - if (data && !spare)
18471 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
18473 - else if (spare) {
18474 - if (dev->useNANDECC) {
18475 - translate_spare2oob(spare, spareAsBytes);
18476 - ops.mode = MTD_OOB_AUTO;
18477 - ops.ooblen = 8; /* temp hack */
18479 - ops.mode = MTD_OOB_RAW;
18480 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
18482 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
18483 - ops.datbuf = (u8 *)data;
18485 - ops.oobbuf = spareAsBytes;
18486 - retval = mtd->write_oob(mtd, addr, &ops);
18489 - __u8 *spareAsBytes = (__u8 *) spare;
18491 - if (data && spare) {
18492 - if (dev->useNANDECC)
18494 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18495 - &dummy, data, spareAsBytes,
18499 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18500 - &dummy, data, spareAsBytes,
18501 - &yaffs_noeccinfo);
18505 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18509 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
18510 - &dummy, spareAsBytes);
18517 - return YAFFS_FAIL;
18520 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
18521 - yaffs_Spare *spare)
18523 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18524 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18525 - struct mtd_oob_ops ops;
18529 +#include "yaffs_linux.h"
18531 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
18532 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18533 - __u8 spareAsBytes[8]; /* OOB */
18535 - if (data && !spare)
18536 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
18538 - else if (spare) {
18539 - if (dev->useNANDECC) {
18540 - ops.mode = MTD_OOB_AUTO;
18541 - ops.ooblen = 8; /* temp hack */
18543 - ops.mode = MTD_OOB_RAW;
18544 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
18546 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
18547 - ops.datbuf = data;
18549 - ops.oobbuf = spareAsBytes;
18550 - retval = mtd->read_oob(mtd, addr, &ops);
18551 - if (dev->useNANDECC)
18552 - translate_oob2spare(spare, spareAsBytes);
18555 - __u8 *spareAsBytes = (__u8 *) spare;
18557 - if (data && spare) {
18558 - if (dev->useNANDECC) {
18559 - /* Careful, this call adds 2 ints */
18560 - /* to the end of the spare data. Calling function */
18561 - /* should allocate enough memory for spare, */
18562 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
18564 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18565 - &dummy, data, spareAsBytes,
18569 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18570 - &dummy, data, spareAsBytes,
18571 - &yaffs_noeccinfo);
18576 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18580 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
18581 - &dummy, spareAsBytes);
18588 - return YAFFS_FAIL;
18591 -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
18592 +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
18594 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18595 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18597 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
18598 - * dev->nChunksPerBlock;
18599 + ((loff_t) blockNumber) * dev->param.total_bytes_per_chunk
18600 + * dev->param.chunks_per_block;
18601 struct erase_info ei;
18607 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
18608 + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
18611 ei.callback = NULL;
18612 ei.priv = (u_long) dev;
18614 - /* Todo finish off the ei if required */
18616 - sema_init(&dev->sem, 0);
18618 retval = mtd->erase(mtd, &ei);
18621 @@ -234,7 +49,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Devic
18625 -int nandmtd_InitialiseNAND(yaffs_Device *dev)
18626 +int nandmtd_InitialiseNAND(yaffs_dev_t *dev)
18630 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.h
18631 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.h 2010-10-20 13:17:58.958000294 +0300
18632 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.h 2010-10-20 13:28:16.062000294 +0300
18635 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18637 - * Copyright (C) 2002-2007 Aleph One Ltd.
18638 + * Copyright (C) 2002-2010 Aleph One Ltd.
18639 * for Toby Churchill Ltd and Brightstar Engineering
18641 * Created by Charles Manning <charles@aleph1.co.uk>
18643 extern struct nand_oobinfo yaffs_oobinfo;
18644 extern struct nand_oobinfo yaffs_noeccinfo;
18647 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
18648 - const __u8 *data, const yaffs_Spare *spare);
18649 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
18650 - yaffs_Spare *spare);
18651 -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
18652 -int nandmtd_InitialiseNAND(yaffs_Device *dev);
18653 +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
18654 +int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
18656 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.c
18657 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.c 1970-01-01 02:00:00.000000000 +0200
18658 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.c 2010-10-20 13:28:16.029000294 +0300
18661 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18663 + * Copyright (C) 2002-2010 Aleph One Ltd.
18664 + * for Toby Churchill Ltd and Brightstar Engineering
18666 + * Created by Charles Manning <charles@aleph1.co.uk>
18668 + * This program is free software; you can redistribute it and/or modify
18669 + * it under the terms of the GNU General Public License version 2 as
18670 + * published by the Free Software Foundation.
18674 + * This simple implementation of a name-value store assumes a small number of values and fits
18675 + * into a small finite buffer.
18677 + * Each attribute is stored as a record:
18678 + * sizeof(int) bytes record size.
18679 + * strnlen+1 bytes name null terminated.
18682 + * total size stored in record size
18684 + * This code has not been tested with unicode yet.
18688 +#include "yaffs_nameval.h"
18690 +#include "yportenv.h"
18692 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
18698 + memcpy(&size,xb,sizeof(int));
18699 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
18700 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
18702 + *exist_size = size;
18706 + if(pos < xb_size -sizeof(int))
18707 + memcpy(&size,xb + pos,sizeof(int));
18716 +static int nval_used(const char *xb, int xb_size)
18721 + memcpy(&size,xb + pos,sizeof(int));
18722 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
18724 + if(pos < xb_size -sizeof(int))
18725 + memcpy(&size,xb + pos,sizeof(int));
18732 +int nval_del(char *xb, int xb_size, const YCHAR *name)
18734 + int pos = nval_find(xb, xb_size, name, NULL);
18737 + if(pos >= 0 && pos < xb_size){
18738 + /* Find size, shift rest over this record, then zero out the rest of buffer */
18739 + memcpy(&size,xb+pos,sizeof(int));
18740 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
18741 + memset(xb + (xb_size - size),0,size);
18747 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
18750 + int namelen = yaffs_strnlen(name,xb_size);
18752 + int size_exist = 0;
18756 + pos = nval_find(xb,xb_size,name, &size_exist);
18758 + if(flags & XATTR_CREATE && pos >= 0)
18760 + if(flags & XATTR_REPLACE && pos < 0)
18763 + start = nval_used(xb,xb_size);
18764 + space = xb_size - start + size_exist;
18766 + reclen = (sizeof(int) + namelen + 1 + bsize);
18768 + if(reclen > space)
18772 + nval_del(xb,xb_size,name);
18773 + start = nval_used(xb, xb_size);
18778 + memcpy(xb + pos,&reclen,sizeof(int));
18779 + pos +=sizeof(int);
18780 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
18781 + pos+= (namelen+1);
18782 + memcpy(xb + pos,buf,bsize);
18786 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
18788 + int pos = nval_find(xb,xb_size,name,NULL);
18791 + if(pos >= 0 && pos< xb_size){
18793 + memcpy(&size,xb +pos,sizeof(int));
18794 + pos+=sizeof(int); /* advance past record length */
18795 + size -= sizeof(int);
18797 + /* Advance over name string */
18798 + while(xb[pos] && size > 0 && pos < xb_size){
18802 + /*Advance over NUL */
18806 + if(size <= bsize){
18807 + memcpy(buf,xb + pos,size);
18818 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
18826 + memcpy(&size,xb + pos,sizeof(int));
18827 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
18828 + pos+= sizeof(int);
18829 + size-=sizeof(int);
18830 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
18831 + if(ncopied + name_len + 1 < bsize){
18832 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
18836 + if(sizeof(YCHAR) > 1){
18840 + ncopied += (name_len+1);
18844 + if(pos < xb_size -sizeof(int))
18845 + memcpy(&size,xb + pos,sizeof(int));
18853 +int nval_hasvalues(const char *xb, int xb_size)
18855 + return nval_used(xb, xb_size) > 0;
18857 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.h
18858 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.h 1970-01-01 02:00:00.000000000 +0200
18859 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.h 2010-10-20 13:28:16.062000294 +0300
18862 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18864 + * Copyright (C) 2002-2010 Aleph One Ltd.
18865 + * for Toby Churchill Ltd and Brightstar Engineering
18867 + * Created by Charles Manning <charles@aleph1.co.uk>
18869 + * This program is free software; you can redistribute it and/or modify
18870 + * it under the terms of the GNU Lesser General Public License version 2.1 as
18871 + * published by the Free Software Foundation.
18873 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
18875 +#ifndef __NAMEVAL_H__
18876 +#define __NAMEVAL_H__
18878 +#include "yportenv.h"
18880 +int nval_del(char *xb, int xb_size, const YCHAR *name);
18881 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
18882 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
18883 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
18884 +int nval_hasvalues(const char *xb, int xb_size);
18886 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.c
18887 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.c 2010-10-20 13:17:58.959000294 +0300
18888 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.c 2010-10-20 13:28:16.029000294 +0300
18891 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18893 - * Copyright (C) 2002-2007 Aleph One Ltd.
18894 + * Copyright (C) 2002-2010 Aleph One Ltd.
18895 * for Toby Churchill Ltd and Brightstar Engineering
18897 * Created by Charles Manning <charles@aleph1.co.uk>
18898 @@ -11,124 +11,129 @@
18899 * published by the Free Software Foundation.
18902 -const char *yaffs_nand_c_version =
18903 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
18905 #include "yaffs_nand.h"
18906 #include "yaffs_tagscompat.h"
18907 #include "yaffs_tagsvalidity.h"
18909 #include "yaffs_getblockinfo.h"
18911 -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18912 +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
18914 - yaffs_ExtendedTags *tags)
18915 + yaffs_ext_tags *tags)
18918 - yaffs_ExtendedTags localTags;
18919 + yaffs_ext_tags localTags;
18921 + int realignedChunkInNAND = nand_chunk - dev->chunk_offset;
18923 - int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
18924 + dev->n_page_reads++;
18926 /* If there are no tags provided, use local tags to get prioritised gc working */
18930 - if (dev->readChunkWithTagsFromNAND)
18931 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
18932 + if (dev->param.read_chunk_tags_fn)
18933 + result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer,
18936 - result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
18937 + result = yaffs_tags_compat_rd(dev,
18938 realignedChunkInNAND,
18942 - tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
18943 + tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
18945 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
18946 - yaffs_HandleChunkError(dev, bi);
18947 + yaffs_block_info_t *bi;
18948 + bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block);
18949 + yaffs_handle_chunk_error(dev, bi);
18955 -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
18957 +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
18959 const __u8 *buffer,
18960 - yaffs_ExtendedTags *tags)
18961 + yaffs_ext_tags *tags)
18963 - chunkInNAND -= dev->chunkOffset;
18965 + dev->n_page_writes++;
18967 + nand_chunk -= dev->chunk_offset;
18971 - tags->sequenceNumber = dev->sequenceNumber;
18972 - tags->chunkUsed = 1;
18973 - if (!yaffs_ValidateTags(tags)) {
18974 + tags->seq_number = dev->seq_number;
18975 + tags->chunk_used = 1;
18976 + if (!yaffs_validate_tags(tags)) {
18977 T(YAFFS_TRACE_ERROR,
18978 (TSTR("Writing uninitialised tags" TENDSTR)));
18981 T(YAFFS_TRACE_WRITE,
18982 - (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
18983 - tags->objectId, tags->chunkId));
18984 + (TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
18985 + tags->obj_id, tags->chunk_id));
18987 T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
18991 - if (dev->writeChunkWithTagsToNAND)
18992 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
18993 + if (dev->param.write_chunk_tags_fn)
18994 + return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
18997 - return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
18999 + return yaffs_tags_compat_wr(dev,
19005 -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
19006 +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no)
19008 - blockNo -= dev->blockOffset;
19009 + block_no -= dev->block_offset;
19013 - if (dev->markNANDBlockBad)
19014 - return dev->markNANDBlockBad(dev, blockNo);
19015 + if (dev->param.bad_block_fn)
19016 + return dev->param.bad_block_fn(dev, block_no);
19018 - return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
19019 + return yaffs_tags_compat_mark_bad(dev, block_no);
19022 -int yaffs_QueryInitialBlockState(yaffs_Device *dev,
19024 - yaffs_BlockState *state,
19025 - __u32 *sequenceNumber)
19026 +int yaffs_query_init_block_state(yaffs_dev_t *dev,
19028 + yaffs_block_state_t *state,
19029 + __u32 *seq_number)
19031 - blockNo -= dev->blockOffset;
19032 + block_no -= dev->block_offset;
19034 - if (dev->queryNANDBlock)
19035 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
19036 + if (dev->param.query_block_fn)
19037 + return dev->param.query_block_fn(dev, block_no, state, seq_number);
19039 - return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
19040 + return yaffs_tags_compat_query_block(dev, block_no,
19047 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19049 +int yaffs_erase_block(struct yaffs_dev_s *dev,
19054 - blockInNAND -= dev->blockOffset;
19055 + flash_block -= dev->block_offset;
19057 + dev->n_erasures++;
19059 - dev->nBlockErasures++;
19060 - result = dev->eraseBlockInNAND(dev, blockInNAND);
19061 + result = dev->param.erase_fn(dev, flash_block);
19066 -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
19067 +int yaffs_init_nand(struct yaffs_dev_s *dev)
19069 - return dev->initialiseNAND(dev);
19070 + if(dev->param.initialise_flash_fn)
19071 + return dev->param.initialise_flash_fn(dev);
19076 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nandemul2k.h
19077 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nandemul2k.h 2010-10-20 13:17:58.959000294 +0300
19078 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nandemul2k.h 2010-10-20 13:28:16.063000294 +0300
19081 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19083 - * Copyright (C) 2002-2007 Aleph One Ltd.
19084 + * Copyright (C) 2002-2010 Aleph One Ltd.
19085 * for Toby Churchill Ltd and Brightstar Engineering
19087 * Created by Charles Manning <charles@aleph1.co.uk>
19088 @@ -20,18 +20,18 @@
19090 #include "yaffs_guts.h"
19092 -int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
19093 - int chunkInNAND, const __u8 *data,
19094 - const yaffs_ExtendedTags *tags);
19095 -int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
19096 - int chunkInNAND, __u8 *data,
19097 - yaffs_ExtendedTags *tags);
19098 -int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
19099 -int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
19100 - yaffs_BlockState *state, __u32 *sequenceNumber);
19101 -int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19102 - int blockInNAND);
19103 -int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
19104 +int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev,
19105 + int nand_chunk, const __u8 *data,
19106 + const yaffs_ext_tags *tags);
19107 +int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev,
19108 + int nand_chunk, __u8 *data,
19109 + yaffs_ext_tags *tags);
19110 +int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
19111 +int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
19112 + yaffs_block_state_t *state, __u32 *seq_number);
19113 +int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev,
19114 + int flash_block);
19115 +int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev);
19116 int nandemul2k_GetBytesPerChunk(void);
19117 int nandemul2k_GetChunksPerBlock(void);
19118 int nandemul2k_GetNumberOfBlocks(void);
19119 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.h
19120 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.h 2010-10-20 13:17:58.959000294 +0300
19121 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.h 2010-10-20 13:28:16.063000294 +0300
19124 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19126 - * Copyright (C) 2002-2007 Aleph One Ltd.
19127 + * Copyright (C) 2002-2010 Aleph One Ltd.
19128 * for Toby Churchill Ltd and Brightstar Engineering
19130 * Created by Charles Manning <charles@aleph1.co.uk>
19131 @@ -19,26 +19,26 @@
19135 -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
19136 +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
19138 - yaffs_ExtendedTags *tags);
19139 + yaffs_ext_tags *tags);
19141 -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
19143 +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
19145 const __u8 *buffer,
19146 - yaffs_ExtendedTags *tags);
19147 + yaffs_ext_tags *tags);
19149 -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
19150 +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no);
19152 -int yaffs_QueryInitialBlockState(yaffs_Device *dev,
19154 - yaffs_BlockState *state,
19155 - unsigned *sequenceNumber);
19156 +int yaffs_query_init_block_state(yaffs_dev_t *dev,
19158 + yaffs_block_state_t *state,
19159 + unsigned *seq_number);
19161 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19162 - int blockInNAND);
19163 +int yaffs_erase_block(struct yaffs_dev_s *dev,
19164 + int flash_block);
19166 -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
19167 +int yaffs_init_nand(struct yaffs_dev_s *dev);
19171 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.c
19172 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.c 2010-10-20 13:17:58.959000294 +0300
19173 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.c 2010-10-20 13:28:16.029000294 +0300
19176 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19178 - * Copyright (C) 2002-2007 Aleph One Ltd.
19179 + * Copyright (C) 2002-2010 Aleph One Ltd.
19180 * for Toby Churchill Ltd and Brightstar Engineering
19182 * Created by Charles Manning <charles@aleph1.co.uk>
19183 @@ -14,37 +14,37 @@
19184 #include "yaffs_packedtags1.h"
19185 #include "yportenv.h"
19187 -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
19188 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t)
19190 - pt->chunkId = t->chunkId;
19191 - pt->serialNumber = t->serialNumber;
19192 - pt->byteCount = t->byteCount;
19193 - pt->objectId = t->objectId;
19194 + pt->chunk_id = t->chunk_id;
19195 + pt->serial_number = t->serial_number;
19196 + pt->n_bytes = t->n_bytes;
19197 + pt->obj_id = t->obj_id;
19199 - pt->deleted = (t->chunkDeleted) ? 0 : 1;
19200 + pt->deleted = (t->is_deleted) ? 0 : 1;
19201 pt->unusedStuff = 0;
19202 pt->shouldBeFF = 0xFFFFFFFF;
19206 -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
19207 +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt)
19209 static const __u8 allFF[] =
19210 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
19213 if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
19215 + t->block_bad = 0;
19216 if (pt->shouldBeFF != 0xFFFFFFFF)
19218 - t->chunkUsed = 1;
19219 - t->objectId = pt->objectId;
19220 - t->chunkId = pt->chunkId;
19221 - t->byteCount = pt->byteCount;
19222 - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19223 - t->chunkDeleted = (pt->deleted) ? 0 : 1;
19224 - t->serialNumber = pt->serialNumber;
19225 + t->block_bad = 1;
19226 + t->chunk_used = 1;
19227 + t->obj_id = pt->obj_id;
19228 + t->chunk_id = pt->chunk_id;
19229 + t->n_bytes = pt->n_bytes;
19230 + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19231 + t->is_deleted = (pt->deleted) ? 0 : 1;
19232 + t->serial_number = pt->serial_number;
19234 - memset(t, 0, sizeof(yaffs_ExtendedTags));
19235 + memset(t, 0, sizeof(yaffs_ext_tags));
19238 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.h
19239 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.h 2010-10-20 13:17:58.960000294 +0300
19240 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.h 2010-10-20 13:28:16.063000294 +0300
19243 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19245 - * Copyright (C) 2002-2007 Aleph One Ltd.
19246 + * Copyright (C) 2002-2010 Aleph One Ltd.
19247 * for Toby Churchill Ltd and Brightstar Engineering
19249 * Created by Charles Manning <charles@aleph1.co.uk>
19250 @@ -21,10 +21,10 @@
19251 #include "yaffs_guts.h"
19254 - unsigned chunkId:20;
19255 - unsigned serialNumber:2;
19256 - unsigned byteCount:10;
19257 - unsigned objectId:18;
19258 + unsigned chunk_id:20;
19259 + unsigned serial_number:2;
19260 + unsigned n_bytes:10;
19261 + unsigned obj_id:18;
19263 unsigned deleted:1;
19264 unsigned unusedStuff:1;
19265 @@ -32,6 +32,6 @@ typedef struct {
19267 } yaffs_PackedTags1;
19269 -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
19270 -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
19271 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t);
19272 +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt);
19274 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.c
19275 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.c 2010-10-20 13:17:58.960000294 +0300
19276 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.c 2010-10-20 13:28:16.029000294 +0300
19279 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19281 - * Copyright (C) 2002-2007 Aleph One Ltd.
19282 + * Copyright (C) 2002-2010 Aleph One Ltd.
19283 * for Toby Churchill Ltd and Brightstar Engineering
19285 * Created by Charles Manning <charles@aleph1.co.uk>
19288 #include "yaffs_packedtags2.h"
19289 #include "yportenv.h"
19290 +#include "yaffs_trace.h"
19291 #include "yaffs_tagsvalidity.h"
19293 /* This code packs a set of extended tags into a binary structure for
19295 * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
19298 -/* Extra flags applied to chunkId */
19299 +/* Extra flags applied to chunk_id */
19301 #define EXTRA_HEADER_INFO_FLAG 0x80000000
19302 #define EXTRA_SHRINK_FLAG 0x40000000
19303 @@ -42,53 +43,53 @@ static void yaffs_DumpPackedTags2TagsPar
19306 (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
19307 - ptt->objectId, ptt->chunkId, ptt->byteCount,
19308 - ptt->sequenceNumber));
19309 + ptt->obj_id, ptt->chunk_id, ptt->n_bytes,
19310 + ptt->seq_number));
19312 static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
19314 yaffs_DumpPackedTags2TagsPart(&pt->t);
19317 -static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
19318 +static void yaffs_DumpTags2(const yaffs_ext_tags *t)
19322 ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
19323 - TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
19324 - t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
19325 - t->sequenceNumber));
19326 + TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
19327 + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
19332 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
19333 - const yaffs_ExtendedTags *t)
19334 + const yaffs_ext_tags *t)
19336 - ptt->chunkId = t->chunkId;
19337 - ptt->sequenceNumber = t->sequenceNumber;
19338 - ptt->byteCount = t->byteCount;
19339 - ptt->objectId = t->objectId;
19340 + ptt->chunk_id = t->chunk_id;
19341 + ptt->seq_number = t->seq_number;
19342 + ptt->n_bytes = t->n_bytes;
19343 + ptt->obj_id = t->obj_id;
19345 - if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
19346 + if (t->chunk_id == 0 && t->extra_available) {
19347 /* Store the extra header info instead */
19348 - /* We save the parent object in the chunkId */
19349 - ptt->chunkId = EXTRA_HEADER_INFO_FLAG
19350 - | t->extraParentObjectId;
19351 - if (t->extraIsShrinkHeader)
19352 - ptt->chunkId |= EXTRA_SHRINK_FLAG;
19353 - if (t->extraShadows)
19354 - ptt->chunkId |= EXTRA_SHADOWS_FLAG;
19356 - ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
19358 - (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
19360 - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
19361 - ptt->byteCount = t->extraEquivalentObjectId;
19362 - else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
19363 - ptt->byteCount = t->extraFileLength;
19364 + /* We save the parent object in the chunk_id */
19365 + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG
19366 + | t->extra_parent_id;
19367 + if (t->extra_is_shrink)
19368 + ptt->chunk_id |= EXTRA_SHRINK_FLAG;
19369 + if (t->extra_shadows)
19370 + ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
19372 + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
19374 + (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
19376 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
19377 + ptt->n_bytes = t->extra_equiv_id;
19378 + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
19379 + ptt->n_bytes = t->extra_length;
19381 - ptt->byteCount = 0;
19382 + ptt->n_bytes = 0;
19385 yaffs_DumpPackedTags2TagsPart(ptt);
19386 @@ -96,59 +97,56 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
19390 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
19391 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC)
19393 yaffs_PackTags2TagsPart(&pt->t, t);
19395 -#ifndef YAFFS_IGNORE_TAGS_ECC
19397 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
19399 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
19400 sizeof(yaffs_PackedTags2TagsPart),
19407 -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
19408 +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t,
19409 yaffs_PackedTags2TagsPart *ptt)
19412 - memset(t, 0, sizeof(yaffs_ExtendedTags));
19413 + memset(t, 0, sizeof(yaffs_ext_tags));
19415 - yaffs_InitialiseTags(t);
19416 + yaffs_init_tags(t);
19418 - if (ptt->sequenceNumber != 0xFFFFFFFF) {
19420 - t->chunkUsed = 1;
19421 - t->objectId = ptt->objectId;
19422 - t->chunkId = ptt->chunkId;
19423 - t->byteCount = ptt->byteCount;
19424 - t->chunkDeleted = 0;
19425 - t->serialNumber = 0;
19426 - t->sequenceNumber = ptt->sequenceNumber;
19427 + if (ptt->seq_number != 0xFFFFFFFF) {
19428 + t->block_bad = 0;
19429 + t->chunk_used = 1;
19430 + t->obj_id = ptt->obj_id;
19431 + t->chunk_id = ptt->chunk_id;
19432 + t->n_bytes = ptt->n_bytes;
19433 + t->is_deleted = 0;
19434 + t->serial_number = 0;
19435 + t->seq_number = ptt->seq_number;
19437 /* Do extra header info stuff */
19439 - if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
19441 - t->byteCount = 0;
19443 - t->extraHeaderInfoAvailable = 1;
19444 - t->extraParentObjectId =
19445 - ptt->chunkId & (~(ALL_EXTRA_FLAGS));
19446 - t->extraIsShrinkHeader =
19447 - (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
19448 - t->extraShadows =
19449 - (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
19450 - t->extraObjectType =
19451 - ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
19452 - t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
19453 + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
19457 + t->extra_available = 1;
19458 + t->extra_parent_id =
19459 + ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
19460 + t->extra_is_shrink =
19461 + (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
19462 + t->extra_shadows =
19463 + (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
19464 + t->extra_obj_type =
19465 + ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
19466 + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
19468 - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
19469 - t->extraEquivalentObjectId = ptt->byteCount;
19470 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
19471 + t->extra_equiv_id = ptt->n_bytes;
19473 - t->extraFileLength = ptt->byteCount;
19474 + t->extra_length = ptt->n_bytes;
19478 @@ -158,49 +156,43 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
19482 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
19483 +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC)
19486 - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19487 + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19489 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
19490 - /* Page is in use */
19491 -#ifndef YAFFS_IGNORE_TAGS_ECC
19493 - yaffs_ECCOther ecc;
19495 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
19497 - (yaffs_PackedTags2TagsPart),
19500 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
19502 - (yaffs_PackedTags2TagsPart),
19504 - switch (result) {
19505 + if (pt->t.seq_number != 0xFFFFFFFF &&
19507 + /* Chunk is in use and we need to do ECC */
19509 + yaffs_ECCOther ecc;
19511 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
19512 + sizeof(yaffs_PackedTags2TagsPart),
19514 + result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
19515 + sizeof(yaffs_PackedTags2TagsPart),
19517 + switch (result) {
19519 - eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19520 + ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19523 - eccResult = YAFFS_ECC_RESULT_FIXED;
19524 + ecc_result = YAFFS_ECC_RESULT_FIXED;
19527 - eccResult = YAFFS_ECC_RESULT_UNFIXED;
19528 + ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19531 - eccResult = YAFFS_ECC_RESULT_UNKNOWN;
19533 + ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
19538 - yaffs_UnpackTags2TagsPart(t, &pt->t);
19539 + yaffs_unpack_tags2tags_part(t, &pt->t);
19541 - t->eccResult = eccResult;
19542 + t->ecc_result = ecc_result;
19544 yaffs_DumpPackedTags2(pt);
19545 yaffs_DumpTags2(t);
19549 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.h
19550 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.h 2010-10-20 13:17:58.960000294 +0300
19551 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.h 2010-10-20 13:28:16.063000294 +0300
19554 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19556 - * Copyright (C) 2002-2007 Aleph One Ltd.
19557 + * Copyright (C) 2002-2010 Aleph One Ltd.
19558 * for Toby Churchill Ltd and Brightstar Engineering
19560 * Created by Charles Manning <charles@aleph1.co.uk>
19561 @@ -22,10 +22,10 @@
19562 #include "yaffs_ecc.h"
19565 - unsigned sequenceNumber;
19566 - unsigned objectId;
19567 - unsigned chunkId;
19568 - unsigned byteCount;
19569 + unsigned seq_number;
19571 + unsigned chunk_id;
19572 + unsigned n_bytes;
19573 } yaffs_PackedTags2TagsPart;
19576 @@ -34,10 +34,10 @@ typedef struct {
19577 } yaffs_PackedTags2;
19579 /* Full packed tags with ECC, used for oob tags */
19580 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
19581 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
19582 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC);
19583 +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC);
19585 /* Only the tags part (no ECC for use with inband tags */
19586 -void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
19587 -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
19588 +void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t);
19589 +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt);
19591 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_qsort.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_qsort.h
19592 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_qsort.h 2010-10-20 13:17:58.961000294 +0300
19593 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_qsort.h 2010-10-20 13:28:16.063000294 +0300
19596 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19598 - * Copyright (C) 2002-2007 Aleph One Ltd.
19599 + * Copyright (C) 2002-2010 Aleph One Ltd.
19600 * for Toby Churchill Ltd and Brightstar Engineering
19602 * Created by Charles Manning <charles@aleph1.co.uk>
19604 #ifndef __YAFFS_QSORT_H__
19605 #define __YAFFS_QSORT_H__
19608 +#include <linux/sort.h>
19610 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
19611 + int (*cmp)(const void *, const void *)){
19612 + sort(base, total_elems, size, cmp, NULL);
19617 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
19618 int (*cmp)(const void *, const void *));
19622 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.c
19623 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.c 2010-10-20 13:17:58.961000294 +0300
19624 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.c 2010-10-20 13:28:16.030000294 +0300
19627 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19629 - * Copyright (C) 2002-2007 Aleph One Ltd.
19630 + * Copyright (C) 2002-2010 Aleph One Ltd.
19631 * for Toby Churchill Ltd and Brightstar Engineering
19633 * Created by Charles Manning <charles@aleph1.co.uk>
19634 @@ -15,19 +15,20 @@
19635 #include "yaffs_tagscompat.h"
19636 #include "yaffs_ecc.h"
19637 #include "yaffs_getblockinfo.h"
19638 +#include "yaffs_trace.h"
19640 -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
19641 +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk);
19643 -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
19644 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
19645 +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk);
19646 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
19648 - const yaffs_Spare *spare);
19649 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
19650 - const yaffs_Spare *spare);
19651 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
19652 + const yaffs_spare *spare);
19653 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
19654 + const yaffs_spare *spare);
19655 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk);
19658 -static const char yaffs_countBitsTable[256] = {
19659 +static const char yaffs_count_bits_table[256] = {
19660 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
19661 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
19662 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
19663 @@ -46,26 +47,26 @@ static const char yaffs_countBitsTable[2
19664 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
19667 -int yaffs_CountBits(__u8 x)
19668 +int yaffs_count_bits(__u8 x)
19671 - retVal = yaffs_countBitsTable[x];
19672 + retVal = yaffs_count_bits_table[x];
19676 /********** Tags ECC calculations *********/
19678 -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
19679 +void yaffs_calc_ecc(const __u8 *data, yaffs_spare *spare)
19681 - yaffs_ECCCalculate(data, spare->ecc1);
19682 - yaffs_ECCCalculate(&data[256], spare->ecc2);
19683 + yaffs_ecc_cacl(data, spare->ecc1);
19684 + yaffs_ecc_cacl(&data[256], spare->ecc2);
19687 -void yaffs_CalcTagsECC(yaffs_Tags *tags)
19688 +void yaffs_calc_tags_ecc(yaffs_tags_t *tags)
19690 /* Calculate an ecc */
19692 - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
19693 + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
19697 @@ -84,24 +85,24 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
19701 -int yaffs_CheckECCOnTags(yaffs_Tags *tags)
19702 +int yaffs_check_tags_ecc(yaffs_tags_t *tags)
19704 unsigned ecc = tags->ecc;
19706 - yaffs_CalcTagsECC(tags);
19707 + yaffs_calc_tags_ecc(tags);
19711 if (ecc && ecc <= 64) {
19712 /* TODO: Handle the failure better. Retire? */
19713 - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
19714 + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
19718 b[ecc / 8] ^= (1 << (ecc & 7));
19720 /* Now recvalc the ecc */
19721 - yaffs_CalcTagsECC(tags);
19722 + yaffs_calc_tags_ecc(tags);
19724 return 1; /* recovered error */
19726 @@ -115,76 +116,73 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tag
19728 /********** Tags **********/
19730 -static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
19731 - yaffs_Tags *tagsPtr)
19732 +static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr,
19733 + yaffs_tags_t *tagsPtr)
19735 - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
19736 + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
19738 - yaffs_CalcTagsECC(tagsPtr);
19739 + yaffs_calc_tags_ecc(tagsPtr);
19741 - sparePtr->tagByte0 = tu->asBytes[0];
19742 - sparePtr->tagByte1 = tu->asBytes[1];
19743 - sparePtr->tagByte2 = tu->asBytes[2];
19744 - sparePtr->tagByte3 = tu->asBytes[3];
19745 - sparePtr->tagByte4 = tu->asBytes[4];
19746 - sparePtr->tagByte5 = tu->asBytes[5];
19747 - sparePtr->tagByte6 = tu->asBytes[6];
19748 - sparePtr->tagByte7 = tu->asBytes[7];
19749 + sparePtr->tb0 = tu->as_bytes[0];
19750 + sparePtr->tb1 = tu->as_bytes[1];
19751 + sparePtr->tb2 = tu->as_bytes[2];
19752 + sparePtr->tb3 = tu->as_bytes[3];
19753 + sparePtr->tb4 = tu->as_bytes[4];
19754 + sparePtr->tb5 = tu->as_bytes[5];
19755 + sparePtr->tb6 = tu->as_bytes[6];
19756 + sparePtr->tb7 = tu->as_bytes[7];
19759 -static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
19760 - yaffs_Tags *tagsPtr)
19761 +static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr,
19762 + yaffs_tags_t *tagsPtr)
19764 - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
19765 + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
19768 - tu->asBytes[0] = sparePtr->tagByte0;
19769 - tu->asBytes[1] = sparePtr->tagByte1;
19770 - tu->asBytes[2] = sparePtr->tagByte2;
19771 - tu->asBytes[3] = sparePtr->tagByte3;
19772 - tu->asBytes[4] = sparePtr->tagByte4;
19773 - tu->asBytes[5] = sparePtr->tagByte5;
19774 - tu->asBytes[6] = sparePtr->tagByte6;
19775 - tu->asBytes[7] = sparePtr->tagByte7;
19776 + tu->as_bytes[0] = sparePtr->tb0;
19777 + tu->as_bytes[1] = sparePtr->tb1;
19778 + tu->as_bytes[2] = sparePtr->tb2;
19779 + tu->as_bytes[3] = sparePtr->tb3;
19780 + tu->as_bytes[4] = sparePtr->tb4;
19781 + tu->as_bytes[5] = sparePtr->tb5;
19782 + tu->as_bytes[6] = sparePtr->tb6;
19783 + tu->as_bytes[7] = sparePtr->tb7;
19785 - result = yaffs_CheckECCOnTags(tagsPtr);
19786 + result = yaffs_check_tags_ecc(tagsPtr);
19788 - dev->tagsEccFixed++;
19789 + dev->n_tags_ecc_fixed++;
19790 else if (result < 0)
19791 - dev->tagsEccUnfixed++;
19792 + dev->n_tags_ecc_unfixed++;
19795 -static void yaffs_SpareInitialise(yaffs_Spare *spare)
19796 +static void yaffs_spare_init(yaffs_spare *spare)
19798 - memset(spare, 0xFF, sizeof(yaffs_Spare));
19799 + memset(spare, 0xFF, sizeof(yaffs_spare));
19802 -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
19803 - int chunkInNAND, const __u8 *data,
19804 - yaffs_Spare *spare)
19805 +static int yaffs_wr_nand(struct yaffs_dev_s *dev,
19806 + int nand_chunk, const __u8 *data,
19807 + yaffs_spare *spare)
19809 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
19810 + if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
19811 T(YAFFS_TRACE_ERROR,
19812 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
19818 - dev->nPageWrites++;
19819 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
19820 + return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
19823 -static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
19825 +static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev,
19828 - yaffs_Spare *spare,
19829 - yaffs_ECCResult *eccResult,
19830 + yaffs_spare *spare,
19831 + yaffs_ecc_result *ecc_result,
19832 int doErrorCorrection)
19835 - yaffs_Spare localSpare;
19837 - dev->nPageReads++;
19838 + yaffs_spare localSpare;
19840 if (!spare && data) {
19841 /* If we don't have a real spare, then we use a local one. */
19842 @@ -192,107 +190,107 @@ static int yaffs_ReadChunkFromNAND(struc
19843 spare = &localSpare;
19846 - if (!dev->useNANDECC) {
19847 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
19848 + if (!dev->param.use_nand_ecc) {
19849 + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
19850 if (data && doErrorCorrection) {
19851 /* Do ECC correction */
19852 /* Todo handle any errors */
19853 - int eccResult1, eccResult2;
19854 + int ecc_result1, ecc_result2;
19857 - yaffs_ECCCalculate(data, calcEcc);
19859 - yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
19860 - yaffs_ECCCalculate(&data[256], calcEcc);
19862 - yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
19863 + yaffs_ecc_cacl(data, calcEcc);
19865 + yaffs_ecc_correct(data, spare->ecc1, calcEcc);
19866 + yaffs_ecc_cacl(&data[256], calcEcc);
19868 + yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc);
19870 - if (eccResult1 > 0) {
19871 + if (ecc_result1 > 0) {
19872 T(YAFFS_TRACE_ERROR,
19874 ("**>>yaffs ecc error fix performed on chunk %d:0"
19875 - TENDSTR), chunkInNAND));
19877 - } else if (eccResult1 < 0) {
19878 + TENDSTR), nand_chunk));
19879 + dev->n_ecc_fixed++;
19880 + } else if (ecc_result1 < 0) {
19881 T(YAFFS_TRACE_ERROR,
19883 ("**>>yaffs ecc error unfixed on chunk %d:0"
19884 - TENDSTR), chunkInNAND));
19885 - dev->eccUnfixed++;
19886 + TENDSTR), nand_chunk));
19887 + dev->n_ecc_unfixed++;
19890 - if (eccResult2 > 0) {
19891 + if (ecc_result2 > 0) {
19892 T(YAFFS_TRACE_ERROR,
19894 ("**>>yaffs ecc error fix performed on chunk %d:1"
19895 - TENDSTR), chunkInNAND));
19897 - } else if (eccResult2 < 0) {
19898 + TENDSTR), nand_chunk));
19899 + dev->n_ecc_fixed++;
19900 + } else if (ecc_result2 < 0) {
19901 T(YAFFS_TRACE_ERROR,
19903 ("**>>yaffs ecc error unfixed on chunk %d:1"
19904 - TENDSTR), chunkInNAND));
19905 - dev->eccUnfixed++;
19906 + TENDSTR), nand_chunk));
19907 + dev->n_ecc_unfixed++;
19910 - if (eccResult1 || eccResult2) {
19911 + if (ecc_result1 || ecc_result2) {
19912 /* We had a data problem on this page */
19913 - yaffs_HandleReadDataError(dev, chunkInNAND);
19914 + yaffs_handle_rd_data_error(dev, nand_chunk);
19917 - if (eccResult1 < 0 || eccResult2 < 0)
19918 - *eccResult = YAFFS_ECC_RESULT_UNFIXED;
19919 - else if (eccResult1 > 0 || eccResult2 > 0)
19920 - *eccResult = YAFFS_ECC_RESULT_FIXED;
19921 + if (ecc_result1 < 0 || ecc_result2 < 0)
19922 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19923 + else if (ecc_result1 > 0 || ecc_result2 > 0)
19924 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
19926 - *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19927 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19930 /* Must allocate enough memory for spare+2*sizeof(int) */
19931 /* for ecc results from device. */
19932 - struct yaffs_NANDSpare nspare;
19933 + struct yaffs_nand_spare nspare;
19935 memset(&nspare, 0, sizeof(nspare));
19937 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
19938 - (yaffs_Spare *) &nspare);
19939 - memcpy(spare, &nspare, sizeof(yaffs_Spare));
19940 + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data,
19941 + (yaffs_spare *) &nspare);
19942 + memcpy(spare, &nspare, sizeof(yaffs_spare));
19943 if (data && doErrorCorrection) {
19944 if (nspare.eccres1 > 0) {
19945 T(YAFFS_TRACE_ERROR,
19947 ("**>>mtd ecc error fix performed on chunk %d:0"
19948 - TENDSTR), chunkInNAND));
19949 + TENDSTR), nand_chunk));
19950 } else if (nspare.eccres1 < 0) {
19951 T(YAFFS_TRACE_ERROR,
19953 ("**>>mtd ecc error unfixed on chunk %d:0"
19954 - TENDSTR), chunkInNAND));
19955 + TENDSTR), nand_chunk));
19958 if (nspare.eccres2 > 0) {
19959 T(YAFFS_TRACE_ERROR,
19961 ("**>>mtd ecc error fix performed on chunk %d:1"
19962 - TENDSTR), chunkInNAND));
19963 + TENDSTR), nand_chunk));
19964 } else if (nspare.eccres2 < 0) {
19965 T(YAFFS_TRACE_ERROR,
19967 ("**>>mtd ecc error unfixed on chunk %d:1"
19968 - TENDSTR), chunkInNAND));
19969 + TENDSTR), nand_chunk));
19972 if (nspare.eccres1 || nspare.eccres2) {
19973 /* We had a data problem on this page */
19974 - yaffs_HandleReadDataError(dev, chunkInNAND);
19975 + yaffs_handle_rd_data_error(dev, nand_chunk);
19978 if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
19979 - *eccResult = YAFFS_ECC_RESULT_UNFIXED;
19980 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19981 else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
19982 - *eccResult = YAFFS_ECC_RESULT_FIXED;
19983 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
19985 - *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19986 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19990 @@ -300,17 +298,17 @@ static int yaffs_ReadChunkFromNAND(struc
19994 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
19996 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
20000 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
20001 static __u8 data[YAFFS_BYTES_PER_CHUNK];
20002 /* Might as well always allocate the larger size for */
20003 - /* dev->useNANDECC == true; */
20004 - static __u8 spare[sizeof(struct yaffs_NANDSpare)];
20005 + /* dev->param.use_nand_ecc == true; */
20006 + static __u8 spare[sizeof(struct yaffs_nand_spare)];
20008 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
20009 + dev->param.read_chunk_fn(dev, nand_chunk, data, (yaffs_spare *) spare);
20012 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
20013 @@ -331,14 +329,14 @@ static int yaffs_CheckChunkErased(struct
20014 * Functions for robustisizing
20017 -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
20018 +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk)
20020 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
20021 + int flash_block = nand_chunk / dev->param.chunks_per_block;
20023 /* Mark the block for retirement */
20024 - yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
20025 + yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1;
20026 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
20027 - (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
20028 + (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
20031 * Just do a garbage collection on the affected block
20032 @@ -348,44 +346,44 @@ static void yaffs_HandleReadDataError(ya
20036 -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
20037 +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk)
20041 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
20042 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
20044 - const yaffs_Spare *spare)
20045 + const yaffs_spare *spare)
20049 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
20050 - const yaffs_Spare *spare)
20051 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
20052 + const yaffs_spare *spare)
20056 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
20057 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk)
20059 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
20060 + int flash_block = nand_chunk / dev->param.chunks_per_block;
20062 /* Mark the block for retirement */
20063 - yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
20064 + yaffs_get_block_info(dev, flash_block)->needs_retiring = 1;
20065 /* Delete the chunk */
20066 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
20067 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
20070 -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
20071 - const yaffs_Spare *s0, const yaffs_Spare *s1)
20072 +static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1,
20073 + const yaffs_spare *s0, const yaffs_spare *s1)
20076 if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
20077 - s0->tagByte0 != s1->tagByte0 ||
20078 - s0->tagByte1 != s1->tagByte1 ||
20079 - s0->tagByte2 != s1->tagByte2 ||
20080 - s0->tagByte3 != s1->tagByte3 ||
20081 - s0->tagByte4 != s1->tagByte4 ||
20082 - s0->tagByte5 != s1->tagByte5 ||
20083 - s0->tagByte6 != s1->tagByte6 ||
20084 - s0->tagByte7 != s1->tagByte7 ||
20085 + s0->tb0 != s1->tb0 ||
20086 + s0->tb1 != s1->tb1 ||
20087 + s0->tb2 != s1->tb2 ||
20088 + s0->tb3 != s1->tb3 ||
20089 + s0->tb4 != s1->tb4 ||
20090 + s0->tb5 != s1->tb5 ||
20091 + s0->tb6 != s1->tb6 ||
20092 + s0->tb7 != s1->tb7 ||
20093 s0->ecc1[0] != s1->ecc1[0] ||
20094 s0->ecc1[1] != s1->ecc1[1] ||
20095 s0->ecc1[2] != s1->ecc1[2] ||
20096 @@ -398,53 +396,53 @@ static int yaffs_VerifyCompare(const __u
20098 #endif /* NOTYET */
20100 -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
20102 +int yaffs_tags_compat_wr(yaffs_dev_t *dev,
20105 - const yaffs_ExtendedTags *eTags)
20106 + const yaffs_ext_tags *eTags)
20108 - yaffs_Spare spare;
20110 + yaffs_spare spare;
20111 + yaffs_tags_t tags;
20113 - yaffs_SpareInitialise(&spare);
20114 + yaffs_spare_init(&spare);
20116 - if (eTags->chunkDeleted)
20117 - spare.pageStatus = 0;
20118 + if (eTags->is_deleted)
20119 + spare.page_status = 0;
20121 - tags.objectId = eTags->objectId;
20122 - tags.chunkId = eTags->chunkId;
20123 + tags.obj_id = eTags->obj_id;
20124 + tags.chunk_id = eTags->chunk_id;
20126 - tags.byteCountLSB = eTags->byteCount & 0x3ff;
20127 + tags.n_bytes_lsb = eTags->n_bytes & 0x3ff;
20129 - if (dev->nDataBytesPerChunk >= 1024)
20130 - tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
20131 + if (dev->data_bytes_per_chunk >= 1024)
20132 + tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3;
20134 - tags.byteCountMSB = 3;
20135 + tags.n_bytes_msb = 3;
20138 - tags.serialNumber = eTags->serialNumber;
20139 + tags.serial_number = eTags->serial_number;
20141 - if (!dev->useNANDECC && data)
20142 - yaffs_CalcECC(data, &spare);
20143 + if (!dev->param.use_nand_ecc && data)
20144 + yaffs_calc_ecc(data, &spare);
20146 - yaffs_LoadTagsIntoSpare(&spare, &tags);
20147 + yaffs_load_tags_to_spare(&spare, &tags);
20151 - return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
20152 + return yaffs_wr_nand(dev, nand_chunk, data, &spare);
20155 -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
20157 +int yaffs_tags_compat_rd(yaffs_dev_t *dev,
20160 - yaffs_ExtendedTags *eTags)
20161 + yaffs_ext_tags *eTags)
20164 - yaffs_Spare spare;
20166 - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
20167 + yaffs_spare spare;
20168 + yaffs_tags_t tags;
20169 + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
20171 - static yaffs_Spare spareFF;
20172 + static yaffs_spare spareFF;
20176 @@ -452,33 +450,33 @@ int yaffs_TagsCompatabilityReadChunkWith
20180 - if (yaffs_ReadChunkFromNAND
20181 - (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
20182 + if (yaffs_rd_chunk_nand
20183 + (dev, nand_chunk, data, &spare, &ecc_result, 1)) {
20184 /* eTags may be NULL */
20188 - (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
20189 + (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
20191 - eTags->chunkDeleted = deleted;
20192 - eTags->eccResult = eccResult;
20193 - eTags->blockBad = 0; /* We're reading it */
20194 + eTags->is_deleted = deleted;
20195 + eTags->ecc_result = ecc_result;
20196 + eTags->block_bad = 0; /* We're reading it */
20197 /* therefore it is not a bad block */
20198 - eTags->chunkUsed =
20199 + eTags->chunk_used =
20200 (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
20203 - if (eTags->chunkUsed) {
20204 - yaffs_GetTagsFromSpare(dev, &spare, &tags);
20205 + if (eTags->chunk_used) {
20206 + yaffs_get_tags_from_spare(dev, &spare, &tags);
20208 - eTags->objectId = tags.objectId;
20209 - eTags->chunkId = tags.chunkId;
20210 - eTags->byteCount = tags.byteCountLSB;
20211 + eTags->obj_id = tags.obj_id;
20212 + eTags->chunk_id = tags.chunk_id;
20213 + eTags->n_bytes = tags.n_bytes_lsb;
20215 - if (dev->nDataBytesPerChunk >= 1024)
20216 - eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
20217 + if (dev->data_bytes_per_chunk >= 1024)
20218 + eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10);
20220 - eTags->serialNumber = tags.serialNumber;
20221 + eTags->serial_number = tags.serial_number;
20225 @@ -488,49 +486,49 @@ int yaffs_TagsCompatabilityReadChunkWith
20229 -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
20231 +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
20235 - yaffs_Spare spare;
20236 + yaffs_spare spare;
20238 - memset(&spare, 0xff, sizeof(yaffs_Spare));
20239 + memset(&spare, 0xff, sizeof(yaffs_spare));
20241 - spare.blockStatus = 'Y';
20242 + spare.block_status = 'Y';
20244 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
20245 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
20247 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
20248 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
20255 -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
20257 - yaffs_BlockState *state,
20258 - __u32 *sequenceNumber)
20259 +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
20261 + yaffs_block_state_t *state,
20262 + __u32 *seq_number)
20265 - yaffs_Spare spare0, spare1;
20266 - static yaffs_Spare spareFF;
20267 + yaffs_spare spare0, spare1;
20268 + static yaffs_spare spareFF;
20270 - yaffs_ECCResult dummy;
20271 + yaffs_ecc_result dummy;
20274 memset(&spareFF, 0xFF, sizeof(spareFF));
20278 - *sequenceNumber = 0;
20281 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
20282 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
20283 &spare0, &dummy, 1);
20284 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
20285 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL,
20286 &spare1, &dummy, 1);
20288 - if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
20289 + if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7)
20290 *state = YAFFS_BLOCK_STATE_DEAD;
20291 else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
20292 *state = YAFFS_BLOCK_STATE_EMPTY;
20293 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.h
20294 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.h 2010-10-20 13:17:58.961000294 +0300
20295 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.h 2010-10-20 13:28:16.064000294 +0300
20298 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20300 - * Copyright (C) 2002-2007 Aleph One Ltd.
20301 + * Copyright (C) 2002-2010 Aleph One Ltd.
20302 * for Toby Churchill Ltd and Brightstar Engineering
20304 * Created by Charles Manning <charles@aleph1.co.uk>
20305 @@ -17,23 +17,23 @@
20306 #define __YAFFS_TAGSCOMPAT_H__
20308 #include "yaffs_guts.h"
20309 -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
20311 +int yaffs_tags_compat_wr(yaffs_dev_t *dev,
20314 - const yaffs_ExtendedTags *tags);
20315 -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
20317 + const yaffs_ext_tags *tags);
20318 +int yaffs_tags_compat_rd(yaffs_dev_t *dev,
20321 - yaffs_ExtendedTags *tags);
20322 -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
20324 -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
20326 - yaffs_BlockState *state,
20327 - __u32 *sequenceNumber);
20328 + yaffs_ext_tags *tags);
20329 +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
20331 +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
20333 + yaffs_block_state_t *state,
20334 + __u32 *seq_number);
20336 -void yaffs_CalcTagsECC(yaffs_Tags *tags);
20337 -int yaffs_CheckECCOnTags(yaffs_Tags *tags);
20338 -int yaffs_CountBits(__u8 byte);
20339 +void yaffs_calc_tags_ecc(yaffs_tags_t *tags);
20340 +int yaffs_check_tags_ecc(yaffs_tags_t *tags);
20341 +int yaffs_count_bits(__u8 byte);
20344 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.c
20345 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-20 13:17:58.962000294 +0300
20346 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-20 13:28:16.030000294 +0300
20349 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
20351 - * Copyright (C) 2002-2007 Aleph One Ltd.
20352 + * Copyright (C) 2002-2010 Aleph One Ltd.
20353 * for Toby Churchill Ltd and Brightstar Engineering
20355 * Created by Charles Manning <charles@aleph1.co.uk>
20356 @@ -13,16 +13,16 @@
20358 #include "yaffs_tagsvalidity.h"
20360 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
20361 +void yaffs_init_tags(yaffs_ext_tags *tags)
20363 - memset(tags, 0, sizeof(yaffs_ExtendedTags));
20364 - tags->validMarker0 = 0xAAAAAAAA;
20365 - tags->validMarker1 = 0x55555555;
20366 + memset(tags, 0, sizeof(yaffs_ext_tags));
20367 + tags->validity1 = 0xAAAAAAAA;
20368 + tags->validty1 = 0x55555555;
20371 -int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
20372 +int yaffs_validate_tags(yaffs_ext_tags *tags)
20374 - return (tags->validMarker0 == 0xAAAAAAAA &&
20375 - tags->validMarker1 == 0x55555555);
20376 + return (tags->validity1 == 0xAAAAAAAA &&
20377 + tags->validty1 == 0x55555555);
20380 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.h
20381 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-20 13:17:58.962000294 +0300
20382 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-20 13:28:16.064000294 +0300
20385 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20387 - * Copyright (C) 2002-2007 Aleph One Ltd.
20388 + * Copyright (C) 2002-2010 Aleph One Ltd.
20389 * for Toby Churchill Ltd and Brightstar Engineering
20391 * Created by Charles Manning <charles@aleph1.co.uk>
20394 #include "yaffs_guts.h"
20396 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
20397 -int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
20398 +void yaffs_init_tags(yaffs_ext_tags *tags);
20399 +int yaffs_validate_tags(yaffs_ext_tags *tags);
20401 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_trace.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_trace.h
20402 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_trace.h 1970-01-01 02:00:00.000000000 +0200
20403 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_trace.h 2010-10-20 13:28:16.064000294 +0300
20406 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20408 + * Copyright (C) 2002-2010 Aleph One Ltd.
20409 + * for Toby Churchill Ltd and Brightstar Engineering
20411 + * Created by Charles Manning <charles@aleph1.co.uk>
20413 + * This program is free software; you can redistribute it and/or modify
20414 + * it under the terms of the GNU Lesser General Public License version 2.1 as
20415 + * published by the Free Software Foundation.
20417 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
20421 +#ifndef __YTRACE_H__
20422 +#define __YTRACE_H__
20424 +extern unsigned int yaffs_trace_mask;
20425 +extern unsigned int yaffs_wr_attempts;
20429 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
20432 +#define YAFFS_TRACE_OS 0x00000002
20433 +#define YAFFS_TRACE_ALLOCATE 0x00000004
20434 +#define YAFFS_TRACE_SCAN 0x00000008
20435 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
20436 +#define YAFFS_TRACE_ERASE 0x00000020
20437 +#define YAFFS_TRACE_GC 0x00000040
20438 +#define YAFFS_TRACE_WRITE 0x00000080
20439 +#define YAFFS_TRACE_TRACING 0x00000100
20440 +#define YAFFS_TRACE_DELETION 0x00000200
20441 +#define YAFFS_TRACE_BUFFERS 0x00000400
20442 +#define YAFFS_TRACE_NANDACCESS 0x00000800
20443 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
20444 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
20445 +#define YAFFS_TRACE_MTD 0x00004000
20446 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
20448 +#define YAFFS_TRACE_VERIFY 0x00010000
20449 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
20450 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
20451 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
20453 +#define YAFFS_TRACE_SYNC 0x00100000
20454 +#define YAFFS_TRACE_BACKGROUND 0x00200000
20455 +#define YAFFS_TRACE_LOCK 0x00400000
20457 +#define YAFFS_TRACE_ERROR 0x40000000
20458 +#define YAFFS_TRACE_BUG 0x80000000
20459 +#define YAFFS_TRACE_ALWAYS 0xF0000000
20462 +#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
20465 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.c
20466 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.c 1970-01-01 02:00:00.000000000 +0200
20467 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.c 2010-10-20 13:28:16.031000294 +0300
20470 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
20472 + * Copyright (C) 2002-2010 Aleph One Ltd.
20473 + * for Toby Churchill Ltd and Brightstar Engineering
20475 + * Created by Charles Manning <charles@aleph1.co.uk>
20477 + * This program is free software; you can redistribute it and/or modify
20478 + * it under the terms of the GNU General Public License version 2 as
20479 + * published by the Free Software Foundation.
20483 +#include "yaffs_verify.h"
20484 +#include "yaffs_trace.h"
20485 +#include "yaffs_bitmap.h"
20486 +#include "yaffs_getblockinfo.h"
20487 +#include "yaffs_nand.h"
20489 +int yaffs_skip_verification(yaffs_dev_t *dev)
20492 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
20495 +static int yaffs_skip_full_verification(yaffs_dev_t *dev)
20498 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
20501 +static int yaffs_skip_nand_verification(yaffs_dev_t *dev)
20504 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
20508 +static const char *block_stateName[] = {
20522 +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
20524 + int actuallyUsed;
20527 + if (yaffs_skip_verification(dev))
20530 + /* Report illegal runtime states */
20531 + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
20532 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state));
20534 + switch (bi->block_state) {
20535 + case YAFFS_BLOCK_STATE_UNKNOWN:
20536 + case YAFFS_BLOCK_STATE_SCANNING:
20537 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
20538 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
20539 + n, block_stateName[bi->block_state]));
20542 + /* Check pages in use and soft deletions are legal */
20544 + actuallyUsed = bi->pages_in_use - bi->soft_del_pages;
20546 + if (bi->pages_in_use < 0 || bi->pages_in_use > dev->param.chunks_per_block ||
20547 + bi->soft_del_pages < 0 || bi->soft_del_pages > dev->param.chunks_per_block ||
20548 + actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block)
20549 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR),
20550 + n, bi->pages_in_use, bi->soft_del_pages));
20553 + /* Check chunk bitmap legal */
20554 + inUse = yaffs_count_chunk_bits(dev, n);
20555 + if (inUse != bi->pages_in_use)
20556 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR),
20557 + n, bi->pages_in_use, inUse));
20563 +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
20565 + yaffs_verify_blk(dev, bi, n);
20567 + /* After collection the block should be in the erased state */
20569 + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
20570 + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
20571 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
20572 + n, bi->block_state));
20576 +void yaffs_verify_blocks(yaffs_dev_t *dev)
20579 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
20580 + int nIllegalBlockStates = 0;
20582 + if (yaffs_skip_verification(dev))
20585 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
20587 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
20588 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
20589 + yaffs_verify_blk(dev, bi, i);
20591 + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
20592 + nBlocksPerState[bi->block_state]++;
20594 + nIllegalBlockStates++;
20597 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
20598 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
20600 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
20601 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
20602 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
20604 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
20605 + T(YAFFS_TRACE_VERIFY,
20606 + (TSTR("%s %d blocks"TENDSTR),
20607 + block_stateName[i], nBlocksPerState[i]));
20609 + if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
20610 + T(YAFFS_TRACE_VERIFY,
20611 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
20612 + dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
20614 + if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
20615 + T(YAFFS_TRACE_VERIFY,
20616 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
20617 + dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
20619 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
20620 + T(YAFFS_TRACE_VERIFY,
20621 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
20622 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
20624 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
20629 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
20630 + * case those tests will not be performed.
20632 +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck)
20634 + if (obj && yaffs_skip_verification(obj->my_dev))
20637 + if (!(tags && obj && oh)) {
20638 + T(YAFFS_TRACE_VERIFY,
20639 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
20644 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
20645 + oh->type > YAFFS_OBJECT_TYPE_MAX)
20646 + T(YAFFS_TRACE_VERIFY,
20647 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
20648 + tags->obj_id, oh->type));
20650 + if (tags->obj_id != obj->obj_id)
20651 + T(YAFFS_TRACE_VERIFY,
20652 + (TSTR("Obj %d header mismatch obj_id %d"TENDSTR),
20653 + tags->obj_id, obj->obj_id));
20657 + * Check that the object's parent ids match if parentCheck requested.
20659 + * Tests do not apply to the root object.
20662 + if (parentCheck && tags->obj_id > 1 && !obj->parent)
20663 + T(YAFFS_TRACE_VERIFY,
20664 + (TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR),
20665 + tags->obj_id, oh->parent_obj_id));
20667 + if (parentCheck && obj->parent &&
20668 + oh->parent_obj_id != obj->parent->obj_id &&
20669 + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
20670 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
20671 + T(YAFFS_TRACE_VERIFY,
20672 + (TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR),
20673 + tags->obj_id, oh->parent_obj_id, obj->parent->obj_id));
20675 + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
20676 + T(YAFFS_TRACE_VERIFY,
20677 + (TSTR("Obj %d header name is NULL"TENDSTR),
20680 + if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
20681 + T(YAFFS_TRACE_VERIFY,
20682 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
20688 +/* Not being used, but don't want to throw away yet */
20689 +int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn,
20690 + __u32 level, int chunk_offset)
20693 + yaffs_dev_t *dev = obj->my_dev;
20699 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
20700 + if (tn->internal[i]) {
20701 + ok = yaffs_verify_tnode_worker(obj,
20704 + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
20707 + } else if (level == 0) {
20708 + yaffs_ext_tags tags;
20709 + __u32 obj_id = obj->obj_id;
20711 + chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS;
20713 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
20714 + __u32 theChunk = yaffs_get_group_base(dev, tn, i);
20716 + if (theChunk > 0) {
20717 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */
20718 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
20719 + if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) {
20720 + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
20721 + obj_id, chunk_offset, theChunk,
20722 + tags.obj_id, tags.chunk_id));
20736 +void yaffs_verify_file(yaffs_obj_t *obj)
20738 + int requiredTallness;
20739 + int actualTallness;
20743 + yaffs_dev_t *dev;
20744 + yaffs_ext_tags tags;
20745 + yaffs_tnode_t *tn;
20751 + if (yaffs_skip_verification(obj->my_dev))
20754 + dev = obj->my_dev;
20755 + obj_id = obj->obj_id;
20757 + /* Check file size is consistent with tnode depth */
20758 + lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
20759 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
20760 + requiredTallness = 0;
20762 + x >>= YAFFS_TNODES_INTERNAL_BITS;
20763 + requiredTallness++;
20766 + actualTallness = obj->variant.file_variant.top_level;
20768 + /* Check that the chunks in the tnode tree are all correct.
20769 + * We do this by scanning through the tnode tree and
20770 + * checking the tags for every chunk match.
20773 + if (yaffs_skip_nand_verification(dev))
20776 + for (i = 1; i <= lastChunk; i++) {
20777 + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
20780 + __u32 theChunk = yaffs_get_group_base(dev, tn, i);
20781 + if (theChunk > 0) {
20782 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */
20783 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
20784 + if (tags.obj_id != obj_id || tags.chunk_id != i) {
20785 + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
20786 + obj_id, i, theChunk,
20787 + tags.obj_id, tags.chunk_id));
20795 +void yaffs_verify_link(yaffs_obj_t *obj)
20797 + if (obj && yaffs_skip_verification(obj->my_dev))
20800 + /* Verify sane equivalent object */
20803 +void yaffs_verify_symlink(yaffs_obj_t *obj)
20805 + if (obj && yaffs_skip_verification(obj->my_dev))
20808 + /* Verify symlink string */
20811 +void yaffs_verify_special(yaffs_obj_t *obj)
20813 + if (obj && yaffs_skip_verification(obj->my_dev))
20817 +void yaffs_verify_obj(yaffs_obj_t *obj)
20819 + yaffs_dev_t *dev;
20824 + __u32 chunk_idOk;
20825 + __u32 chunkInRange;
20826 + __u32 chunkShouldNotBeDeleted;
20827 + __u32 chunkValid;
20832 + if (obj->being_created)
20835 + dev = obj->my_dev;
20837 + if (yaffs_skip_verification(dev))
20840 + /* Check sane object header chunk */
20842 + chunkMin = dev->internal_start_block * dev->param.chunks_per_block;
20843 + chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1;
20845 + chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax);
20846 + chunk_idOk = chunkInRange || (obj->hdr_chunk == 0);
20847 + chunkValid = chunkInRange &&
20848 + yaffs_check_chunk_bit(dev,
20849 + obj->hdr_chunk / dev->param.chunks_per_block,
20850 + obj->hdr_chunk % dev->param.chunks_per_block);
20851 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
20853 + if (!obj->fake &&
20854 + (!chunk_idOk || chunkShouldNotBeDeleted)) {
20855 + T(YAFFS_TRACE_VERIFY,
20856 + (TSTR("Obj %d has chunk_id %d %s %s"TENDSTR),
20857 + obj->obj_id, obj->hdr_chunk,
20858 + chunk_idOk ? "" : ",out of range",
20859 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
20862 + if (chunkValid && !yaffs_skip_nand_verification(dev)) {
20863 + yaffs_ext_tags tags;
20864 + yaffs_obj_header *oh;
20865 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
20867 + oh = (yaffs_obj_header *)buffer;
20869 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer,
20872 + yaffs_verify_oh(obj, oh, &tags, 1);
20874 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
20877 + /* Verify it has a parent */
20878 + if (obj && !obj->fake &&
20879 + (!obj->parent || obj->parent->my_dev != dev)) {
20880 + T(YAFFS_TRACE_VERIFY,
20881 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
20882 + obj->obj_id, obj->parent));
20885 + /* Verify parent is a directory */
20886 + if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20887 + T(YAFFS_TRACE_VERIFY,
20888 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
20889 + obj->obj_id, obj->parent->variant_type));
20892 + switch (obj->variant_type) {
20893 + case YAFFS_OBJECT_TYPE_FILE:
20894 + yaffs_verify_file(obj);
20896 + case YAFFS_OBJECT_TYPE_SYMLINK:
20897 + yaffs_verify_symlink(obj);
20899 + case YAFFS_OBJECT_TYPE_DIRECTORY:
20900 + yaffs_verify_dir(obj);
20902 + case YAFFS_OBJECT_TYPE_HARDLINK:
20903 + yaffs_verify_link(obj);
20905 + case YAFFS_OBJECT_TYPE_SPECIAL:
20906 + yaffs_verify_special(obj);
20908 + case YAFFS_OBJECT_TYPE_UNKNOWN:
20910 + T(YAFFS_TRACE_VERIFY,
20911 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
20912 + obj->obj_id, obj->variant_type));
20917 +void yaffs_verify_objects(yaffs_dev_t *dev)
20919 + yaffs_obj_t *obj;
20921 + struct ylist_head *lh;
20923 + if (yaffs_skip_verification(dev))
20926 + /* Iterate through the objects in each hash entry */
20928 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
20929 + ylist_for_each(lh, &dev->obj_bucket[i].list) {
20931 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
20932 + yaffs_verify_obj(obj);
20939 +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
20941 + struct ylist_head *lh;
20942 + yaffs_obj_t *listObj;
20947 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
20952 + if (yaffs_skip_verification(obj->my_dev))
20955 + if (!obj->parent) {
20956 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
20961 + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20962 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
20966 + /* Iterate through the objects in each hash entry */
20968 + ylist_for_each(lh, &obj->parent->variant.dir_variant.children) {
20970 + listObj = ylist_entry(lh, yaffs_obj_t, siblings);
20971 + yaffs_verify_obj(listObj);
20972 + if (obj == listObj)
20977 + if (count != 1) {
20978 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
20983 +void yaffs_verify_dir(yaffs_obj_t *directory)
20985 + struct ylist_head *lh;
20986 + yaffs_obj_t *listObj;
20988 + if (!directory) {
20993 + if (yaffs_skip_full_verification(directory->my_dev))
20996 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20997 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type));
21001 + /* Iterate through the objects in each hash entry */
21003 + ylist_for_each(lh, &directory->variant.dir_variant.children) {
21005 + listObj = ylist_entry(lh, yaffs_obj_t, siblings);
21006 + if (listObj->parent != directory) {
21007 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
21010 + yaffs_verify_obj_in_dir(listObj);
21015 +static int yaffs_free_verification_failures;
21017 +void yaffs_verify_free_chunks(yaffs_dev_t *dev)
21022 + if (yaffs_skip_verification(dev))
21025 + counted = yaffs_count_free_chunks(dev);
21027 + difference = dev->n_free_chunks - counted;
21029 + if (difference) {
21030 + T(YAFFS_TRACE_ALWAYS,
21031 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
21032 + dev->n_free_chunks, counted, difference));
21033 + yaffs_free_verification_failures++;
21037 +int yaffs_verify_file_sane(yaffs_obj_t *in)
21045 + yaffs_tnode_t *tn;
21046 + yaffs_tags_t localTags;
21047 + yaffs_tags_t *tags = &localTags;
21051 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
21052 + return YAFFS_FAIL;
21054 + obj_id = in->obj_id;
21055 + fSize = in->variant.file_variant.file_size;
21057 + (fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk;
21059 + for (chunk = 1; chunk <= n_chunks; chunk++) {
21060 + tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant,
21065 + theChunk = yaffs_get_group_base(dev, tn, chunk);
21067 + if (yaffs_check_chunk_bits
21068 + (dev, theChunk / dev->param.chunks_per_block,
21069 + theChunk % dev->param.chunks_per_block)) {
21071 + yaffs_rd_chunk_tags_nand(in->my_dev, theChunk,
21074 + if (yaffs_tags_match
21075 + (tags, in->obj_id, chunk, is_deleted)) {
21085 + /* T(("No level 0 found for %d\n", chunk)); */
21089 + return failed ? YAFFS_FAIL : YAFFS_OK;
21095 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.h
21096 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.h 1970-01-01 02:00:00.000000000 +0200
21097 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.h 2010-10-20 13:28:16.064000294 +0300
21100 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21102 + * Copyright (C) 2002-2010 Aleph One Ltd.
21103 + * for Toby Churchill Ltd and Brightstar Engineering
21105 + * Created by Charles Manning <charles@aleph1.co.uk>
21107 + * This program is free software; you can redistribute it and/or modify
21108 + * it under the terms of the GNU General Public License version 2 as
21109 + * published by the Free Software Foundation.
21112 +#ifndef __YAFFS_VERIFY_H__
21113 +#define __YAFFS_VERIFY_H__
21115 +#include "yaffs_guts.h"
21117 +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
21118 +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
21119 +void yaffs_verify_blocks(yaffs_dev_t *dev);
21121 +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck);
21122 +void yaffs_verify_file(yaffs_obj_t *obj);
21123 +void yaffs_verify_link(yaffs_obj_t *obj);
21124 +void yaffs_verify_symlink(yaffs_obj_t *obj);
21125 +void yaffs_verify_special(yaffs_obj_t *obj);
21126 +void yaffs_verify_obj(yaffs_obj_t *obj);
21127 +void yaffs_verify_objects(yaffs_dev_t *dev);
21128 +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj);
21129 +void yaffs_verify_dir(yaffs_obj_t *directory);
21130 +void yaffs_verify_free_chunks(yaffs_dev_t *dev);
21132 +int yaffs_verify_file_sane(yaffs_obj_t *obj);
21134 +int yaffs_skip_verification(yaffs_dev_t *dev);
21138 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_vfs_glue.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_vfs_glue.c
21139 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_vfs_glue.c 1970-01-01 02:00:00.000000000 +0200
21140 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_vfs_glue.c 2010-10-20 13:28:16.069000294 +0300
21143 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21145 + * Copyright (C) 2002-2010 Aleph One Ltd.
21146 + * for Toby Churchill Ltd and Brightstar Engineering
21148 + * Created by Charles Manning <charles@aleph1.co.uk>
21149 + * Acknowledgements:
21150 + * Luc van OostenRyck for numerous patches.
21151 + * Nick Bane for numerous patches.
21152 + * Nick Bane for 2.5/2.6 integration.
21153 + * Andras Toth for mknod rdev issue.
21154 + * Michael Fischer for finding the problem with inode inconsistency.
21155 + * Some code bodily lifted from JFFS
21157 + * This program is free software; you can redistribute it and/or modify
21158 + * it under the terms of the GNU General Public License version 2 as
21159 + * published by the Free Software Foundation.
21164 + * This is the file system front-end to YAFFS that hooks it up to
21168 + * >> 2.4: sb->u.generic_sbp points to the yaffs_dev_t associated with
21169 + * this superblock
21170 + * >> 2.6: sb->s_fs_info points to the yaffs_dev_t associated with this
21172 + * >> inode->u.generic_ip points to the associated yaffs_obj_t.
21176 + * There are two variants of the VFS glue code. This variant should compile
21177 + * for any version of Linux.
21179 +#include <linux/version.h>
21181 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
21182 +#define YAFFS_COMPILE_BACKGROUND
21183 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
21184 +#define YAFFS_COMPILE_FREEZER
21188 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
21189 +#define YAFFS_COMPILE_EXPORTFS
21192 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
21193 +#define YAFFS_USE_SETATTR_COPY
21194 +#define YAFFS_USE_TRUNCATE_SETSIZE
21196 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
21197 +#define YAFFS_HAS_EVICT_INODE
21200 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
21201 +#define YAFFS_NEW_FOLLOW_LINK 1
21203 +#define YAFFS_NEW_FOLLOW_LINK 0
21206 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
21207 +#include <linux/config.h>
21210 +#include <linux/kernel.h>
21211 +#include <linux/module.h>
21212 +#include <linux/slab.h>
21213 +#include <linux/init.h>
21214 +#include <linux/fs.h>
21215 +#include <linux/proc_fs.h>
21216 +#include <linux/smp_lock.h>
21217 +#include <linux/pagemap.h>
21218 +#include <linux/mtd/mtd.h>
21219 +#include <linux/interrupt.h>
21220 +#include <linux/string.h>
21221 +#include <linux/ctype.h>
21223 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21224 +#include <linux/namei.h>
21227 +#ifdef YAFFS_COMPILE_EXPORTFS
21228 +#include <linux/exportfs.h>
21231 +#ifdef YAFFS_COMPILE_BACKGROUND
21232 +#include <linux/kthread.h>
21233 +#include <linux/delay.h>
21235 +#ifdef YAFFS_COMPILE_FREEZER
21236 +#include <linux/freezer.h>
21239 +#include <asm/div64.h>
21241 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21243 +#include <linux/statfs.h>
21245 +#define UnlockPage(p) unlock_page(p)
21246 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
21248 +/* FIXME: use sb->s_id instead ? */
21249 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
21253 +#include <linux/locks.h>
21254 +#define BDEVNAME_SIZE 0
21255 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
21257 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
21258 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
21264 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
21265 +#define YPROC_ROOT (&proc_root)
21267 +#define YPROC_ROOT NULL
21270 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
21271 +#define Y_INIT_TIMER(a) init_timer(a)
21273 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
21276 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21277 +#define WRITE_SIZE_STR "writesize"
21278 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
21280 +#define WRITE_SIZE_STR "oobblock"
21281 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
21284 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
21285 +#define YAFFS_USE_WRITE_BEGIN_END 1
21287 +#define YAFFS_USE_WRITE_BEGIN_END 0
21290 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
21291 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
21293 + uint64_t result = partition_size;
21294 + do_div(result, block_size);
21295 + return (uint32_t)result;
21298 +#define YCALCBLOCKS(s, b) ((s)/(b))
21301 +#include <linux/uaccess.h>
21302 +#include <linux/mtd/mtd.h>
21304 +#include "yportenv.h"
21305 +#include "yaffs_trace.h"
21306 +#include "yaffs_guts.h"
21308 +#include "yaffs_linux.h"
21310 +#include "yaffs_mtdif.h"
21311 +#include "yaffs_mtdif1.h"
21312 +#include "yaffs_mtdif2.h"
21314 +unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
21315 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
21316 +unsigned int yaffs_auto_checkpoint = 1;
21317 +unsigned int yaffs_gc_control = 1;
21318 +unsigned int yaffs_bg_enable = 1;
21320 +/* Module Parameters */
21321 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21322 +module_param(yaffs_trace_mask, uint, 0644);
21323 +module_param(yaffs_wr_attempts, uint, 0644);
21324 +module_param(yaffs_auto_checkpoint, uint, 0644);
21325 +module_param(yaffs_gc_control, uint, 0644);
21326 +module_param(yaffs_bg_enable, uint, 0644);
21328 +MODULE_PARM(yaffs_trace_mask, "i");
21329 +MODULE_PARM(yaffs_wr_attempts, "i");
21330 +MODULE_PARM(yaffs_auto_checkpoint, "i");
21331 +MODULE_PARM(yaffs_gc_control, "i");
21334 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
21335 +/* use iget and read_inode */
21336 +#define Y_IGET(sb, inum) iget((sb), (inum))
21337 +static void yaffs_read_inode(struct inode *inode);
21340 +/* Call local equivalent */
21341 +#define YAFFS_USE_OWN_IGET
21342 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
21344 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
21347 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
21348 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
21350 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
21353 +#define yaffs_InodeToObject(iptr) ((yaffs_obj_t *)(yaffs_InodeToObjectLV(iptr)))
21354 +#define yaffs_dentry_to_obj(dptr) yaffs_InodeToObject((dptr)->d_inode)
21356 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21357 +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->s_fs_info)
21359 +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
21363 +#define update_dir_time(dir) do {\
21364 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
21367 +static void yaffs_put_super(struct super_block *sb);
21369 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
21371 +static ssize_t yaffs_hold_space(struct file *f);
21372 +static void yaffs_release_space(struct file *f);
21374 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21375 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
21377 +static int yaffs_file_flush(struct file *file);
21380 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
21381 +static int yaffs_sync_object(struct file *file, int datasync);
21383 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
21387 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
21389 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21390 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
21391 + struct nameidata *n);
21392 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
21393 + struct nameidata *n);
21395 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
21396 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
21398 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
21399 + struct dentry *dentry);
21400 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
21401 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
21402 + const char *symname);
21403 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
21405 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21406 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
21409 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
21412 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
21413 + struct inode *new_dir, struct dentry *new_dentry);
21414 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
21416 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21417 +static int yaffs_sync_fs(struct super_block *sb, int wait);
21418 +static void yaffs_write_super(struct super_block *sb);
21420 +static int yaffs_sync_fs(struct super_block *sb);
21421 +static int yaffs_write_super(struct super_block *sb);
21424 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21425 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
21426 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21427 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
21429 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
21432 +#ifdef YAFFS_HAS_PUT_INODE
21433 +static void yaffs_put_inode(struct inode *inode);
21436 +#ifdef YAFFS_HAS_EVICT_INODE
21437 +static void yaffs_evict_inode(struct inode *);
21439 +static void yaffs_delete_inode(struct inode *);
21440 +static void yaffs_clear_inode(struct inode *);
21443 +static int yaffs_readpage(struct file *file, struct page *page);
21444 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21445 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
21447 +static int yaffs_writepage(struct page *page);
21450 +#ifdef CONFIG_YAFFS_XATTR
21451 +int yaffs_setxattr(struct dentry *dentry, const char *name,
21452 + const void *value, size_t size, int flags);
21453 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
21455 +int yaffs_removexattr(struct dentry *dentry, const char *name);
21456 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
21460 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
21461 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
21462 + loff_t pos, unsigned len, unsigned flags,
21463 + struct page **pagep, void **fsdata);
21464 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
21465 + loff_t pos, unsigned len, unsigned copied,
21466 + struct page *pg, void *fsdadata);
21468 +static int yaffs_prepare_write(struct file *f, struct page *pg,
21469 + unsigned offset, unsigned to);
21470 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
21475 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
21477 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21478 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
21479 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
21481 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
21484 +static void yaffs_touch_super(yaffs_dev_t *dev);
21486 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
21488 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
21491 +static struct address_space_operations yaffs_file_address_operations = {
21492 + .readpage = yaffs_readpage,
21493 + .writepage = yaffs_writepage,
21494 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
21495 + .write_begin = yaffs_write_begin,
21496 + .write_end = yaffs_write_end,
21498 + .prepare_write = yaffs_prepare_write,
21499 + .commit_write = yaffs_commit_write,
21504 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
21505 +static const struct file_operations yaffs_file_operations = {
21506 + .read = do_sync_read,
21507 + .write = do_sync_write,
21508 + .aio_read = generic_file_aio_read,
21509 + .aio_write = generic_file_aio_write,
21510 + .mmap = generic_file_mmap,
21511 + .flush = yaffs_file_flush,
21512 + .fsync = yaffs_sync_object,
21513 + .splice_read = generic_file_splice_read,
21514 + .splice_write = generic_file_splice_write,
21515 + .llseek = generic_file_llseek,
21518 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
21520 +static const struct file_operations yaffs_file_operations = {
21521 + .read = do_sync_read,
21522 + .write = do_sync_write,
21523 + .aio_read = generic_file_aio_read,
21524 + .aio_write = generic_file_aio_write,
21525 + .mmap = generic_file_mmap,
21526 + .flush = yaffs_file_flush,
21527 + .fsync = yaffs_sync_object,
21528 + .sendfile = generic_file_sendfile,
21533 +static const struct file_operations yaffs_file_operations = {
21534 + .read = generic_file_read,
21535 + .write = generic_file_write,
21536 + .mmap = generic_file_mmap,
21537 + .flush = yaffs_file_flush,
21538 + .fsync = yaffs_sync_object,
21539 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21540 + .sendfile = generic_file_sendfile,
21545 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
21546 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
21548 + void * kaddr = kmap_atomic(page, KM_USER0);
21549 + memset(kaddr + start, 0, end - start);
21550 + kunmap_atomic(kaddr, KM_USER0);
21551 + flush_dcache_page(page);
21556 +static const struct inode_operations yaffs_file_inode_operations = {
21557 + .setattr = yaffs_setattr,
21558 +#ifdef CONFIG_YAFFS_XATTR
21559 + .setxattr = yaffs_setxattr,
21560 + .getxattr = yaffs_getxattr,
21561 + .listxattr = yaffs_listxattr,
21562 + .removexattr = yaffs_removexattr,
21566 +static const struct inode_operations yaffs_symlink_inode_operations = {
21567 + .readlink = yaffs_readlink,
21568 + .follow_link = yaffs_follow_link,
21569 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21570 + .put_link = yaffs_put_link,
21572 + .setattr = yaffs_setattr,
21573 +#ifdef CONFIG_YAFFS_XATTR
21574 + .setxattr = yaffs_setxattr,
21575 + .getxattr = yaffs_getxattr,
21576 + .listxattr = yaffs_listxattr,
21577 + .removexattr = yaffs_removexattr,
21581 +static const struct inode_operations yaffs_dir_inode_operations = {
21582 + .create = yaffs_create,
21583 + .lookup = yaffs_lookup,
21584 + .link = yaffs_link,
21585 + .unlink = yaffs_unlink,
21586 + .symlink = yaffs_symlink,
21587 + .mkdir = yaffs_mkdir,
21588 + .rmdir = yaffs_unlink,
21589 + .mknod = yaffs_mknod,
21590 + .rename = yaffs_rename,
21591 + .setattr = yaffs_setattr,
21592 +#ifdef CONFIG_YAFFS_XATTR
21593 + .setxattr = yaffs_setxattr,
21594 + .getxattr = yaffs_getxattr,
21595 + .listxattr = yaffs_listxattr,
21596 + .removexattr = yaffs_removexattr,
21600 +static const struct file_operations yaffs_dir_operations = {
21601 + .read = generic_read_dir,
21602 + .readdir = yaffs_readdir,
21603 + .fsync = yaffs_sync_object,
21604 + .llseek = yaffs_dir_llseek,
21607 +static const struct super_operations yaffs_super_ops = {
21608 + .statfs = yaffs_statfs,
21610 +#ifndef YAFFS_USE_OWN_IGET
21611 + .read_inode = yaffs_read_inode,
21613 +#ifdef YAFFS_HAS_PUT_INODE
21614 + .put_inode = yaffs_put_inode,
21616 + .put_super = yaffs_put_super,
21617 +#ifdef YAFFS_HAS_EVICT_INODE
21618 + .evict_inode = yaffs_evict_inode,
21620 + .delete_inode = yaffs_delete_inode,
21621 + .clear_inode = yaffs_clear_inode,
21623 + .sync_fs = yaffs_sync_fs,
21624 + .write_super = yaffs_write_super,
21628 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
21630 +#ifdef YAFFS_USE_SETATTR_COPY
21631 + setattr_copy(inode,attr);
21634 + return inode_setattr(inode, attr);
21639 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
21641 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
21642 + truncate_setsize(inode,newsize);
21645 + truncate_inode_pages(&inode->i_data,newsize);
21651 +static unsigned yaffs_gc_control_callback(yaffs_dev_t *dev)
21653 + return yaffs_gc_control;
21656 +static void yaffs_gross_lock(yaffs_dev_t *dev)
21658 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
21659 + down(&(yaffs_dev_to_lc(dev)->grossLock));
21660 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
21663 +static void yaffs_gross_unlock(yaffs_dev_t *dev)
21665 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
21666 + up(&(yaffs_dev_to_lc(dev)->grossLock));
21669 +#ifdef YAFFS_COMPILE_EXPORTFS
21671 +static struct inode *
21672 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
21674 + return Y_IGET(sb, ino);
21677 +static struct dentry *
21678 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
21680 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
21683 +static struct dentry *
21684 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
21686 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
21689 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
21692 + struct super_block *sb = dentry->d_inode->i_sb;
21693 + struct dentry *parent = ERR_PTR(-ENOENT);
21694 + struct inode *inode;
21695 + unsigned long parent_ino;
21696 + yaffs_obj_t *d_obj;
21697 + yaffs_obj_t *parent_obj;
21699 + d_obj = yaffs_InodeToObject(dentry->d_inode);
21702 + parent_obj = d_obj->parent;
21703 + if (parent_obj) {
21704 + parent_ino = yaffs_get_obj_inode(parent_obj);
21705 + inode = Y_IGET(sb, parent_ino);
21707 + if (IS_ERR(inode)) {
21708 + parent = ERR_CAST(inode);
21710 + parent = d_obtain_alias(inode);
21711 + if (!IS_ERR(parent)) {
21712 + parent = ERR_PTR(-ENOMEM);
21722 +/* Just declare a zero structure as a NULL value implies
21723 + * using the default functions of exportfs.
21726 +static struct export_operations yaffs_export_ops =
21728 + .fh_to_dentry = yaffs2_fh_to_dentry,
21729 + .fh_to_parent = yaffs2_fh_to_parent,
21730 + .get_parent = yaffs2_get_parent,
21735 +/*-----------------------------------------------------------------*/
21736 +/* Directory search context allows us to unlock access to yaffs during
21737 + * filldir without causing problems with the directory being modified.
21738 + * This is similar to the tried and tested mechanism used in yaffs direct.
21740 + * A search context iterates along a doubly linked list of siblings in the
21741 + * directory. If the iterating object is deleted then this would corrupt
21742 + * the list iteration, likely causing a crash. The search context avoids
21743 + * this by using the remove_obj_fn to move the search context to the
21744 + * next object before the object is deleted.
21746 + * Many readdirs (and thus seach conexts) may be alive simulateously so
21747 + * each yaffs_dev_t has a list of these.
21749 + * A seach context lives for the duration of a readdir.
21751 + * All these functions must be called while yaffs is locked.
21754 +struct yaffs_SearchContext {
21755 + yaffs_dev_t *dev;
21756 + yaffs_obj_t *dirObj;
21757 + yaffs_obj_t *nextReturn;
21758 + struct ylist_head others;
21762 + * yaffs_NewSearch() creates a new search context, initialises it and
21763 + * adds it to the device's search context list.
21765 + * Called at start of readdir.
21767 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_obj_t *dir)
21769 + yaffs_dev_t *dev = dir->my_dev;
21770 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
21772 + sc->dirObj = dir;
21774 + if( ylist_empty(&sc->dirObj->variant.dir_variant.children))
21775 + sc->nextReturn = NULL;
21777 + sc->nextReturn = ylist_entry(
21778 + dir->variant.dir_variant.children.next,
21779 + yaffs_obj_t,siblings);
21780 + YINIT_LIST_HEAD(&sc->others);
21781 + ylist_add(&sc->others,&(yaffs_dev_to_lc(dev)->searchContexts));
21787 + * yaffs_search_end() disposes of a search context and cleans up.
21789 +static void yaffs_search_end(struct yaffs_SearchContext * sc)
21792 + ylist_del(&sc->others);
21798 + * yaffs_search_advance() moves a search context to the next object.
21799 + * Called when the search iterates or when an object removal causes
21800 + * the search context to be moved to the next object.
21802 +static void yaffs_search_advance(struct yaffs_SearchContext *sc)
21807 + if( sc->nextReturn == NULL ||
21808 + ylist_empty(&sc->dirObj->variant.dir_variant.children))
21809 + sc->nextReturn = NULL;
21811 + struct ylist_head *next = sc->nextReturn->siblings.next;
21813 + if( next == &sc->dirObj->variant.dir_variant.children)
21814 + sc->nextReturn = NULL; /* end of list */
21816 + sc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
21821 + * yaffs_remove_obj_callback() is called when an object is unlinked.
21822 + * We check open search contexts and advance any which are currently
21823 + * on the object being iterated.
21825 +static void yaffs_remove_obj_callback(yaffs_obj_t *obj)
21828 + struct ylist_head *i;
21829 + struct yaffs_SearchContext *sc;
21830 + struct ylist_head *search_contexts = &(yaffs_dev_to_lc(obj->my_dev)->searchContexts);
21833 + /* Iterate through the directory search contexts.
21834 + * If any are currently on the object being removed, then advance
21835 + * the search context to the next object to prevent a hanging pointer.
21837 + ylist_for_each(i, search_contexts) {
21839 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
21840 + if(sc->nextReturn == obj)
21841 + yaffs_search_advance(sc);
21848 +/*-----------------------------------------------------------------*/
21850 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
21853 + unsigned char *alias;
21856 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
21858 + yaffs_gross_lock(dev);
21860 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
21862 + yaffs_gross_unlock(dev);
21867 + ret = vfs_readlink(dentry, buffer, buflen, alias);
21872 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21873 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
21875 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
21878 + unsigned char *alias;
21880 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
21882 + yaffs_gross_lock(dev);
21884 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
21885 + yaffs_gross_unlock(dev);
21892 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21893 + nd_set_link(nd, alias);
21894 + ret = (int)alias;
21896 + return ERR_PTR(ret);
21898 + ret = vfs_follow_link(nd, alias);
21905 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21906 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
21911 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
21912 + yaffs_obj_t *obj);
21915 + * Lookup is used to find objects in the fs
21917 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21919 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
21920 + struct nameidata *n)
21922 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
21925 + yaffs_obj_t *obj;
21926 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
21928 + yaffs_dev_t *dev = yaffs_InodeToObject(dir)->my_dev;
21930 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
21931 + yaffs_gross_lock(dev);
21933 + T(YAFFS_TRACE_OS,
21934 + (TSTR("yaffs_lookup for %d:%s\n"),
21935 + yaffs_InodeToObject(dir)->obj_id, dentry->d_name.name));
21937 + obj = yaffs_find_by_name(yaffs_InodeToObject(dir),
21938 + dentry->d_name.name);
21940 + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
21942 + /* Can't hold gross lock when calling yaffs_get_inode() */
21943 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
21944 + yaffs_gross_unlock(dev);
21947 + T(YAFFS_TRACE_OS,
21948 + (TSTR("yaffs_lookup found %d\n"), obj->obj_id));
21950 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
21953 + T(YAFFS_TRACE_OS,
21954 + (TSTR("yaffs_loookup dentry \n")));
21955 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
21956 + * d_add even if NULL inode */
21958 + /*dget(dentry); // try to solve directory bug */
21959 + d_add(dentry, inode);
21961 + /* return dentry; */
21967 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
21971 +/* added NCB for 2.5/6 compatability - forces add even if inode is
21972 + * NULL which creates dentry hash */
21973 + d_add(dentry, inode);
21979 +#ifdef YAFFS_HAS_PUT_INODE
21981 +/* For now put inode is just for debugging
21982 + * Put inode is called when the inode **structure** is put.
21984 +static void yaffs_put_inode(struct inode *inode)
21986 + T(YAFFS_TRACE_OS,
21987 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
21988 + atomic_read(&inode->i_count)));
21994 +static void yaffs_unstitch_obj(struct inode *inode, yaffs_obj_t *obj)
21996 + /* Clear the association between the inode and
21997 + * the yaffs_obj_t.
21999 + obj->my_inode = NULL;
22000 + yaffs_InodeToObjectLV(inode) = NULL;
22002 + /* If the object freeing was deferred, then the real
22003 + * free happens now.
22004 + * This should fix the inode inconsistency problem.
22006 + yaffs_handle_defered_free(obj);
22009 +#ifdef YAFFS_HAS_EVICT_INODE
22010 +/* yaffs_evict_inode combines into one operation what was previously done in
22011 + * yaffs_clear_inode() and yaffs_delete_inode()
22014 +static void yaffs_evict_inode( struct inode *inode)
22016 + yaffs_obj_t *obj;
22017 + yaffs_dev_t *dev;
22018 + int deleteme = 0;
22020 + obj = yaffs_InodeToObject(inode);
22022 + T(YAFFS_TRACE_OS,
22023 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22024 + atomic_read(&inode->i_count),
22025 + obj ? "object exists" : "null object"));
22027 + if (!inode->i_nlink && !is_bad_inode(inode))
22029 + truncate_inode_pages(&inode->i_data,0);
22030 + end_writeback(inode);
22032 + if(deleteme && obj){
22033 + dev = obj->my_dev;
22034 + yaffs_gross_lock(dev);
22035 + yaffs_del_obj(obj);
22036 + yaffs_gross_unlock(dev);
22039 + dev = obj->my_dev;
22040 + yaffs_gross_lock(dev);
22041 + yaffs_unstitch_obj(inode,obj);
22042 + yaffs_gross_unlock(dev);
22049 +/* clear is called to tell the fs to release any per-inode data it holds.
22050 + * The object might still exist on disk and is just being thrown out of the cache
22051 + * or else the object has actually been deleted and we're being called via
22053 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
22056 +static void yaffs_clear_inode(struct inode *inode)
22058 + yaffs_obj_t *obj;
22059 + yaffs_dev_t *dev;
22061 + obj = yaffs_InodeToObject(inode);
22063 + T(YAFFS_TRACE_OS,
22064 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22065 + atomic_read(&inode->i_count),
22066 + obj ? "object exists" : "null object"));
22069 + dev = obj->my_dev;
22070 + yaffs_gross_lock(dev);
22071 + yaffs_unstitch_obj(inode,obj);
22072 + yaffs_gross_unlock(dev);
22077 +/* delete is called when the link count is zero and the inode
22078 + * is put (ie. nobody wants to know about it anymore, time to
22079 + * delete the file).
22080 + * NB Must call clear_inode()
22082 +static void yaffs_delete_inode(struct inode *inode)
22084 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
22085 + yaffs_dev_t *dev;
22087 + T(YAFFS_TRACE_OS,
22088 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22089 + atomic_read(&inode->i_count),
22090 + obj ? "object exists" : "null object"));
22093 + dev = obj->my_dev;
22094 + yaffs_gross_lock(dev);
22095 + yaffs_del_obj(obj);
22096 + yaffs_gross_unlock(dev);
22098 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
22099 + truncate_inode_pages(&inode->i_data, 0);
22101 + clear_inode(inode);
22106 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
22107 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
22109 +static int yaffs_file_flush(struct file *file)
22112 + yaffs_obj_t *obj = yaffs_dentry_to_obj(file->f_dentry);
22114 + yaffs_dev_t *dev = obj->my_dev;
22116 + T(YAFFS_TRACE_OS,
22117 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id,
22118 + obj->dirty ? "dirty" : "clean"));
22120 + yaffs_gross_lock(dev);
22122 + yaffs_flush_file(obj, 1, 0);
22124 + yaffs_gross_unlock(dev);
22129 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
22131 + /* Lifted from jffs2 */
22133 + yaffs_obj_t *obj;
22134 + unsigned char *pg_buf;
22137 + yaffs_dev_t *dev;
22139 + T(YAFFS_TRACE_OS,
22140 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
22141 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
22142 + (unsigned)PAGE_CACHE_SIZE));
22144 + obj = yaffs_dentry_to_obj(f->f_dentry);
22146 + dev = obj->my_dev;
22148 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22149 + BUG_ON(!PageLocked(pg));
22151 + if (!PageLocked(pg))
22155 + pg_buf = kmap(pg);
22156 + /* FIXME: Can kmap fail? */
22158 + yaffs_gross_lock(dev);
22160 + ret = yaffs_file_rd(obj, pg_buf,
22161 + pg->index << PAGE_CACHE_SHIFT,
22162 + PAGE_CACHE_SIZE);
22164 + yaffs_gross_unlock(dev);
22170 + ClearPageUptodate(pg);
22171 + SetPageError(pg);
22173 + SetPageUptodate(pg);
22174 + ClearPageError(pg);
22177 + flush_dcache_page(pg);
22180 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
22184 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
22186 + int ret = yaffs_readpage_nolock(f, pg);
22191 +static int yaffs_readpage(struct file *f, struct page *pg)
22195 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
22196 + ret=yaffs_readpage_unlock(f, pg);
22197 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
22201 +/* writepage inspired by/stolen from smbfs */
22203 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22204 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
22206 +static int yaffs_writepage(struct page *page)
22209 + yaffs_dev_t *dev;
22210 + struct address_space *mapping = page->mapping;
22211 + struct inode *inode;
22212 + unsigned long end_index;
22214 + yaffs_obj_t *obj;
22215 + int nWritten = 0;
22216 + unsigned n_bytes;
22221 + inode = mapping->host;
22224 + i_size = i_size_read(inode);
22226 + end_index = i_size >> PAGE_CACHE_SHIFT;
22228 + if(page->index < end_index)
22229 + n_bytes = PAGE_CACHE_SIZE;
22231 + n_bytes = i_size & (PAGE_CACHE_SIZE -1);
22233 + if (page->index > end_index || !n_bytes) {
22234 + T(YAFFS_TRACE_OS,
22235 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
22236 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
22237 + (unsigned)inode->i_size));
22238 + T(YAFFS_TRACE_OS,
22239 + (TSTR(" -> don't care!!\n")));
22241 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
22242 + set_page_writeback(page);
22243 + unlock_page(page);
22244 + end_page_writeback(page);
22249 + if(n_bytes != PAGE_CACHE_SIZE)
22250 + zero_user_segment(page,n_bytes,PAGE_CACHE_SIZE);
22254 + buffer = kmap(page);
22256 + obj = yaffs_InodeToObject(inode);
22257 + dev = obj->my_dev;
22258 + yaffs_gross_lock(dev);
22260 + T(YAFFS_TRACE_OS,
22261 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
22262 + (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes));
22263 + T(YAFFS_TRACE_OS,
22264 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
22265 + (int)obj->variant.file_variant.file_size, (int)inode->i_size));
22267 + nWritten = yaffs_wr_file(obj, buffer,
22268 + page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
22270 + yaffs_touch_super(dev);
22272 + T(YAFFS_TRACE_OS,
22273 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
22274 + (int)obj->variant.file_variant.file_size, (int)inode->i_size));
22276 + yaffs_gross_unlock(dev);
22279 + set_page_writeback(page);
22280 + unlock_page(page);
22281 + end_page_writeback(page);
22284 + return (nWritten == n_bytes) ? 0 : -ENOSPC;
22288 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
22289 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
22290 + loff_t pos, unsigned len, unsigned flags,
22291 + struct page **pagep, void **fsdata)
22293 + struct page *pg = NULL;
22294 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
22297 + int space_held = 0;
22300 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
22301 + pg = grab_cache_page_write_begin(mapping, index, flags);
22303 + pg = __grab_cache_page(mapping, index);
22311 + T(YAFFS_TRACE_OS,
22312 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
22313 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
22315 + /* Get fs space */
22316 + space_held = yaffs_hold_space(filp);
22318 + if (!space_held) {
22323 + /* Update page if required */
22325 + if (!Page_Uptodate(pg))
22326 + ret = yaffs_readpage_nolock(filp, pg);
22331 + /* Happy path return */
22332 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
22337 + T(YAFFS_TRACE_OS,
22338 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
22340 + yaffs_release_space(filp);
22343 + page_cache_release(pg);
22350 +static int yaffs_prepare_write(struct file *f, struct page *pg,
22351 + unsigned offset, unsigned to)
22353 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
22355 + if (!Page_Uptodate(pg))
22356 + return yaffs_readpage_nolock(f, pg);
22361 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
22362 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
22363 + loff_t pos, unsigned len, unsigned copied,
22364 + struct page *pg, void *fsdadata)
22367 + void *addr, *kva;
22368 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
22371 + addr = kva + offset_into_page;
22373 + T(YAFFS_TRACE_OS,
22374 + ("yaffs_write_end addr %p pos %x n_bytes %d\n",
22375 + addr,(unsigned)pos, copied));
22377 + ret = yaffs_file_write(filp, addr, copied, &pos);
22379 + if (ret != copied) {
22380 + T(YAFFS_TRACE_OS,
22381 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
22383 + SetPageError(pg);
22390 + yaffs_release_space(filp);
22392 + page_cache_release(pg);
22397 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
22400 + void *addr, *kva;
22402 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
22403 + int n_bytes = to - offset;
22406 + unsigned spos = pos;
22410 + addr = kva + offset;
22412 + saddr = (unsigned) addr;
22414 + T(YAFFS_TRACE_OS,
22415 + (TSTR("yaffs_commit_write addr %x pos %x n_bytes %d\n"),
22416 + saddr, spos, n_bytes));
22418 + nWritten = yaffs_file_write(f, addr, n_bytes, &pos);
22420 + if (nWritten != n_bytes) {
22421 + T(YAFFS_TRACE_OS,
22422 + (TSTR("yaffs_commit_write not same size nWritten %d n_bytes %d\n"),
22423 + nWritten, n_bytes));
22424 + SetPageError(pg);
22431 + T(YAFFS_TRACE_OS,
22432 + (TSTR("yaffs_commit_write returning %d\n"),
22433 + nWritten == n_bytes ? 0 : nWritten));
22435 + return nWritten == n_bytes ? 0 : nWritten;
22440 +static void yaffs_fill_inode_from_obj(struct inode *inode, yaffs_obj_t *obj)
22442 + if (inode && obj) {
22445 + /* Check mode against the variant type and attempt to repair if broken. */
22446 + __u32 mode = obj->yst_mode;
22447 + switch (obj->variant_type) {
22448 + case YAFFS_OBJECT_TYPE_FILE:
22449 + if (!S_ISREG(mode)) {
22450 + obj->yst_mode &= ~S_IFMT;
22451 + obj->yst_mode |= S_IFREG;
22455 + case YAFFS_OBJECT_TYPE_SYMLINK:
22456 + if (!S_ISLNK(mode)) {
22457 + obj->yst_mode &= ~S_IFMT;
22458 + obj->yst_mode |= S_IFLNK;
22462 + case YAFFS_OBJECT_TYPE_DIRECTORY:
22463 + if (!S_ISDIR(mode)) {
22464 + obj->yst_mode &= ~S_IFMT;
22465 + obj->yst_mode |= S_IFDIR;
22469 + case YAFFS_OBJECT_TYPE_UNKNOWN:
22470 + case YAFFS_OBJECT_TYPE_HARDLINK:
22471 + case YAFFS_OBJECT_TYPE_SPECIAL:
22477 + inode->i_flags |= S_NOATIME;
22479 + inode->i_ino = obj->obj_id;
22480 + inode->i_mode = obj->yst_mode;
22481 + inode->i_uid = obj->yst_uid;
22482 + inode->i_gid = obj->yst_gid;
22483 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
22484 + inode->i_blksize = inode->i_sb->s_blocksize;
22486 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22488 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
22489 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
22490 + inode->i_atime.tv_nsec = 0;
22491 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
22492 + inode->i_mtime.tv_nsec = 0;
22493 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
22494 + inode->i_ctime.tv_nsec = 0;
22496 + inode->i_rdev = obj->yst_rdev;
22497 + inode->i_atime = obj->yst_atime;
22498 + inode->i_mtime = obj->yst_mtime;
22499 + inode->i_ctime = obj->yst_ctime;
22501 + inode->i_size = yaffs_get_obj_length(obj);
22502 + inode->i_blocks = (inode->i_size + 511) >> 9;
22504 + inode->i_nlink = yaffs_get_obj_link_count(obj);
22506 + T(YAFFS_TRACE_OS,
22507 + (TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
22508 + inode->i_mode, inode->i_uid, inode->i_gid,
22509 + (int)inode->i_size, atomic_read(&inode->i_count)));
22511 + switch (obj->yst_mode & S_IFMT) {
22512 + default: /* fifo, device or socket */
22513 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22514 + init_special_inode(inode, obj->yst_mode,
22515 + old_decode_dev(obj->yst_rdev));
22517 + init_special_inode(inode, obj->yst_mode,
22518 + (dev_t) (obj->yst_rdev));
22521 + case S_IFREG: /* file */
22522 + inode->i_op = &yaffs_file_inode_operations;
22523 + inode->i_fop = &yaffs_file_operations;
22524 + inode->i_mapping->a_ops =
22525 + &yaffs_file_address_operations;
22527 + case S_IFDIR: /* directory */
22528 + inode->i_op = &yaffs_dir_inode_operations;
22529 + inode->i_fop = &yaffs_dir_operations;
22531 + case S_IFLNK: /* symlink */
22532 + inode->i_op = &yaffs_symlink_inode_operations;
22536 + yaffs_InodeToObjectLV(inode) = obj;
22538 + obj->my_inode = inode;
22541 + T(YAFFS_TRACE_OS,
22542 + (TSTR("yaffs_FileInode invalid parameters\n")));
22547 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
22548 + yaffs_obj_t *obj)
22550 + struct inode *inode;
22553 + T(YAFFS_TRACE_OS,
22554 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
22560 + T(YAFFS_TRACE_OS,
22561 + (TSTR("yaffs_get_inode for NULL object!!\n")));
22566 + T(YAFFS_TRACE_OS,
22567 + (TSTR("yaffs_get_inode for object %d\n"), obj->obj_id));
22569 + inode = Y_IGET(sb, obj->obj_id);
22570 + if (IS_ERR(inode))
22573 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
22574 + /* iget also increments the inode's i_count */
22575 + /* NB You can't be holding grossLock or deadlock will happen! */
22580 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
22583 + yaffs_obj_t *obj;
22584 + int nWritten, ipos;
22585 + struct inode *inode;
22586 + yaffs_dev_t *dev;
22588 + obj = yaffs_dentry_to_obj(f->f_dentry);
22590 + dev = obj->my_dev;
22592 + yaffs_gross_lock(dev);
22594 + inode = f->f_dentry->d_inode;
22596 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
22597 + ipos = inode->i_size;
22602 + T(YAFFS_TRACE_OS,
22603 + (TSTR("yaffs_file_write: hey obj is null!\n")));
22605 + T(YAFFS_TRACE_OS,
22606 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
22607 + "to object %d at %d(%x)\n"),
22608 + (unsigned) n, (unsigned) n, obj->obj_id, ipos,ipos));
22610 + nWritten = yaffs_wr_file(obj, buf, ipos, n, 0);
22612 + yaffs_touch_super(dev);
22614 + T(YAFFS_TRACE_OS,
22615 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
22616 + (unsigned )n,(unsigned)n));
22618 + if (nWritten > 0) {
22619 + ipos += nWritten;
22621 + if (ipos > inode->i_size) {
22622 + inode->i_size = ipos;
22623 + inode->i_blocks = (ipos + 511) >> 9;
22625 + T(YAFFS_TRACE_OS,
22626 + (TSTR("yaffs_file_write size updated to %d bytes, "
22628 + ipos, (int)(inode->i_blocks)));
22632 + yaffs_gross_unlock(dev);
22633 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
22636 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
22637 +/* For now we just assume few parallel writes and check against a small number. */
22638 +/* Todo: need to do this with a counter to handle parallel reads better */
22640 +static ssize_t yaffs_hold_space(struct file *f)
22642 + yaffs_obj_t *obj;
22643 + yaffs_dev_t *dev;
22645 + int n_free_chunks;
22648 + obj = yaffs_dentry_to_obj(f->f_dentry);
22650 + dev = obj->my_dev;
22652 + yaffs_gross_lock(dev);
22654 + n_free_chunks = yaffs_get_n_free_chunks(dev);
22656 + yaffs_gross_unlock(dev);
22658 + return (n_free_chunks > 20) ? 1 : 0;
22661 +static void yaffs_release_space(struct file *f)
22663 + yaffs_obj_t *obj;
22664 + yaffs_dev_t *dev;
22667 + obj = yaffs_dentry_to_obj(f->f_dentry);
22669 + dev = obj->my_dev;
22671 + yaffs_gross_lock(dev);
22674 + yaffs_gross_unlock(dev);
22678 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
22680 + long long retval;
22686 + offset += i_size_read(file->f_path.dentry->d_inode);
22689 + offset += file->f_pos;
22691 + retval = -EINVAL;
22693 + if (offset >= 0){
22694 + if (offset != file->f_pos)
22695 + file->f_pos = offset;
22704 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
22706 + yaffs_obj_t *obj;
22707 + yaffs_dev_t *dev;
22708 + struct yaffs_SearchContext *sc;
22709 + struct inode *inode = f->f_dentry->d_inode;
22710 + unsigned long offset, curoffs;
22714 + char name[YAFFS_MAX_NAME_LENGTH + 1];
22716 + obj = yaffs_dentry_to_obj(f->f_dentry);
22717 + dev = obj->my_dev;
22719 + yaffs_gross_lock(dev);
22721 + yaffs_dev_to_lc(dev)->readdirProcess = current;
22723 + offset = f->f_pos;
22725 + sc = yaffs_NewSearch(obj);
22727 + retVal = -ENOMEM;
22731 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
22733 + if (offset == 0) {
22734 + T(YAFFS_TRACE_OS,
22735 + (TSTR("yaffs_readdir: entry . ino %d \n"),
22736 + (int)inode->i_ino));
22737 + yaffs_gross_unlock(dev);
22738 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
22739 + yaffs_gross_lock(dev);
22742 + yaffs_gross_lock(dev);
22746 + if (offset == 1) {
22747 + T(YAFFS_TRACE_OS,
22748 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
22749 + (int)f->f_dentry->d_parent->d_inode->i_ino));
22750 + yaffs_gross_unlock(dev);
22751 + if (filldir(dirent, "..", 2, offset,
22752 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
22753 + yaffs_gross_lock(dev);
22756 + yaffs_gross_lock(dev);
22763 + /* If the directory has changed since the open or last call to
22764 + readdir, rewind to after the 2 canned entries. */
22765 + if (f->f_version != inode->i_version) {
22767 + f->f_pos = offset;
22768 + f->f_version = inode->i_version;
22771 + while(sc->nextReturn){
22773 + l = sc->nextReturn;
22774 + if (curoffs >= offset) {
22775 + int this_inode = yaffs_get_obj_inode(l);
22776 + int this_type = yaffs_get_obj_type(l);
22778 + yaffs_get_obj_name(l, name,
22779 + YAFFS_MAX_NAME_LENGTH + 1);
22780 + T(YAFFS_TRACE_OS,
22781 + (TSTR("yaffs_readdir: %s inode %d\n"),
22782 + name, yaffs_get_obj_inode(l)));
22784 + yaffs_gross_unlock(dev);
22786 + if (filldir(dirent,
22792 + yaffs_gross_lock(dev);
22796 + yaffs_gross_lock(dev);
22801 + yaffs_search_advance(sc);
22805 + yaffs_search_end(sc);
22806 + yaffs_dev_to_lc(dev)->readdirProcess = NULL;
22807 + yaffs_gross_unlock(dev);
22815 + * File creation. Allocate an inode, and we're done..
22818 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
22819 +#define YCRED(x) x
22821 +#define YCRED(x) (x->cred)
22824 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22825 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
22828 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
22832 + struct inode *inode;
22834 + yaffs_obj_t *obj = NULL;
22835 + yaffs_dev_t *dev;
22837 + yaffs_obj_t *parent = yaffs_InodeToObject(dir);
22839 + int error = -ENOSPC;
22840 + uid_t uid = YCRED(current)->fsuid;
22841 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
22843 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
22847 + T(YAFFS_TRACE_OS,
22848 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
22849 + parent->obj_id, parent->variant_type));
22851 + T(YAFFS_TRACE_OS,
22852 + (TSTR("yaffs_mknod: could not get parent object\n")));
22856 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
22857 + "mode %x dev %x\n"),
22858 + dentry->d_name.name, mode, rdev));
22860 + dev = parent->my_dev;
22862 + yaffs_gross_lock(dev);
22864 + switch (mode & S_IFMT) {
22866 + /* Special (socket, fifo, device...) */
22867 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
22868 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22869 + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
22870 + gid, old_encode_dev(rdev));
22872 + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
22876 + case S_IFREG: /* file */
22877 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
22878 + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
22881 + case S_IFDIR: /* directory */
22882 + T(YAFFS_TRACE_OS,
22883 + (TSTR("yaffs_mknod: making directory\n")));
22884 + obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
22887 + case S_IFLNK: /* symlink */
22888 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
22889 + obj = NULL; /* Do we ever get here? */
22893 + /* Can not call yaffs_get_inode() with gross lock held */
22894 + yaffs_gross_unlock(dev);
22897 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
22898 + d_instantiate(dentry, inode);
22899 + update_dir_time(dir);
22900 + T(YAFFS_TRACE_OS,
22901 + (TSTR("yaffs_mknod created object %d count = %d\n"),
22902 + obj->obj_id, atomic_read(&inode->i_count)));
22904 + yaffs_fill_inode_from_obj(dir,parent);
22906 + T(YAFFS_TRACE_OS,
22907 + (TSTR("yaffs_mknod failed making object\n")));
22914 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
22917 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
22918 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
22922 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22923 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
22924 + struct nameidata *n)
22926 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
22929 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
22930 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
22933 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
22937 + yaffs_dev_t *dev;
22938 + yaffs_obj_t *obj;
22940 + T(YAFFS_TRACE_OS,
22941 + (TSTR("yaffs_unlink %d:%s\n"),
22942 + (int)(dir->i_ino),
22943 + dentry->d_name.name));
22944 + obj = yaffs_InodeToObject(dir);
22945 + dev = obj->my_dev;
22947 + yaffs_gross_lock(dev);
22949 + retVal = yaffs_unlinker(obj, dentry->d_name.name);
22951 + if (retVal == YAFFS_OK) {
22952 + dentry->d_inode->i_nlink--;
22953 + dir->i_version++;
22954 + yaffs_gross_unlock(dev);
22955 + mark_inode_dirty(dentry->d_inode);
22956 + update_dir_time(dir);
22959 + yaffs_gross_unlock(dev);
22960 + return -ENOTEMPTY;
22964 + * Create a link...
22966 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
22967 + struct dentry *dentry)
22969 + struct inode *inode = old_dentry->d_inode;
22970 + yaffs_obj_t *obj = NULL;
22971 + yaffs_obj_t *link = NULL;
22972 + yaffs_dev_t *dev;
22974 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
22976 + obj = yaffs_InodeToObject(inode);
22977 + dev = obj->my_dev;
22979 + yaffs_gross_lock(dev);
22981 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
22982 + link = yaffs_link_obj(yaffs_InodeToObject(dir), dentry->d_name.name,
22986 + old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
22987 + d_instantiate(dentry, old_dentry->d_inode);
22988 + atomic_inc(&old_dentry->d_inode->i_count);
22989 + T(YAFFS_TRACE_OS,
22990 + (TSTR("yaffs_link link count %d i_count %d\n"),
22991 + old_dentry->d_inode->i_nlink,
22992 + atomic_read(&old_dentry->d_inode->i_count)));
22995 + yaffs_gross_unlock(dev);
22998 + update_dir_time(dir);
23005 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
23006 + const char *symname)
23008 + yaffs_obj_t *obj;
23009 + yaffs_dev_t *dev;
23010 + uid_t uid = YCRED(current)->fsuid;
23011 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
23013 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
23015 + dev = yaffs_InodeToObject(dir)->my_dev;
23016 + yaffs_gross_lock(dev);
23017 + obj = yaffs_create_symlink(yaffs_InodeToObject(dir), dentry->d_name.name,
23018 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
23019 + yaffs_gross_unlock(dev);
23022 + struct inode *inode;
23024 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
23025 + d_instantiate(dentry, inode);
23026 + update_dir_time(dir);
23027 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
23030 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
23036 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
23037 +static int yaffs_sync_object(struct file *file, int datasync)
23039 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
23044 + yaffs_obj_t *obj;
23045 + yaffs_dev_t *dev;
23046 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
23047 + struct dentry *dentry = file->f_path.dentry;
23050 + obj = yaffs_dentry_to_obj(dentry);
23052 + dev = obj->my_dev;
23054 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
23055 + (TSTR("yaffs_sync_object\n")));
23056 + yaffs_gross_lock(dev);
23057 + yaffs_flush_file(obj, 1, datasync);
23058 + yaffs_gross_unlock(dev);
23063 + * The VFS layer already does all the dentry stuff for rename.
23065 + * NB: POSIX says you can rename an object over an old object of the same name
23067 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
23068 + struct inode *new_dir, struct dentry *new_dentry)
23070 + yaffs_dev_t *dev;
23071 + int retVal = YAFFS_FAIL;
23072 + yaffs_obj_t *target;
23074 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
23075 + dev = yaffs_InodeToObject(old_dir)->my_dev;
23077 + yaffs_gross_lock(dev);
23079 + /* Check if the target is an existing directory that is not empty. */
23080 + target = yaffs_find_by_name(yaffs_InodeToObject(new_dir),
23081 + new_dentry->d_name.name);
23085 + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
23086 + !ylist_empty(&target->variant.dir_variant.children)) {
23088 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
23090 + retVal = YAFFS_FAIL;
23092 + /* Now does unlinking internally using shadowing mechanism */
23093 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_rename_obj\n")));
23095 + retVal = yaffs_rename_obj(yaffs_InodeToObject(old_dir),
23096 + old_dentry->d_name.name,
23097 + yaffs_InodeToObject(new_dir),
23098 + new_dentry->d_name.name);
23100 + yaffs_gross_unlock(dev);
23102 + if (retVal == YAFFS_OK) {
23104 + new_dentry->d_inode->i_nlink--;
23105 + mark_inode_dirty(new_dentry->d_inode);
23108 + update_dir_time(old_dir);
23109 + if(old_dir != new_dir)
23110 + update_dir_time(new_dir);
23113 + return -ENOTEMPTY;
23117 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
23119 + struct inode *inode = dentry->d_inode;
23121 + yaffs_dev_t *dev;
23123 + T(YAFFS_TRACE_OS,
23124 + (TSTR("yaffs_setattr of object %d\n"),
23125 + yaffs_InodeToObject(inode)->obj_id));
23127 + /* Fail if a requested resize >= 2GB */
23128 + if (attr->ia_valid & ATTR_SIZE &&
23129 + (attr->ia_size >> 31))
23133 + error = inode_change_ok(inode, attr);
23134 + if (error == 0) {
23137 + error = yaffs_vfs_setattr(inode, attr);
23138 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
23139 + if (attr->ia_valid & ATTR_SIZE){
23140 + yaffs_vfs_setsize(inode,attr->ia_size);
23141 + inode->i_blocks = (inode->i_size + 511) >> 9;
23144 + dev = yaffs_InodeToObject(inode)->my_dev;
23145 + if (attr->ia_valid & ATTR_SIZE){
23146 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
23147 + (int)(attr->ia_size),(int)(attr->ia_size)));
23149 + yaffs_gross_lock(dev);
23150 + result = yaffs_set_attribs(yaffs_InodeToObject(inode), attr);
23151 + if(result == YAFFS_OK) {
23156 + yaffs_gross_unlock(dev);
23160 + T(YAFFS_TRACE_OS,
23161 + (TSTR("yaffs_setattr done returning %d\n"),error));
23166 +#ifdef CONFIG_YAFFS_XATTR
23167 +int yaffs_setxattr(struct dentry *dentry, const char *name,
23168 + const void *value, size_t size, int flags)
23170 + struct inode *inode = dentry->d_inode;
23172 + yaffs_dev_t *dev;
23173 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23175 + T(YAFFS_TRACE_OS,
23176 + (TSTR("yaffs_setxattr of object %d\n"),
23180 + if (error == 0) {
23182 + dev = obj->my_dev;
23183 + yaffs_gross_lock(dev);
23184 + result = yaffs_set_xattrib(obj, name, value, size, flags);
23185 + if(result == YAFFS_OK)
23187 + else if(result < 0)
23189 + yaffs_gross_unlock(dev);
23192 + T(YAFFS_TRACE_OS,
23193 + (TSTR("yaffs_setxattr done returning %d\n"),error));
23199 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
23202 + struct inode *inode = dentry->d_inode;
23204 + yaffs_dev_t *dev;
23205 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23207 + T(YAFFS_TRACE_OS,
23208 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
23209 + name, obj->obj_id));
23211 + if (error == 0) {
23212 + dev = obj->my_dev;
23213 + yaffs_gross_lock(dev);
23214 + error = yaffs_get_xattrib(obj, name, buff, size);
23215 + yaffs_gross_unlock(dev);
23218 + T(YAFFS_TRACE_OS,
23219 + (TSTR("yaffs_getxattr done returning %d\n"),error));
23224 +int yaffs_removexattr(struct dentry *dentry, const char *name)
23226 + struct inode *inode = dentry->d_inode;
23228 + yaffs_dev_t *dev;
23229 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23231 + T(YAFFS_TRACE_OS,
23232 + (TSTR("yaffs_removexattr of object %d\n"),
23236 + if (error == 0) {
23238 + dev = obj->my_dev;
23239 + yaffs_gross_lock(dev);
23240 + result = yaffs_remove_xattrib(obj, name);
23241 + if(result == YAFFS_OK)
23243 + else if(result < 0)
23245 + yaffs_gross_unlock(dev);
23248 + T(YAFFS_TRACE_OS,
23249 + (TSTR("yaffs_removexattr done returning %d\n"),error));
23254 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
23256 + struct inode *inode = dentry->d_inode;
23258 + yaffs_dev_t *dev;
23259 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23261 + T(YAFFS_TRACE_OS,
23262 + (TSTR("yaffs_listxattr of object %d\n"),
23266 + if (error == 0) {
23267 + dev = obj->my_dev;
23268 + yaffs_gross_lock(dev);
23269 + error = yaffs_list_xattrib(obj, buff, size);
23270 + yaffs_gross_unlock(dev);
23273 + T(YAFFS_TRACE_OS,
23274 + (TSTR("yaffs_listxattr done returning %d\n"),error));
23282 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23283 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
23285 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
23286 + struct super_block *sb = dentry->d_sb;
23287 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23288 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
23290 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23292 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
23294 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23297 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
23299 + yaffs_gross_lock(dev);
23301 + buf->f_type = YAFFS_MAGIC;
23302 + buf->f_bsize = sb->s_blocksize;
23303 + buf->f_namelen = 255;
23305 + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
23306 + /* Do this if chunk size is not a power of 2 */
23308 + uint64_t bytesInDev;
23309 + uint64_t bytesFree;
23311 + bytesInDev = ((uint64_t)((dev->param.end_block - dev->param.start_block + 1))) *
23312 + ((uint64_t)(dev->param.chunks_per_block * dev->data_bytes_per_chunk));
23314 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
23315 + buf->f_blocks = bytesInDev;
23317 + bytesFree = ((uint64_t)(yaffs_get_n_free_chunks(dev))) *
23318 + ((uint64_t)(dev->data_bytes_per_chunk));
23320 + do_div(bytesFree, sb->s_blocksize);
23322 + buf->f_bfree = bytesFree;
23324 + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
23327 + (dev->param.end_block - dev->param.start_block + 1) *
23328 + dev->param.chunks_per_block /
23329 + (sb->s_blocksize / dev->data_bytes_per_chunk);
23331 + yaffs_get_n_free_chunks(dev) /
23332 + (sb->s_blocksize / dev->data_bytes_per_chunk);
23335 + (dev->param.end_block - dev->param.start_block + 1) *
23336 + dev->param.chunks_per_block *
23337 + (dev->data_bytes_per_chunk / sb->s_blocksize);
23340 + yaffs_get_n_free_chunks(dev) *
23341 + (dev->data_bytes_per_chunk / sb->s_blocksize);
23344 + buf->f_files = 0;
23345 + buf->f_ffree = 0;
23346 + buf->f_bavail = buf->f_bfree;
23348 + yaffs_gross_unlock(dev);
23354 +static void yaffs_flush_inodes(struct super_block *sb)
23356 + struct inode *iptr;
23357 + yaffs_obj_t *obj;
23359 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
23360 + obj = yaffs_InodeToObject(iptr);
23362 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
23364 + yaffs_flush_file(obj,1,0);
23370 +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
23372 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23376 + yaffs_flush_inodes(sb);
23377 + yaffs_update_dirty_dirs(dev);
23378 + yaffs_flush_whole_cache(dev);
23379 + if(do_checkpoint)
23380 + yaffs_checkpoint_save(dev);
23384 +static unsigned yaffs_bg_gc_urgency(yaffs_dev_t *dev)
23386 + unsigned erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
23387 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23388 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
23390 + if(erasedChunks < dev->n_free_chunks)
23391 + scatteredFree = (dev->n_free_chunks - erasedChunks);
23393 + if(!context->bgRunning)
23395 + else if(scatteredFree < (dev->param.chunks_per_block * 2))
23397 + else if(erasedChunks > dev->n_free_chunks/2)
23399 + else if(erasedChunks > dev->n_free_chunks/4)
23405 +static int yaffs_do_sync_fs(struct super_block *sb,
23406 + int request_checkpoint)
23409 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23410 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
23411 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
23412 + int do_checkpoint;
23414 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
23415 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
23417 + sb->s_dirt ? "dirty" : "clean",
23418 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
23419 + oneshot_checkpoint ? " one-shot" : "" ));
23421 + yaffs_gross_lock(dev);
23422 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
23423 + oneshot_checkpoint) &&
23424 + !dev->is_checkpointed;
23426 + if (sb->s_dirt || do_checkpoint) {
23427 + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
23429 + if(oneshot_checkpoint)
23430 + yaffs_auto_checkpoint &= ~4;
23432 + yaffs_gross_unlock(dev);
23438 + * yaffs background thread functions .
23439 + * yaffs_bg_thread_fn() the thread function
23440 + * yaffs_bg_start() launches the background thread.
23441 + * yaffs_bg_stop() cleans up the background thread.
23444 + * The thread should only run after the yaffs is initialised
23445 + * The thread should be stopped before yaffs is unmounted.
23446 + * The thread should not do any writing while the fs is in read only.
23449 +#ifdef YAFFS_COMPILE_BACKGROUND
23451 +void yaffs_background_waker(unsigned long data)
23453 + wake_up_process((struct task_struct *)data);
23456 +static int yaffs_bg_thread_fn(void *data)
23458 + yaffs_dev_t *dev = (yaffs_dev_t *)data;
23459 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23460 + unsigned long now = jiffies;
23461 + unsigned long next_dir_update = now;
23462 + unsigned long next_gc = now;
23463 + unsigned long expires;
23464 + unsigned int urgency;
23467 + struct timer_list timer;
23469 + T(YAFFS_TRACE_BACKGROUND,
23470 + (TSTR("yaffs_background starting for dev %p\n"),
23473 +#ifdef YAFFS_COMPILE_FREEZER
23476 + while(context->bgRunning){
23477 + T(YAFFS_TRACE_BACKGROUND,
23478 + (TSTR("yaffs_background\n")));
23480 + if(kthread_should_stop())
23483 +#ifdef YAFFS_COMPILE_FREEZER
23484 + if(try_to_freeze())
23487 + yaffs_gross_lock(dev);
23491 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
23492 + yaffs_update_dirty_dirs(dev);
23493 + next_dir_update = now + HZ;
23496 + if(time_after(now,next_gc) && yaffs_bg_enable){
23497 + if(!dev->is_checkpointed){
23498 + urgency = yaffs_bg_gc_urgency(dev);
23499 + gcResult = yaffs_bg_gc(dev, urgency);
23501 + next_gc = now + HZ/20+1;
23502 + else if(urgency > 0)
23503 + next_gc = now + HZ/10+1;
23505 + next_gc = now + HZ * 2;
23507 + * gc not running so set to next_dir_update
23508 + * to cut down on wake ups
23510 + next_gc = next_dir_update;
23512 + yaffs_gross_unlock(dev);
23514 + expires = next_dir_update;
23515 + if (time_before(next_gc,expires))
23516 + expires = next_gc;
23517 + if(time_before(expires,now))
23518 + expires = now + HZ;
23520 + Y_INIT_TIMER(&timer);
23521 + timer.expires = expires+1;
23522 + timer.data = (unsigned long) current;
23523 + timer.function = yaffs_background_waker;
23525 + set_current_state(TASK_INTERRUPTIBLE);
23526 + add_timer(&timer);
23528 + del_timer_sync(&timer);
23537 +static int yaffs_bg_start(yaffs_dev_t *dev)
23540 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23542 + if(dev->read_only)
23545 + context->bgRunning = 1;
23547 + context->bgThread = kthread_run(yaffs_bg_thread_fn,
23548 + (void *)dev,"yaffs-bg-%d",context->mount_id);
23550 + if(IS_ERR(context->bgThread)){
23551 + retval = PTR_ERR(context->bgThread);
23552 + context->bgThread = NULL;
23553 + context->bgRunning = 0;
23558 +static void yaffs_bg_stop(yaffs_dev_t *dev)
23560 + struct yaffs_LinuxContext *ctxt = yaffs_dev_to_lc(dev);
23562 + ctxt->bgRunning = 0;
23564 + if( ctxt->bgThread){
23565 + kthread_stop(ctxt->bgThread);
23566 + ctxt->bgThread = NULL;
23570 +static int yaffs_bg_thread_fn(void *data)
23575 +static int yaffs_bg_start(yaffs_dev_t *dev)
23580 +static void yaffs_bg_stop(yaffs_dev_t *dev)
23586 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23587 +static void yaffs_write_super(struct super_block *sb)
23589 +static int yaffs_write_super(struct super_block *sb)
23592 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
23594 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
23595 + (TSTR("yaffs_write_super%s\n"),
23596 + request_checkpoint ? " checkpt" : ""));
23598 + yaffs_do_sync_fs(sb, request_checkpoint);
23600 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
23606 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23607 +static int yaffs_sync_fs(struct super_block *sb, int wait)
23609 +static int yaffs_sync_fs(struct super_block *sb)
23612 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
23614 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
23615 + (TSTR("yaffs_sync_fs%s\n"),
23616 + request_checkpoint ? " checkpt" : ""));
23618 + yaffs_do_sync_fs(sb, request_checkpoint);
23623 +#ifdef YAFFS_USE_OWN_IGET
23625 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
23627 + struct inode *inode;
23628 + yaffs_obj_t *obj;
23629 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23631 + T(YAFFS_TRACE_OS,
23632 + (TSTR("yaffs_iget for %lu\n"), ino));
23634 + inode = iget_locked(sb, ino);
23636 + return ERR_PTR(-ENOMEM);
23637 + if (!(inode->i_state & I_NEW))
23640 + /* NB This is called as a side effect of other functions, but
23641 + * we had to release the lock to prevent deadlocks, so
23642 + * need to lock again.
23645 + yaffs_gross_lock(dev);
23647 + obj = yaffs_find_by_number(dev, inode->i_ino);
23649 + yaffs_fill_inode_from_obj(inode, obj);
23651 + yaffs_gross_unlock(dev);
23653 + unlock_new_inode(inode);
23659 +static void yaffs_read_inode(struct inode *inode)
23661 + /* NB This is called as a side effect of other functions, but
23662 + * we had to release the lock to prevent deadlocks, so
23663 + * need to lock again.
23666 + yaffs_obj_t *obj;
23667 + yaffs_dev_t *dev = yaffs_SuperToDevice(inode->i_sb);
23669 + T(YAFFS_TRACE_OS,
23670 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
23672 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
23673 + yaffs_gross_lock(dev);
23675 + obj = yaffs_find_by_number(dev, inode->i_ino);
23677 + yaffs_fill_inode_from_obj(inode, obj);
23679 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
23680 + yaffs_gross_unlock(dev);
23685 +static YLIST_HEAD(yaffs_context_list);
23686 +struct semaphore yaffs_context_lock;
23688 +static void yaffs_put_super(struct super_block *sb)
23690 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23692 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
23694 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
23695 + (TSTR("Shutting down yaffs background thread\n")));
23696 + yaffs_bg_stop(dev);
23697 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
23698 + (TSTR("yaffs background thread shut down\n")));
23700 + yaffs_gross_lock(dev);
23702 + yaffs_flush_super(sb,1);
23704 + if (yaffs_dev_to_lc(dev)->putSuperFunc)
23705 + yaffs_dev_to_lc(dev)->putSuperFunc(sb);
23708 + yaffs_deinitialise(dev);
23710 + yaffs_gross_unlock(dev);
23712 + down(&yaffs_context_lock);
23713 + ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
23714 + up(&yaffs_context_lock);
23716 + if (yaffs_dev_to_lc(dev)->spareBuffer) {
23717 + YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
23718 + yaffs_dev_to_lc(dev)->spareBuffer = NULL;
23725 +static void yaffs_MTDPutSuper(struct super_block *sb)
23727 + struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb));
23732 + put_mtd_device(mtd);
23736 +static void yaffs_touch_super(yaffs_dev_t *dev)
23738 + struct super_block *sb = yaffs_dev_to_lc(dev)->superBlock;
23740 + T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
23747 + int skip_checkpoint_read;
23748 + int skip_checkpoint_write;
23751 + int tags_ecc_overridden;
23752 + int lazy_loading_enabled;
23753 + int lazy_loading_overridden;
23754 + int empty_lost_and_found;
23755 + int empty_lost_and_found_overridden;
23758 +#define MAX_OPT_LEN 30
23759 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
23761 + char cur_opt[MAX_OPT_LEN + 1];
23765 + /* Parse through the options which is a comma seperated list */
23767 + while (options_str && *options_str && !error) {
23768 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
23771 + while(*options_str == ',')
23774 + while (*options_str && *options_str != ',') {
23775 + if (p < MAX_OPT_LEN) {
23776 + cur_opt[p] = *options_str;
23782 + if (!strcmp(cur_opt, "inband-tags"))
23783 + options->inband_tags = 1;
23784 + else if (!strcmp(cur_opt, "tags-ecc-off")){
23785 + options->tags_ecc_on = 0;
23786 + options->tags_ecc_overridden=1;
23787 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
23788 + options->tags_ecc_on = 1;
23789 + options->tags_ecc_overridden = 1;
23790 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
23791 + options->lazy_loading_enabled = 0;
23792 + options->lazy_loading_overridden=1;
23793 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
23794 + options->lazy_loading_enabled = 1;
23795 + options->lazy_loading_overridden = 1;
23796 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
23797 + options->empty_lost_and_found = 0;
23798 + options->empty_lost_and_found_overridden=1;
23799 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
23800 + options->empty_lost_and_found = 1;
23801 + options->empty_lost_and_found_overridden=1;
23802 + } else if (!strcmp(cur_opt, "no-cache"))
23803 + options->no_cache = 1;
23804 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
23805 + options->skip_checkpoint_read = 1;
23806 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
23807 + options->skip_checkpoint_write = 1;
23808 + else if (!strcmp(cur_opt, "no-checkpoint")) {
23809 + options->skip_checkpoint_read = 1;
23810 + options->skip_checkpoint_write = 1;
23812 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
23821 +static struct super_block *yaffs_internal_read_super(int yaffs_version,
23822 + struct super_block *sb,
23823 + void *data, int silent)
23826 + struct inode *inode = NULL;
23827 + struct dentry *root;
23828 + yaffs_dev_t *dev = 0;
23829 + char devname_buf[BDEVNAME_SIZE + 1];
23830 + struct mtd_info *mtd;
23832 + char *data_str = (char *)data;
23833 + struct yaffs_LinuxContext *context = NULL;
23834 + yaffs_param_t *param;
23836 + int read_only = 0;
23838 + yaffs_options options;
23840 + unsigned mount_id;
23842 + struct yaffs_LinuxContext *context_iterator;
23843 + struct ylist_head *l;
23845 + sb->s_magic = YAFFS_MAGIC;
23846 + sb->s_op = &yaffs_super_ops;
23847 + sb->s_flags |= MS_NOATIME;
23849 + read_only =((sb->s_flags & MS_RDONLY) != 0);
23852 +#ifdef YAFFS_COMPILE_EXPORTFS
23853 + sb->s_export_op = &yaffs_export_ops;
23857 + printk(KERN_INFO "yaffs: sb is NULL\n");
23858 + else if (!sb->s_dev)
23859 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
23860 + else if (!yaffs_devname(sb, devname_buf))
23861 + printk(KERN_INFO "yaffs: devname is NULL\n");
23863 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
23865 + yaffs_devname(sb, devname_buf),
23866 + read_only ? "ro" : "rw");
23871 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
23873 + memset(&options, 0, sizeof(options));
23875 + if (yaffs_parse_options(&options, data_str)) {
23876 + /* Option parsing failed */
23881 + sb->s_blocksize = PAGE_CACHE_SIZE;
23882 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
23884 + T(YAFFS_TRACE_OS,
23885 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffs_version));
23886 + T(YAFFS_TRACE_OS,
23887 + (TSTR("yaffs_read_super: block size %d\n"),
23888 + (int)(sb->s_blocksize)));
23890 + T(YAFFS_TRACE_ALWAYS,
23891 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
23892 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
23893 + yaffs_devname(sb, devname_buf)));
23895 + /* Check it's an mtd device..... */
23896 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
23897 + return NULL; /* This isn't an mtd device */
23899 + /* Get the device */
23900 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
23902 + T(YAFFS_TRACE_ALWAYS,
23903 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
23904 + MINOR(sb->s_dev)));
23907 + /* Check it's NAND */
23908 + if (mtd->type != MTD_NANDFLASH) {
23909 + T(YAFFS_TRACE_ALWAYS,
23910 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
23915 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
23916 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
23917 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
23918 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
23919 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
23920 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
23921 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
23922 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
23923 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
23924 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
23925 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
23926 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
23928 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
23931 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
23933 + if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
23934 + T(YAFFS_TRACE_ALWAYS,
23935 + (TSTR("yaffs: auto selecting yaffs2\n")));
23936 + yaffs_version = 2;
23939 + /* Added NCB 26/5/2006 for completeness */
23940 + if (yaffs_version == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
23941 + T(YAFFS_TRACE_ALWAYS,
23942 + (TSTR("yaffs: auto selecting yaffs1\n")));
23943 + yaffs_version = 1;
23948 + if (yaffs_version == 2) {
23949 + /* Check for version 2 style functions */
23950 + if (!mtd->erase ||
23951 + !mtd->block_isbad ||
23952 + !mtd->block_markbad ||
23955 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23956 + !mtd->read_oob || !mtd->write_oob) {
23958 + !mtd->write_ecc ||
23959 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
23961 + T(YAFFS_TRACE_ALWAYS,
23962 + (TSTR("yaffs: MTD device does not support required "
23963 + "functions\n")));
23967 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
23968 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
23969 + !options.inband_tags) {
23970 + T(YAFFS_TRACE_ALWAYS,
23971 + (TSTR("yaffs: MTD device does not have the "
23972 + "right page sizes\n")));
23976 + /* Check for V1 style functions */
23977 + if (!mtd->erase ||
23980 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23981 + !mtd->read_oob || !mtd->write_oob) {
23983 + !mtd->write_ecc ||
23984 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
23986 + T(YAFFS_TRACE_ALWAYS,
23987 + (TSTR("yaffs: MTD device does not support required "
23988 + "functions\n")));
23992 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
23993 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
23994 + T(YAFFS_TRACE_ALWAYS,
23995 + (TSTR("yaffs: MTD device does not support have the "
23996 + "right page sizes\n")));
24001 + /* OK, so if we got here, we have an MTD that's NAND and looks
24002 + * like it has the right capabilities
24003 + * Set the yaffs_dev_t up for mtd
24006 + if (!read_only && !(mtd->flags & MTD_WRITEABLE)){
24008 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
24009 + sb->s_flags |= MS_RDONLY;
24012 + dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL);
24013 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
24015 + if(!dev || !context ){
24025 + /* Deep shit could not allocate device structure */
24026 + T(YAFFS_TRACE_ALWAYS,
24027 + (TSTR("yaffs_read_super: Failed trying to allocate "
24028 + "yaffs_dev_t. \n")));
24031 + memset(dev, 0, sizeof(yaffs_dev_t));
24032 + param = &(dev->param);
24034 + memset(context,0,sizeof(struct yaffs_LinuxContext));
24035 + dev->os_context = context;
24036 + YINIT_LIST_HEAD(&(context->contextList));
24037 + context->dev = dev;
24038 + context->superBlock = sb;
24040 + dev->read_only = read_only;
24042 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24043 + sb->s_fs_info = dev;
24045 + sb->u.generic_sbp = dev;
24048 + dev->driver_context = mtd;
24049 + param->name = mtd->name;
24051 + /* Set up the memory size parameters.... */
24053 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
24055 + param->start_block = 0;
24056 + param->end_block = nBlocks - 1;
24057 + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
24058 + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
24059 + param->n_reserved_blocks = 5;
24060 + param->n_caches = (options.no_cache) ? 0 : 10;
24061 + param->inband_tags = options.inband_tags;
24063 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
24064 + param->disable_lazy_load = 1;
24066 +#ifdef CONFIG_YAFFS_XATTR
24067 + param->enable_xattr = 1;
24069 + if(options.lazy_loading_overridden)
24070 + param->disable_lazy_load = !options.lazy_loading_enabled;
24072 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
24073 + param->no_tags_ecc = 1;
24076 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
24078 + param->defered_dir_update = 1;
24081 + if(options.tags_ecc_overridden)
24082 + param->no_tags_ecc = !options.tags_ecc_on;
24084 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
24085 + param->empty_lost_n_found = 1;
24088 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
24089 + param->refresh_period = 0;
24091 + param->refresh_period = 500;
24094 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
24095 + param->always_check_erased = 1;
24098 + if(options.empty_lost_and_found_overridden)
24099 + param->empty_lost_n_found = options.empty_lost_and_found;
24101 + /* ... and the functions. */
24102 + if (yaffs_version == 2) {
24103 + param->write_chunk_tags_fn =
24104 + nandmtd2_WriteChunkWithTagsToNAND;
24105 + param->read_chunk_tags_fn =
24106 + nandmtd2_ReadChunkWithTagsFromNAND;
24107 + param->bad_block_fn = nandmtd2_MarkNANDBlockBad;
24108 + param->query_block_fn = nandmtd2_QueryNANDBlock;
24109 + yaffs_dev_to_lc(dev)->spareBuffer = YMALLOC(mtd->oobsize);
24110 + param->is_yaffs2 = 1;
24111 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24112 + param->total_bytes_per_chunk = mtd->writesize;
24113 + param->chunks_per_block = mtd->erasesize / mtd->writesize;
24115 + param->total_bytes_per_chunk = mtd->oobblock;
24116 + param->chunks_per_block = mtd->erasesize / mtd->oobblock;
24118 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
24120 + param->start_block = 0;
24121 + param->end_block = nBlocks - 1;
24123 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24124 + /* use the MTD interface in yaffs_mtdif1.c */
24125 + param->write_chunk_tags_fn =
24126 + nandmtd1_WriteChunkWithTagsToNAND;
24127 + param->read_chunk_tags_fn =
24128 + nandmtd1_ReadChunkWithTagsFromNAND;
24129 + param->bad_block_fn = nandmtd1_MarkNANDBlockBad;
24130 + param->query_block_fn = nandmtd1_QueryNANDBlock;
24132 + param->write_chunk_fn = nandmtd_WriteChunkToNAND;
24133 + param->read_chunk_fn = nandmtd_ReadChunkFromNAND;
24135 + param->is_yaffs2 = 0;
24137 + /* ... and common functions */
24138 + param->erase_fn = nandmtd_EraseBlockInNAND;
24139 + param->initialise_flash_fn = nandmtd_InitialiseNAND;
24141 + yaffs_dev_to_lc(dev)->putSuperFunc = yaffs_MTDPutSuper;
24143 + param->sb_dirty_fn = yaffs_touch_super;
24144 + param->gc_control = yaffs_gc_control_callback;
24146 + yaffs_dev_to_lc(dev)->superBlock= sb;
24149 +#ifndef CONFIG_YAFFS_DOES_ECC
24150 + param->use_nand_ecc = 1;
24153 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
24154 + param->wide_tnodes_disabled = 1;
24157 + param->skip_checkpt_rd = options.skip_checkpoint_read;
24158 + param->skip_checkpt_wr = options.skip_checkpoint_write;
24160 + down(&yaffs_context_lock);
24161 + /* Get a mount id */
24163 + for(mount_id=0; ! found; mount_id++){
24165 + ylist_for_each(l,&yaffs_context_list){
24166 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
24167 + if(context_iterator->mount_id == mount_id)
24171 + context->mount_id = mount_id;
24173 + ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
24174 + up(&yaffs_context_lock);
24176 + /* Directory search handling...*/
24177 + YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts));
24178 + param->remove_obj_fn = yaffs_remove_obj_callback;
24180 + init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock));
24182 + yaffs_gross_lock(dev);
24184 + err = yaffs_guts_initialise(dev);
24186 + T(YAFFS_TRACE_OS,
24187 + (TSTR("yaffs_read_super: guts initialised %s\n"),
24188 + (err == YAFFS_OK) ? "OK" : "FAILED"));
24190 + if(err == YAFFS_OK)
24191 + yaffs_bg_start(dev);
24193 + if(!context->bgThread)
24194 + param->defered_dir_update = 0;
24197 + /* Release lock before yaffs_get_inode() */
24198 + yaffs_gross_unlock(dev);
24200 + /* Create root inode */
24201 + if (err == YAFFS_OK)
24202 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
24203 + yaffs_root(dev));
24208 + inode->i_op = &yaffs_dir_inode_operations;
24209 + inode->i_fop = &yaffs_dir_operations;
24211 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
24213 + root = d_alloc_root(inode);
24215 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
24221 + sb->s_root = root;
24222 + sb->s_dirt = !dev->is_checkpointed;
24223 + T(YAFFS_TRACE_ALWAYS,
24224 + (TSTR("yaffs_read_super: is_checkpointed %d\n"),
24225 + dev->is_checkpointed));
24227 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
24232 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24233 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
24236 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
24239 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24240 +static int yaffs_read_super(struct file_system_type *fs,
24241 + int flags, const char *dev_name,
24242 + void *data, struct vfsmount *mnt)
24245 + return get_sb_bdev(fs, flags, dev_name, data,
24246 + yaffs_internal_read_super_mtd, mnt);
24249 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
24250 + int flags, const char *dev_name,
24254 + return get_sb_bdev(fs, flags, dev_name, data,
24255 + yaffs_internal_read_super_mtd);
24259 +static struct file_system_type yaffs_fs_type = {
24260 + .owner = THIS_MODULE,
24262 + .get_sb = yaffs_read_super,
24263 + .kill_sb = kill_block_super,
24264 + .fs_flags = FS_REQUIRES_DEV,
24267 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
24270 + return yaffs_internal_read_super(1, sb, data, silent);
24273 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
24274 + FS_REQUIRES_DEV);
24278 +#ifdef CONFIG_YAFFS_YAFFS2
24280 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24281 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
24284 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
24287 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24288 +static int yaffs2_read_super(struct file_system_type *fs,
24289 + int flags, const char *dev_name, void *data,
24290 + struct vfsmount *mnt)
24292 + return get_sb_bdev(fs, flags, dev_name, data,
24293 + yaffs2_internal_read_super_mtd, mnt);
24296 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
24297 + int flags, const char *dev_name,
24301 + return get_sb_bdev(fs, flags, dev_name, data,
24302 + yaffs2_internal_read_super_mtd);
24306 +static struct file_system_type yaffs2_fs_type = {
24307 + .owner = THIS_MODULE,
24308 + .name = "yaffs2",
24309 + .get_sb = yaffs2_read_super,
24310 + .kill_sb = kill_block_super,
24311 + .fs_flags = FS_REQUIRES_DEV,
24314 +static struct super_block *yaffs2_read_super(struct super_block *sb,
24315 + void *data, int silent)
24317 + return yaffs_internal_read_super(2, sb, data, silent);
24320 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
24321 + FS_REQUIRES_DEV);
24324 +#endif /* CONFIG_YAFFS_YAFFS2 */
24326 +static struct proc_dir_entry *my_proc_entry;
24327 +static struct proc_dir_entry *debug_proc_entry;
24329 +static char *yaffs_dump_dev_part0(char *buf, yaffs_dev_t * dev)
24331 + buf += sprintf(buf, "start_block.......... %d\n", dev->param.start_block);
24332 + buf += sprintf(buf, "end_block............ %d\n", dev->param.end_block);
24333 + buf += sprintf(buf, "total_bytes_per_chunk %d\n", dev->param.total_bytes_per_chunk);
24334 + buf += sprintf(buf, "use_nand_ecc......... %d\n", dev->param.use_nand_ecc);
24335 + buf += sprintf(buf, "no_tags_ecc.......... %d\n", dev->param.no_tags_ecc);
24336 + buf += sprintf(buf, "is_yaffs2............ %d\n", dev->param.is_yaffs2);
24337 + buf += sprintf(buf, "inband_tags.......... %d\n", dev->param.inband_tags);
24338 + buf += sprintf(buf, "empty_lost_n_found... %d\n", dev->param.empty_lost_n_found);
24339 + buf += sprintf(buf, "disable_lazy_load.... %d\n", dev->param.disable_lazy_load);
24340 + buf += sprintf(buf, "refresh_period....... %d\n", dev->param.refresh_period);
24341 + buf += sprintf(buf, "n_caches............. %d\n", dev->param.n_caches);
24342 + buf += sprintf(buf, "n_reserved_blocks.... %d\n", dev->param.n_reserved_blocks);
24343 + buf += sprintf(buf, "always_check_erased.. %d\n", dev->param.always_check_erased);
24345 + buf += sprintf(buf, "\n");
24351 +static char *yaffs_dump_dev_part1(char *buf, yaffs_dev_t * dev)
24353 + buf += sprintf(buf, "data_bytes_per_chunk. %d\n", dev->data_bytes_per_chunk);
24354 + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
24355 + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
24356 + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
24357 + buf += sprintf(buf, "blocks_in_checkpt.... %d\n", dev->blocks_in_checkpt);
24358 + buf += sprintf(buf, "\n");
24359 + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
24360 + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
24361 + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
24362 + buf += sprintf(buf, "\n");
24363 + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
24364 + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
24365 + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
24366 + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
24367 + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
24368 + buf += sprintf(buf, "passive_gc_count..... %u\n", dev->passive_gc_count);
24369 + buf += sprintf(buf, "oldest_dirty_gc_count %u\n", dev->oldest_dirty_gc_count);
24370 + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
24371 + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
24372 + buf += sprintf(buf, "n_retired_writes..... %u\n", dev->n_retired_writes);
24373 + buf += sprintf(buf, "nRetireBlocks........ %u\n", dev->n_retired_blocks);
24374 + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
24375 + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
24376 + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", dev->n_tags_ecc_fixed);
24377 + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", dev->n_tags_ecc_unfixed);
24378 + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
24379 + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
24380 + buf += sprintf(buf, "n_unlinked_files..... %u\n", dev->n_unlinked_files);
24381 + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
24382 + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
24387 +static int yaffs_proc_read(char *page,
24389 + off_t offset, int count, int *eof, void *data)
24391 + struct ylist_head *item;
24392 + char *buf = page;
24393 + int step = offset;
24396 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
24397 + * We use 'offset' (*ppos) to indicate where we are in dev_list.
24398 + * This also assumes the user has posted a read buffer large
24399 + * enough to hold the complete output; but that's life in /proc.
24402 + *(int *)start = 1;
24404 + /* Print header first */
24406 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
24407 + else if (step == 1)
24408 + buf += sprintf(buf,"\n");
24412 + down(&yaffs_context_lock);
24414 + /* Locate and print the Nth entry. Order N-squared but N is small. */
24415 + ylist_for_each(item, &yaffs_context_list) {
24416 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
24417 + yaffs_dev_t *dev = dc->dev;
24419 + if (n < (step & ~1)) {
24423 + if((step & 1)==0){
24424 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
24425 + buf = yaffs_dump_dev_part0(buf, dev);
24427 + buf = yaffs_dump_dev_part1(buf, dev);
24431 + up(&yaffs_context_lock);
24434 + return buf - page < count ? buf - page : count;
24437 +static int yaffs_stats_proc_read(char *page,
24439 + off_t offset, int count, int *eof, void *data)
24441 + struct ylist_head *item;
24442 + char *buf = page;
24445 + down(&yaffs_context_lock);
24447 + /* Locate and print the Nth entry. Order N-squared but N is small. */
24448 + ylist_for_each(item, &yaffs_context_list) {
24449 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
24450 + yaffs_dev_t *dev = dc->dev;
24452 + int erasedChunks;
24454 + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
24456 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
24457 + n, dev->n_free_chunks, erasedChunks,
24458 + dev->bg_gcs, dev->oldest_dirty_gc_count,
24459 + dev->n_obj, dev->n_tnodes);
24461 + up(&yaffs_context_lock);
24464 + return buf - page < count ? buf - page : count;
24468 + * Set the verbosity of the warnings and error messages.
24470 + * Note that the names can only be a..z or _ with the current code.
24475 + unsigned mask_bitfield;
24476 +} mask_flags[] = {
24477 + {"allocate", YAFFS_TRACE_ALLOCATE},
24478 + {"always", YAFFS_TRACE_ALWAYS},
24479 + {"background", YAFFS_TRACE_BACKGROUND},
24480 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
24481 + {"buffers", YAFFS_TRACE_BUFFERS},
24482 + {"bug", YAFFS_TRACE_BUG},
24483 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
24484 + {"deletion", YAFFS_TRACE_DELETION},
24485 + {"erase", YAFFS_TRACE_ERASE},
24486 + {"error", YAFFS_TRACE_ERROR},
24487 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
24488 + {"gc", YAFFS_TRACE_GC},
24489 + {"lock", YAFFS_TRACE_LOCK},
24490 + {"mtd", YAFFS_TRACE_MTD},
24491 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
24492 + {"os", YAFFS_TRACE_OS},
24493 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
24494 + {"scan", YAFFS_TRACE_SCAN},
24495 + {"tracing", YAFFS_TRACE_TRACING},
24496 + {"sync", YAFFS_TRACE_SYNC},
24497 + {"write", YAFFS_TRACE_WRITE},
24499 + {"verify", YAFFS_TRACE_VERIFY},
24500 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
24501 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
24502 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
24504 + {"all", 0xffffffff},
24509 +#define MAX_MASK_NAME_LENGTH 40
24510 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
24511 + unsigned long count, void *data)
24513 + unsigned rg = 0, mask_bitfield;
24517 + char substring[MAX_MASK_NAME_LENGTH + 1];
24520 + int add, len = 0;
24523 + rg = yaffs_trace_mask;
24525 + while (!done && (pos < count)) {
24527 + while ((pos < count) && isspace(buf[pos]))
24530 + switch (buf[pos]) {
24542 + mask_name = NULL;
24544 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
24546 + if (end > buf + pos) {
24547 + mask_name = "numeral";
24548 + len = end - (buf + pos);
24552 + for (x = buf + pos, i = 0;
24553 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
24554 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
24555 + substring[i] = *x;
24556 + substring[i] = '\0';
24558 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
24559 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
24560 + mask_name = mask_flags[i].mask_name;
24561 + mask_bitfield = mask_flags[i].mask_bitfield;
24568 + if (mask_name != NULL) {
24572 + rg &= ~mask_bitfield;
24575 + rg |= mask_bitfield;
24578 + rg = mask_bitfield;
24581 + rg |= mask_bitfield;
24587 + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
24589 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
24591 + if (rg & YAFFS_TRACE_ALWAYS) {
24592 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
24594 + flag = ((rg & mask_flags[i].mask_bitfield) ==
24595 + mask_flags[i].mask_bitfield) ? '+' : '-';
24596 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
24604 +static int yaffs_proc_write(struct file *file, const char *buf,
24605 + unsigned long count, void *data)
24607 + return yaffs_proc_write_trace_options(file, buf, count, data);
24610 +/* Stuff to handle installation of file systems */
24611 +struct file_system_to_install {
24612 + struct file_system_type *fst;
24616 +static struct file_system_to_install fs_to_install[] = {
24617 + {&yaffs_fs_type, 0},
24618 + {&yaffs2_fs_type, 0},
24622 +static int __init init_yaffs_fs(void)
24625 + struct file_system_to_install *fsinst;
24627 + T(YAFFS_TRACE_ALWAYS,
24628 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
24630 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
24631 + T(YAFFS_TRACE_ALWAYS,
24632 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
24638 + init_MUTEX(&yaffs_context_lock);
24640 + /* Install the proc_fs entries */
24641 + my_proc_entry = create_proc_entry("yaffs",
24642 + S_IRUGO | S_IFREG,
24645 + if (my_proc_entry) {
24646 + my_proc_entry->write_proc = yaffs_proc_write;
24647 + my_proc_entry->read_proc = yaffs_proc_read;
24648 + my_proc_entry->data = NULL;
24652 + debug_proc_entry = create_proc_entry("yaffs_stats",
24653 + S_IRUGO | S_IFREG,
24656 + if (debug_proc_entry) {
24657 + debug_proc_entry->write_proc = NULL;
24658 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
24659 + debug_proc_entry->data = NULL;
24663 + /* Now add the file system entries */
24665 + fsinst = fs_to_install;
24667 + while (fsinst->fst && !error) {
24668 + error = register_filesystem(fsinst->fst);
24670 + fsinst->installed = 1;
24674 + /* Any errors? uninstall */
24676 + fsinst = fs_to_install;
24678 + while (fsinst->fst) {
24679 + if (fsinst->installed) {
24680 + unregister_filesystem(fsinst->fst);
24681 + fsinst->installed = 0;
24690 +static void __exit exit_yaffs_fs(void)
24693 + struct file_system_to_install *fsinst;
24695 + T(YAFFS_TRACE_ALWAYS,
24696 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
24698 + remove_proc_entry("yaffs", YPROC_ROOT);
24699 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
24701 + fsinst = fs_to_install;
24703 + while (fsinst->fst) {
24704 + if (fsinst->installed) {
24705 + unregister_filesystem(fsinst->fst);
24706 + fsinst->installed = 0;
24712 +module_init(init_yaffs_fs)
24713 +module_exit(exit_yaffs_fs)
24715 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
24716 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
24717 +MODULE_LICENSE("GPL");
24718 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.c
24719 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 02:00:00.000000000 +0200
24720 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.c 2010-10-20 13:28:16.039000295 +0300
24723 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
24725 + * Copyright (C) 2002-2010 Aleph One Ltd.
24726 + * for Toby Churchill Ltd and Brightstar Engineering
24728 + * Created by Charles Manning <charles@aleph1.co.uk>
24730 + * This program is free software; you can redistribute it and/or modify
24731 + * it under the terms of the GNU General Public License version 2 as
24732 + * published by the Free Software Foundation.
24734 +#include "yaffs_yaffs1.h"
24735 +#include "yportenv.h"
24736 +#include "yaffs_trace.h"
24737 +#include "yaffs_bitmap.h"
24738 +#include "yaffs_getblockinfo.h"
24739 +#include "yaffs_nand.h"
24742 +int yaffs1_scan(yaffs_dev_t *dev)
24744 + yaffs_ext_tags tags;
24746 + int blockIterator;
24747 + int startIterator;
24754 + yaffs_block_state_t state;
24755 + yaffs_obj_t *hard_list = NULL;
24756 + yaffs_block_info_t *bi;
24757 + __u32 seq_number;
24758 + yaffs_obj_header *oh;
24760 + yaffs_obj_t *parent;
24762 + int alloc_failed = 0;
24764 + struct yaffs_shadow_fixer_s *shadowFixerList = NULL;
24771 + T(YAFFS_TRACE_SCAN,
24772 + (TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
24773 + dev->internal_start_block, dev->internal_end_block));
24775 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
24777 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
24779 + /* Scan all the blocks to determine their state */
24780 + bi = dev->block_info;
24781 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
24782 + yaffs_clear_chunk_bits(dev, blk);
24783 + bi->pages_in_use = 0;
24784 + bi->soft_del_pages = 0;
24786 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
24788 + bi->block_state = state;
24789 + bi->seq_number = seq_number;
24791 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
24792 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
24794 + T(YAFFS_TRACE_SCAN_DEBUG,
24795 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
24796 + state, seq_number));
24798 + if (state == YAFFS_BLOCK_STATE_DEAD) {
24799 + T(YAFFS_TRACE_BAD_BLOCKS,
24800 + (TSTR("block %d is bad" TENDSTR), blk));
24801 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
24802 + T(YAFFS_TRACE_SCAN_DEBUG,
24803 + (TSTR("Block empty " TENDSTR)));
24804 + dev->n_erased_blocks++;
24805 + dev->n_free_chunks += dev->param.chunks_per_block;
24810 + startIterator = dev->internal_start_block;
24811 + endIterator = dev->internal_end_block;
24813 + /* For each block.... */
24814 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
24815 + blockIterator++) {
24821 + blk = blockIterator;
24823 + bi = yaffs_get_block_info(dev, blk);
24824 + state = bi->block_state;
24828 + /* For each chunk in each block that needs scanning....*/
24829 + for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
24830 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
24831 + /* Read the tags and decide what to do */
24832 + chunk = blk * dev->param.chunks_per_block + c;
24834 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
24837 + /* Let's have a good look at this chunk... */
24839 + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) {
24840 + /* YAFFS1 only...
24841 + * A deleted chunk
24844 + dev->n_free_chunks++;
24845 + /*T((" %d %d deleted\n",blk,c)); */
24846 + } else if (!tags.chunk_used) {
24847 + /* An unassigned chunk in the block
24848 + * This means that either the block is empty or
24849 + * this is the one being allocated from
24853 + /* We're looking at the first chunk in the block so the block is unused */
24854 + state = YAFFS_BLOCK_STATE_EMPTY;
24855 + dev->n_erased_blocks++;
24857 + /* this is the block being allocated from */
24858 + T(YAFFS_TRACE_SCAN,
24860 + (" Allocating from %d %d" TENDSTR),
24862 + state = YAFFS_BLOCK_STATE_ALLOCATING;
24863 + dev->alloc_block = blk;
24864 + dev->alloc_page = c;
24865 + dev->alloc_block_finder = blk;
24866 + /* Set block finder here to encourage the allocator to go forth from here. */
24870 + dev->n_free_chunks += (dev->param.chunks_per_block - c);
24871 + } else if (tags.chunk_id > 0) {
24872 + /* chunk_id > 0 so it is a data chunk... */
24873 + unsigned int endpos;
24875 + yaffs_set_chunk_bit(dev, blk, c);
24876 + bi->pages_in_use++;
24878 + in = yaffs_find_or_create_by_number(dev,
24881 + YAFFS_OBJECT_TYPE_FILE);
24882 + /* PutChunkIntoFile checks for a clash (two data chunks with
24883 + * the same chunk_id).
24887 + alloc_failed = 1;
24890 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1))
24891 + alloc_failed = 1;
24895 + (tags.chunk_id - 1) * dev->data_bytes_per_chunk +
24898 + in->variant_type == YAFFS_OBJECT_TYPE_FILE
24899 + && in->variant.file_variant.scanned_size <
24901 + in->variant.file_variant.
24902 + scanned_size = endpos;
24903 + if (!dev->param.use_header_file_size) {
24904 + in->variant.file_variant.
24906 + in->variant.file_variant.
24911 + /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
24913 + /* chunk_id == 0, so it is an ObjectHeader.
24914 + * Thus, we read in the object header and make the object
24916 + yaffs_set_chunk_bit(dev, blk, c);
24917 + bi->pages_in_use++;
24919 + result = yaffs_rd_chunk_tags_nand(dev, chunk,
24923 + oh = (yaffs_obj_header *) chunkData;
24925 + in = yaffs_find_by_number(dev,
24927 + if (in && in->variant_type != oh->type) {
24928 + /* This should not happen, but somehow
24929 + * Wev'e ended up with an obj_id that has been reused but not yet
24930 + * deleted, and worse still it has changed type. Delete the old object.
24933 + yaffs_del_obj(in);
24938 + in = yaffs_find_or_create_by_number(dev,
24944 + alloc_failed = 1;
24946 + if (in && oh->shadows_obj > 0) {
24948 + struct yaffs_shadow_fixer_s *fixer;
24949 + fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s));
24951 + fixer->next = shadowFixerList;
24952 + shadowFixerList = fixer;
24953 + fixer->obj_id = tags.obj_id;
24954 + fixer->shadowed_id = oh->shadows_obj;
24955 + T(YAFFS_TRACE_SCAN,
24957 + (" Shadow fixer: %d shadows %d" TENDSTR),
24958 + fixer->obj_id, fixer->shadowed_id));
24964 + if (in && in->valid) {
24965 + /* We have already filled this one. We have a duplicate and need to resolve it. */
24967 + unsigned existingSerial = in->serial;
24968 + unsigned newSerial = tags.serial_number;
24970 + if (((existingSerial + 1) & 3) == newSerial) {
24971 + /* Use new one - destroy the exisiting one */
24972 + yaffs_chunk_del(dev,
24977 + /* Use existing - destroy this one. */
24978 + yaffs_chunk_del(dev, chunk, 1,
24983 + if (in && !in->valid &&
24984 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
24985 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
24986 + /* We only load some info, don't fiddle with directory structure */
24988 + in->variant_type = oh->type;
24990 + in->yst_mode = oh->yst_mode;
24991 +#ifdef CONFIG_YAFFS_WINCE
24992 + in->win_atime[0] = oh->win_atime[0];
24993 + in->win_ctime[0] = oh->win_ctime[0];
24994 + in->win_mtime[0] = oh->win_mtime[0];
24995 + in->win_atime[1] = oh->win_atime[1];
24996 + in->win_ctime[1] = oh->win_ctime[1];
24997 + in->win_mtime[1] = oh->win_mtime[1];
24999 + in->yst_uid = oh->yst_uid;
25000 + in->yst_gid = oh->yst_gid;
25001 + in->yst_atime = oh->yst_atime;
25002 + in->yst_mtime = oh->yst_mtime;
25003 + in->yst_ctime = oh->yst_ctime;
25004 + in->yst_rdev = oh->yst_rdev;
25006 + in->hdr_chunk = chunk;
25007 + in->serial = tags.serial_number;
25009 + } else if (in && !in->valid) {
25010 + /* we need to load this info */
25013 + in->variant_type = oh->type;
25015 + in->yst_mode = oh->yst_mode;
25016 +#ifdef CONFIG_YAFFS_WINCE
25017 + in->win_atime[0] = oh->win_atime[0];
25018 + in->win_ctime[0] = oh->win_ctime[0];
25019 + in->win_mtime[0] = oh->win_mtime[0];
25020 + in->win_atime[1] = oh->win_atime[1];
25021 + in->win_ctime[1] = oh->win_ctime[1];
25022 + in->win_mtime[1] = oh->win_mtime[1];
25024 + in->yst_uid = oh->yst_uid;
25025 + in->yst_gid = oh->yst_gid;
25026 + in->yst_atime = oh->yst_atime;
25027 + in->yst_mtime = oh->yst_mtime;
25028 + in->yst_ctime = oh->yst_ctime;
25029 + in->yst_rdev = oh->yst_rdev;
25031 + in->hdr_chunk = chunk;
25032 + in->serial = tags.serial_number;
25034 + yaffs_set_obj_name_from_oh(in, oh);
25037 + /* directory stuff...
25038 + * hook up to parent
25042 + yaffs_find_or_create_by_number
25043 + (dev, oh->parent_obj_id,
25044 + YAFFS_OBJECT_TYPE_DIRECTORY);
25046 + alloc_failed = 1;
25047 + if (parent && parent->variant_type ==
25048 + YAFFS_OBJECT_TYPE_UNKNOWN) {
25049 + /* Set up as a directory */
25050 + parent->variant_type =
25051 + YAFFS_OBJECT_TYPE_DIRECTORY;
25052 + YINIT_LIST_HEAD(&parent->variant.
25055 + } else if (!parent || parent->variant_type !=
25056 + YAFFS_OBJECT_TYPE_DIRECTORY) {
25057 + /* Hoosterman, another problem....
25058 + * We're trying to use a non-directory as a directory
25061 + T(YAFFS_TRACE_ERROR,
25063 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
25065 + parent = dev->lost_n_found;
25068 + yaffs_add_obj_to_dir(parent, in);
25070 + if (0 && (parent == dev->del_dir ||
25071 + parent == dev->unlinked_dir)) {
25072 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
25073 + dev->n_deleted_files++;
25075 + /* Note re hardlinks.
25076 + * Since we might scan a hardlink before its equivalent object is scanned
25077 + * we put them all in a list.
25078 + * After scanning is complete, we should have all the objects, so we run through this
25079 + * list and fix up all the chains.
25082 + switch (in->variant_type) {
25083 + case YAFFS_OBJECT_TYPE_UNKNOWN:
25084 + /* Todo got a problem */
25086 + case YAFFS_OBJECT_TYPE_FILE:
25087 + if (dev->param.use_header_file_size)
25089 + in->variant.file_variant.
25094 + case YAFFS_OBJECT_TYPE_HARDLINK:
25095 + in->variant.hardlink_variant.
25098 + in->hard_links.next =
25099 + (struct ylist_head *)
25103 + case YAFFS_OBJECT_TYPE_DIRECTORY:
25106 + case YAFFS_OBJECT_TYPE_SPECIAL:
25109 + case YAFFS_OBJECT_TYPE_SYMLINK:
25110 + in->variant.symlink_variant.alias =
25111 + yaffs_clone_str(oh->alias);
25112 + if (!in->variant.symlink_variant.alias)
25113 + alloc_failed = 1;
25121 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
25122 + /* If we got this far while scanning, then the block is fully allocated.*/
25123 + state = YAFFS_BLOCK_STATE_FULL;
25126 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
25127 + /* If the block was partially allocated then treat it as fully allocated.*/
25128 + state = YAFFS_BLOCK_STATE_FULL;
25129 + dev->alloc_block = -1;
25132 + bi->block_state = state;
25134 + /* Now let's see if it was dirty */
25135 + if (bi->pages_in_use == 0 &&
25136 + !bi->has_shrink_hdr &&
25137 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
25138 + yaffs_block_became_dirty(dev, blk);
25144 + /* Ok, we've done all the scanning.
25145 + * Fix up the hard link chains.
25146 + * We should now have scanned all the objects, now it's time to add these
25150 + yaffs_link_fixup(dev, hard_list);
25152 + /* Fix up any shadowed objects */
25154 + struct yaffs_shadow_fixer_s *fixer;
25155 + yaffs_obj_t *obj;
25157 + while (shadowFixerList) {
25158 + fixer = shadowFixerList;
25159 + shadowFixerList = fixer->next;
25160 + /* Complete the rename transaction by deleting the shadowed object
25161 + * then setting the object header to unshadowed.
25163 + obj = yaffs_find_by_number(dev, fixer->shadowed_id);
25165 + yaffs_del_obj(obj);
25167 + obj = yaffs_find_by_number(dev, fixer->obj_id);
25170 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
25176 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
25178 + if (alloc_failed)
25179 + return YAFFS_FAIL;
25181 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
25187 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.h
25188 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 02:00:00.000000000 +0200
25189 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.h 2010-10-20 13:28:16.064000294 +0300
25192 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
25194 + * Copyright (C) 2002-2010 Aleph One Ltd.
25195 + * for Toby Churchill Ltd and Brightstar Engineering
25197 + * Created by Charles Manning <charles@aleph1.co.uk>
25199 + * This program is free software; you can redistribute it and/or modify
25200 + * it under the terms of the GNU Lesser General Public License version 2.1 as
25201 + * published by the Free Software Foundation.
25203 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
25206 +#ifndef __YAFFS_YAFFS1_H__
25207 +#define __YAFFS_YAFFS1_H__
25209 +#include "yaffs_guts.h"
25210 +int yaffs1_scan(yaffs_dev_t *dev);
25213 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.c
25214 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 02:00:00.000000000 +0200
25215 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.c 2010-10-20 13:28:16.050000294 +0300
25218 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
25220 + * Copyright (C) 2002-2010 Aleph One Ltd.
25221 + * for Toby Churchill Ltd and Brightstar Engineering
25223 + * Created by Charles Manning <charles@aleph1.co.uk>
25225 + * This program is free software; you can redistribute it and/or modify
25226 + * it under the terms of the GNU General Public License version 2 as
25227 + * published by the Free Software Foundation.
25231 +#include "yaffs_guts.h"
25232 +#include "yaffs_trace.h"
25233 +#include "yaffs_yaffs2.h"
25234 +#include "yaffs_checkptrw.h"
25235 +#include "yaffs_bitmap.h"
25236 +#include "yaffs_qsort.h"
25237 +#include "yaffs_nand.h"
25238 +#include "yaffs_getblockinfo.h"
25239 +#include "yaffs_verify.h"
25242 + * Checkpoints are really no benefit on very small partitions.
25244 + * To save space on small partitions don't bother with checkpoints unless
25245 + * the partition is at least this big.
25247 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
25249 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
25253 + * Oldest Dirty Sequence Number handling.
25256 +/* yaffs_calc_oldest_dirty_seq()
25257 + * yaffs2_find_oldest_dirty_seq()
25258 + * Calculate the oldest dirty sequence number if we don't know it.
25260 +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev)
25264 + unsigned block_no = 0;
25265 + yaffs_block_info_t *b;
25267 + if(!dev->param.is_yaffs2)
25270 + /* Find the oldest dirty sequence number. */
25271 + seq = dev->seq_number + 1;
25272 + b = dev->block_info;
25273 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
25274 + if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
25275 + (b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block &&
25276 + b->seq_number < seq) {
25277 + seq = b->seq_number;
25284 + dev->oldest_dirty_seq = seq;
25285 + dev->oldest_dirty_block = block_no;
25291 +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev)
25293 + if(!dev->param.is_yaffs2)
25296 + if(!dev->oldest_dirty_seq)
25297 + yaffs_calc_oldest_dirty_seq(dev);
25301 + * yaffs_clear_oldest_dirty_seq()
25302 + * Called when a block is erased or marked bad. (ie. when its seq_number
25303 + * becomes invalid). If the value matches the oldest then we clear
25304 + * dev->oldest_dirty_seq to force its recomputation.
25306 +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi)
25309 + if(!dev->param.is_yaffs2)
25312 + if(!bi || bi->seq_number == dev->oldest_dirty_seq){
25313 + dev->oldest_dirty_seq = 0;
25314 + dev->oldest_dirty_block = 0;
25319 + * yaffs2_update_oldest_dirty_seq()
25320 + * Update the oldest dirty sequence number whenever we dirty a block.
25321 + * Only do this if the oldest_dirty_seq is actually being tracked.
25323 +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi)
25325 + if(!dev->param.is_yaffs2)
25328 + if(dev->oldest_dirty_seq){
25329 + if(dev->oldest_dirty_seq > bi->seq_number){
25330 + dev->oldest_dirty_seq = bi->seq_number;
25331 + dev->oldest_dirty_block = block_no;
25336 +int yaffs_block_ok_for_gc(yaffs_dev_t *dev,
25337 + yaffs_block_info_t *bi)
25340 + if (!dev->param.is_yaffs2)
25341 + return 1; /* disqualification only applies to yaffs2. */
25343 + if (!bi->has_shrink_hdr)
25344 + return 1; /* can gc */
25346 + yaffs2_find_oldest_dirty_seq(dev);
25348 + /* Can't do gc of this block if there are any blocks older than this one that have
25349 + * discarded pages.
25351 + return (bi->seq_number <= dev->oldest_dirty_seq);
25355 + * yaffs2_find_refresh_block()
25356 + * periodically finds the oldest full block by sequence number for refreshing.
25357 + * Only for yaffs2.
25359 +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev)
25363 + __u32 oldest = 0;
25364 + __u32 oldestSequence = 0;
25366 + yaffs_block_info_t *bi;
25368 + if(!dev->param.is_yaffs2)
25372 + * If refresh period < 10 then refreshing is disabled.
25374 + if(dev->param.refresh_period < 10)
25378 + * Fix broken values.
25380 + if(dev->refresh_skip > dev->param.refresh_period)
25381 + dev->refresh_skip = dev->param.refresh_period;
25383 + if(dev->refresh_skip > 0)
25387 + * Refresh skip is now zero.
25388 + * We'll do a refresh this time around....
25389 + * Update the refresh skip and find the oldest block.
25391 + dev->refresh_skip = dev->param.refresh_period;
25392 + dev->refresh_count++;
25393 + bi = dev->block_info;
25394 + for (b = dev->internal_start_block; b <=dev->internal_end_block; b++){
25396 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL){
25399 + bi->seq_number < oldestSequence){
25401 + oldestSequence = bi->seq_number;
25407 + if (oldest > 0) {
25408 + T(YAFFS_TRACE_GC,
25409 + (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR),
25410 + dev->refresh_count, oldest, oldestSequence));
25416 +int yaffs2_checkpt_required(yaffs_dev_t *dev)
25420 + if(!dev->param.is_yaffs2)
25423 + nblocks = dev->internal_end_block - dev->internal_start_block + 1 ;
25425 + return !dev->param.skip_checkpt_wr &&
25426 + !dev->read_only &&
25427 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
25430 +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev)
25434 + if(!dev->param.is_yaffs2)
25437 + if (!dev->checkpoint_blocks_required &&
25438 + yaffs2_checkpt_required(dev)){
25439 + /* Not a valid value so recalculate */
25442 + int devBlocks = (dev->param.end_block - dev->param.start_block + 1);
25444 + n_bytes += sizeof(yaffs_checkpt_validty_t);
25445 + n_bytes += sizeof(yaffs_checkpt_dev_t);
25446 + n_bytes += devBlocks * sizeof(yaffs_block_info_t);
25447 + n_bytes += devBlocks * dev->chunk_bit_stride;
25448 + n_bytes += (sizeof(yaffs_checkpt_obj_t) + sizeof(__u32)) * (dev->n_obj);
25449 + n_bytes += (dev->tnode_size + sizeof(__u32)) * (dev->n_tnodes);
25450 + n_bytes += sizeof(yaffs_checkpt_validty_t);
25451 + n_bytes += sizeof(__u32); /* checksum*/
25453 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
25455 + nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3;
25457 + dev->checkpoint_blocks_required = nBlocks;
25460 + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
25466 +/*--------------------- Checkpointing --------------------*/
25469 +static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head)
25471 + yaffs_checkpt_validty_t cp;
25473 + memset(&cp, 0, sizeof(cp));
25475 + cp.struct_type = sizeof(cp);
25476 + cp.magic = YAFFS_MAGIC;
25477 + cp.version = YAFFS_CHECKPOINT_VERSION;
25478 + cp.head = (head) ? 1 : 0;
25480 + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
25484 +static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head)
25486 + yaffs_checkpt_validty_t cp;
25489 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25492 + ok = (cp.struct_type == sizeof(cp)) &&
25493 + (cp.magic == YAFFS_MAGIC) &&
25494 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
25495 + (cp.head == ((head) ? 1 : 0));
25496 + return ok ? 1 : 0;
25499 +static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp,
25500 + yaffs_dev_t *dev)
25502 + cp->n_erased_blocks = dev->n_erased_blocks;
25503 + cp->alloc_block = dev->alloc_block;
25504 + cp->alloc_page = dev->alloc_page;
25505 + cp->n_free_chunks = dev->n_free_chunks;
25507 + cp->n_deleted_files = dev->n_deleted_files;
25508 + cp->n_unlinked_files = dev->n_unlinked_files;
25509 + cp->n_bg_deletions = dev->n_bg_deletions;
25510 + cp->seq_number = dev->seq_number;
25514 +static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev,
25515 + yaffs_checkpt_dev_t *cp)
25517 + dev->n_erased_blocks = cp->n_erased_blocks;
25518 + dev->alloc_block = cp->alloc_block;
25519 + dev->alloc_page = cp->alloc_page;
25520 + dev->n_free_chunks = cp->n_free_chunks;
25522 + dev->n_deleted_files = cp->n_deleted_files;
25523 + dev->n_unlinked_files = cp->n_unlinked_files;
25524 + dev->n_bg_deletions = cp->n_bg_deletions;
25525 + dev->seq_number = cp->seq_number;
25529 +static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev)
25531 + yaffs_checkpt_dev_t cp;
25533 + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
25537 + /* Write device runtime values*/
25538 + yaffs2_dev_to_checkpt_dev(&cp, dev);
25539 + cp.struct_type = sizeof(cp);
25541 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25543 + /* Write block info */
25545 + n_bytes = nBlocks * sizeof(yaffs_block_info_t);
25546 + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
25549 + /* Write chunk bits */
25551 + n_bytes = nBlocks * dev->chunk_bit_stride;
25552 + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
25554 + return ok ? 1 : 0;
25558 +static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev)
25560 + yaffs_checkpt_dev_t cp;
25562 + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
25566 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25570 + if (cp.struct_type != sizeof(cp))
25574 + yaffs_checkpt_dev_to_dev(dev, &cp);
25576 + n_bytes = nBlocks * sizeof(yaffs_block_info_t);
25578 + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
25582 + n_bytes = nBlocks * dev->chunk_bit_stride;
25584 + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
25586 + return ok ? 1 : 0;
25589 +static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp,
25590 + yaffs_obj_t *obj)
25593 + cp->obj_id = obj->obj_id;
25594 + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
25595 + cp->hdr_chunk = obj->hdr_chunk;
25596 + cp->variant_type = obj->variant_type;
25597 + cp->deleted = obj->deleted;
25598 + cp->soft_del = obj->soft_del;
25599 + cp->unlinked = obj->unlinked;
25600 + cp->fake = obj->fake;
25601 + cp->rename_allowed = obj->rename_allowed;
25602 + cp->unlink_allowed = obj->unlink_allowed;
25603 + cp->serial = obj->serial;
25604 + cp->n_data_chunks = obj->n_data_chunks;
25606 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25607 + cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
25608 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
25609 + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
25612 +static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp)
25615 + yaffs_obj_t *parent;
25617 + if (obj->variant_type != cp->variant_type) {
25618 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
25619 + TCONT("chunk %d does not match existing object type %d")
25620 + TENDSTR), cp->obj_id, cp->variant_type, cp->hdr_chunk,
25621 + obj->variant_type));
25625 + obj->obj_id = cp->obj_id;
25627 + if (cp->parent_id)
25628 + parent = yaffs_find_or_create_by_number(
25631 + YAFFS_OBJECT_TYPE_DIRECTORY);
25636 + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
25637 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
25638 + TCONT(" chunk %d Parent type, %d, not directory")
25640 + cp->obj_id, cp->parent_id, cp->variant_type,
25641 + cp->hdr_chunk, parent->variant_type));
25644 + yaffs_add_obj_to_dir(parent, obj);
25647 + obj->hdr_chunk = cp->hdr_chunk;
25648 + obj->variant_type = cp->variant_type;
25649 + obj->deleted = cp->deleted;
25650 + obj->soft_del = cp->soft_del;
25651 + obj->unlinked = cp->unlinked;
25652 + obj->fake = cp->fake;
25653 + obj->rename_allowed = cp->rename_allowed;
25654 + obj->unlink_allowed = cp->unlink_allowed;
25655 + obj->serial = cp->serial;
25656 + obj->n_data_chunks = cp->n_data_chunks;
25658 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25659 + obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
25660 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
25661 + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
25663 + if (obj->hdr_chunk > 0)
25664 + obj->lazy_loaded = 1;
25670 +static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
25671 + __u32 level, int chunk_offset)
25674 + yaffs_dev_t *dev = in->my_dev;
25680 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
25681 + if (tn->internal[i]) {
25682 + ok = yaffs2_checkpt_tnode_worker(in,
25685 + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
25688 + } else if (level == 0) {
25689 + __u32 baseOffset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
25690 + ok = (yaffs2_checkpt_wr(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
25692 + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size);
25700 +static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj)
25702 + __u32 endMarker = ~0;
25705 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
25706 + ok = yaffs2_checkpt_tnode_worker(obj,
25707 + obj->variant.file_variant.top,
25708 + obj->variant.file_variant.top_level,
25711 + ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) ==
25712 + sizeof(endMarker));
25715 + return ok ? 1 : 0;
25718 +static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj)
25722 + yaffs_dev_t *dev = obj->my_dev;
25723 + yaffs_file_s *fileStructPtr = &obj->variant.file_variant;
25724 + yaffs_tnode_t *tn;
25727 + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
25729 + while (ok && (~baseChunk)) {
25731 + /* Read level 0 tnode */
25734 + tn = yaffs_get_tnode(dev);
25736 + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size);
25741 + ok = yaffs_add_find_tnode_0(dev,
25747 + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
25751 + T(YAFFS_TRACE_CHECKPOINT, (
25752 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
25753 + nread, baseChunk, ok));
25755 + return ok ? 1 : 0;
25759 +static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev)
25761 + yaffs_obj_t *obj;
25762 + yaffs_checkpt_obj_t cp;
25765 + struct ylist_head *lh;
25768 + /* Iterate through the objects in each hash entry,
25769 + * dumping them to the checkpointing stream.
25772 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
25773 + ylist_for_each(lh, &dev->obj_bucket[i].list) {
25775 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
25776 + if (!obj->defered_free) {
25777 + yaffs2_obj_checkpt_obj(&cp, obj);
25778 + cp.struct_type = sizeof(cp);
25780 + T(YAFFS_TRACE_CHECKPOINT, (
25781 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
25782 + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk, obj));
25784 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25786 + if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25787 + ok = yaffs2_wr_checkpt_tnodes(obj);
25793 + /* Dump end of list */
25794 + memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t));
25795 + cp.struct_type = sizeof(cp);
25798 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25800 + return ok ? 1 : 0;
25803 +static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev)
25805 + yaffs_obj_t *obj;
25806 + yaffs_checkpt_obj_t cp;
25809 + yaffs_obj_t *hard_list = NULL;
25811 + while (ok && !done) {
25812 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25813 + if (cp.struct_type != sizeof(cp)) {
25814 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
25815 + cp.struct_type, (int)sizeof(cp), ok));
25819 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
25820 + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk));
25822 + if (ok && cp.obj_id == ~0)
25825 + obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type);
25827 + ok = taffs2_checkpt_obj_to_obj(obj, &cp);
25830 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
25831 + ok = yaffs2_rd_checkpt_tnodes(obj);
25832 + } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
25833 + obj->hard_links.next =
25834 + (struct ylist_head *) hard_list;
25843 + yaffs_link_fixup(dev, hard_list);
25845 + return ok ? 1 : 0;
25848 +static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev)
25850 + __u32 checkpt_sum;
25853 + yaffs2_get_checkpt_sum(dev, &checkpt_sum);
25855 + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum));
25863 +static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev)
25865 + __u32 checkpt_sum0;
25866 + __u32 checkpt_sum1;
25869 + yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
25871 + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1));
25876 + if (checkpt_sum0 != checkpt_sum1)
25883 +static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev)
25887 + if (!yaffs2_checkpt_required(dev)) {
25888 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
25893 + ok = yaffs2_checkpt_open(dev, 1);
25896 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
25897 + ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
25900 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
25901 + ok = yaffs2_wr_checkpt_dev(dev);
25904 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
25905 + ok = yaffs2_wr_checkpt_objs(dev);
25908 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
25909 + ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
25913 + ok = yaffs2_wr_checkpt_sum(dev);
25915 + if (!yaffs_checkpt_close(dev))
25919 + dev->is_checkpointed = 1;
25921 + dev->is_checkpointed = 0;
25923 + return dev->is_checkpointed;
25926 +static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev)
25930 + if(!dev->param.is_yaffs2)
25933 + if (ok && dev->param.skip_checkpt_rd) {
25934 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
25939 + ok = yaffs2_checkpt_open(dev, 0); /* open for read */
25942 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
25943 + ok = yaffs2_rd_checkpt_validty_marker(dev, 1);
25946 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
25947 + ok = yaffs2_rd_checkpt_dev(dev);
25950 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
25951 + ok = yaffs2_rd_checkpt_objs(dev);
25954 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
25955 + ok = yaffs2_rd_checkpt_validty_marker(dev, 0);
25959 + ok = yaffs2_rd_checkpt_sum(dev);
25960 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
25963 + if (!yaffs_checkpt_close(dev))
25967 + dev->is_checkpointed = 1;
25969 + dev->is_checkpointed = 0;
25971 + return ok ? 1 : 0;
25975 +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev)
25977 + if (dev->is_checkpointed ||
25978 + dev->blocks_in_checkpt > 0) {
25979 + dev->is_checkpointed = 0;
25980 + yaffs2_checkpt_invalidate_stream(dev);
25982 + if (dev->param.sb_dirty_fn)
25983 + dev->param.sb_dirty_fn(dev);
25987 +int yaffs_checkpoint_save(yaffs_dev_t *dev)
25990 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
25992 + yaffs_verify_objects(dev);
25993 + yaffs_verify_blocks(dev);
25994 + yaffs_verify_free_chunks(dev);
25996 + if (!dev->is_checkpointed) {
25997 + yaffs2_checkpt_invalidate(dev);
25998 + yaffs2_wr_checkpt_data(dev);
26001 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
26003 + return dev->is_checkpointed;
26006 +int yaffs2_checkpt_restore(yaffs_dev_t *dev)
26009 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
26011 + retval = yaffs2_rd_checkpt_data(dev);
26013 + if (dev->is_checkpointed) {
26014 + yaffs_verify_objects(dev);
26015 + yaffs_verify_blocks(dev);
26016 + yaffs_verify_free_chunks(dev);
26019 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
26024 +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size)
26026 + /* if newsSize > oldFileSize.
26027 + * We're going to be writing a hole.
26028 + * If the hole is small then write zeros otherwise write a start of hole marker.
26032 + loff_t oldFileSize;
26035 + int result = YAFFS_OK;
26036 + yaffs_dev_t *dev = NULL;
26038 + __u8 *localBuffer = NULL;
26040 + int smallIncreaseOk = 0;
26043 + return YAFFS_FAIL;
26045 + if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
26046 + return YAFFS_FAIL;
26048 + dev = obj->my_dev;
26050 + /* Bail out if not yaffs2 mode */
26051 + if(!dev->param.is_yaffs2)
26054 + oldFileSize = obj->variant.file_variant.file_size;
26056 + if (new_size <= oldFileSize)
26059 + increase = new_size - oldFileSize;
26061 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
26062 + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
26068 + localBuffer= yaffs_get_temp_buffer(dev, __LINE__);
26071 + /* fill hole with zero bytes */
26072 + int pos = oldFileSize;
26075 + memset(localBuffer,0,dev->data_bytes_per_chunk);
26076 + smallIncreaseOk = 1;
26078 + while(increase > 0 && smallIncreaseOk){
26079 + thisWrite = increase;
26080 + if(thisWrite > dev->data_bytes_per_chunk)
26081 + thisWrite = dev->data_bytes_per_chunk;
26082 + written = yaffs_do_file_wr(obj,localBuffer,pos,thisWrite,0);
26083 + if(written == thisWrite){
26084 + pos += thisWrite;
26085 + increase -= thisWrite;
26087 + smallIncreaseOk = 0;
26090 + yaffs_release_temp_buffer(dev,localBuffer,__LINE__);
26092 + /* If we were out of space then reverse any chunks we've added */
26093 + if(!smallIncreaseOk)
26094 + yaffs_resize_file_down(obj, oldFileSize);
26097 + if (!smallIncreaseOk &&
26099 + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
26100 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED){
26101 + /* Write a hole start header with the old file size */
26102 + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
26113 +} yaffs_BlockIndex;
26116 +static int yaffs2_ybicmp(const void *a, const void *b)
26118 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
26119 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
26120 + register int ablock = ((yaffs_BlockIndex *)a)->block;
26121 + register int bblock = ((yaffs_BlockIndex *)b)->block;
26122 + if (aseq == bseq)
26123 + return ablock - bblock;
26125 + return aseq - bseq;
26128 +int yaffs2_scan_backwards(yaffs_dev_t *dev)
26130 + yaffs_ext_tags tags;
26132 + int blockIterator;
26133 + int startIterator;
26135 + int nBlocksToScan = 0;
26141 + yaffs_block_state_t state;
26142 + yaffs_obj_t *hard_list = NULL;
26143 + yaffs_block_info_t *bi;
26144 + __u32 seq_number;
26145 + yaffs_obj_header *oh;
26147 + yaffs_obj_t *parent;
26148 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
26154 + int foundChunksInBlock;
26156 + int alloc_failed = 0;
26159 + yaffs_BlockIndex *blockIndex = NULL;
26160 + int altBlockIndex = 0;
26162 + T(YAFFS_TRACE_SCAN,
26164 + ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
26165 + TENDSTR), dev->internal_start_block, dev->internal_end_block));
26168 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
26170 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
26172 + if (!blockIndex) {
26173 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
26174 + altBlockIndex = 1;
26177 + if (!blockIndex) {
26178 + T(YAFFS_TRACE_SCAN,
26179 + (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR)));
26180 + return YAFFS_FAIL;
26183 + dev->blocks_in_checkpt = 0;
26185 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
26187 + /* Scan all the blocks to determine their state */
26188 + bi = dev->block_info;
26189 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
26190 + yaffs_clear_chunk_bits(dev, blk);
26191 + bi->pages_in_use = 0;
26192 + bi->soft_del_pages = 0;
26194 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
26196 + bi->block_state = state;
26197 + bi->seq_number = seq_number;
26199 + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
26200 + bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
26201 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
26202 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
26204 + T(YAFFS_TRACE_SCAN_DEBUG,
26205 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
26206 + state, seq_number));
26209 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
26210 + dev->blocks_in_checkpt++;
26212 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
26213 + T(YAFFS_TRACE_BAD_BLOCKS,
26214 + (TSTR("block %d is bad" TENDSTR), blk));
26215 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
26216 + T(YAFFS_TRACE_SCAN_DEBUG,
26217 + (TSTR("Block empty " TENDSTR)));
26218 + dev->n_erased_blocks++;
26219 + dev->n_free_chunks += dev->param.chunks_per_block;
26220 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
26222 + /* Determine the highest sequence number */
26223 + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
26224 + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
26226 + blockIndex[nBlocksToScan].seq = seq_number;
26227 + blockIndex[nBlocksToScan].block = blk;
26231 + if (seq_number >= dev->seq_number)
26232 + dev->seq_number = seq_number;
26234 + /* TODO: Nasty sequence number! */
26235 + T(YAFFS_TRACE_SCAN,
26237 + ("Block scanning block %d has bad sequence number %d"
26238 + TENDSTR), blk, seq_number));
26245 + T(YAFFS_TRACE_SCAN,
26246 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
26252 + /* Sort the blocks by sequence number*/
26253 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
26257 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
26259 + /* Now scan the blocks looking at the data. */
26260 + startIterator = 0;
26261 + endIterator = nBlocksToScan - 1;
26262 + T(YAFFS_TRACE_SCAN_DEBUG,
26263 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
26265 + /* For each block.... backwards */
26266 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
26267 + blockIterator--) {
26268 + /* Cooperative multitasking! This loop can run for so
26269 + long that watchdog timers expire. */
26272 + /* get the block to scan in the correct order */
26273 + blk = blockIndex[blockIterator].block;
26275 + bi = yaffs_get_block_info(dev, blk);
26278 + state = bi->block_state;
26282 + /* For each chunk in each block that needs scanning.... */
26283 + foundChunksInBlock = 0;
26284 + for (c = dev->param.chunks_per_block - 1;
26285 + !alloc_failed && c >= 0 &&
26286 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
26287 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
26288 + /* Scan backwards...
26289 + * Read the tags and decide what to do
26292 + chunk = blk * dev->param.chunks_per_block + c;
26294 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
26297 + /* Let's have a good look at this chunk... */
26299 + if (!tags.chunk_used) {
26300 + /* An unassigned chunk in the block.
26301 + * If there are used chunks after this one, then
26302 + * it is a chunk that was skipped due to failing the erased
26303 + * check. Just skip it so that it can be deleted.
26304 + * But, more typically, We get here when this is an unallocated
26305 + * chunk and his means that either the block is empty or
26306 + * this is the one being allocated from
26309 + if (foundChunksInBlock) {
26310 + /* This is a chunk that was skipped due to failing the erased check */
26311 + } else if (c == 0) {
26312 + /* We're looking at the first chunk in the block so the block is unused */
26313 + state = YAFFS_BLOCK_STATE_EMPTY;
26314 + dev->n_erased_blocks++;
26316 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
26317 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
26318 + if (dev->seq_number == bi->seq_number) {
26319 + /* this is the block being allocated from */
26321 + T(YAFFS_TRACE_SCAN,
26323 + (" Allocating from %d %d"
26324 + TENDSTR), blk, c));
26326 + state = YAFFS_BLOCK_STATE_ALLOCATING;
26327 + dev->alloc_block = blk;
26328 + dev->alloc_page = c;
26329 + dev->alloc_block_finder = blk;
26331 + /* This is a partially written block that is not
26332 + * the current allocation block.
26335 + T(YAFFS_TRACE_SCAN,
26336 + (TSTR("Partially written block %d detected" TENDSTR),
26342 + dev->n_free_chunks++;
26344 + } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
26345 + T(YAFFS_TRACE_SCAN,
26346 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
26349 + dev->n_free_chunks++;
26351 + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
26352 + tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
26353 + (tags.chunk_id > 0 && tags.n_bytes > dev->data_bytes_per_chunk) ||
26354 + tags.seq_number != bi->seq_number ) {
26355 + T(YAFFS_TRACE_SCAN,
26356 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR),
26357 + blk, c,tags.obj_id, tags.chunk_id, tags.n_bytes));
26359 + dev->n_free_chunks++;
26361 + } else if (tags.chunk_id > 0) {
26362 + /* chunk_id > 0 so it is a data chunk... */
26363 + unsigned int endpos;
26364 + __u32 chunkBase =
26365 + (tags.chunk_id - 1) * dev->data_bytes_per_chunk;
26367 + foundChunksInBlock = 1;
26370 + yaffs_set_chunk_bit(dev, blk, c);
26371 + bi->pages_in_use++;
26373 + in = yaffs_find_or_create_by_number(dev,
26376 + YAFFS_OBJECT_TYPE_FILE);
26378 + /* Out of memory */
26379 + alloc_failed = 1;
26383 + in->variant_type == YAFFS_OBJECT_TYPE_FILE
26384 + && chunkBase < in->variant.file_variant.shrink_size) {
26385 + /* This has not been invalidated by a resize */
26386 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, -1)) {
26387 + alloc_failed = 1;
26390 + /* File size is calculated by looking at the data chunks if we have not
26391 + * seen an object header yet. Stop this practice once we find an object header.
26393 + endpos = chunkBase + tags.n_bytes;
26395 + if (!in->valid && /* have not got an object header yet */
26396 + in->variant.file_variant.scanned_size < endpos) {
26397 + in->variant.file_variant.scanned_size = endpos;
26398 + in->variant.file_variant.file_size = endpos;
26402 + /* This chunk has been invalidated by a resize, or a past file deletion
26403 + * so delete the chunk*/
26404 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
26408 + /* chunk_id == 0, so it is an ObjectHeader.
26409 + * Thus, we read in the object header and make the object
26411 + foundChunksInBlock = 1;
26413 + yaffs_set_chunk_bit(dev, blk, c);
26414 + bi->pages_in_use++;
26419 + if (tags.extra_available) {
26420 + in = yaffs_find_or_create_by_number(dev,
26422 + tags.extra_obj_type);
26424 + alloc_failed = 1;
26428 + (!in->valid && dev->param.disable_lazy_load) ||
26429 + tags.extra_shadows ||
26431 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
26432 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
26434 + /* If we don't have valid info then we need to read the chunk
26435 + * TODO In future we can probably defer reading the chunk and
26436 + * living with invalid data until needed.
26439 + result = yaffs_rd_chunk_tags_nand(dev,
26444 + oh = (yaffs_obj_header *) chunkData;
26446 + if (dev->param.inband_tags) {
26447 + /* Fix up the header if they got corrupted by inband tags */
26448 + oh->shadows_obj = oh->inband_shadowed_obj_id;
26449 + oh->is_shrink = oh->inband_is_shrink;
26453 + in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
26455 + alloc_failed = 1;
26461 + /* TODO Hoosterman we have a problem! */
26462 + T(YAFFS_TRACE_ERROR,
26464 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
26465 + TENDSTR), tags.obj_id, chunk));
26470 + /* We have already filled this one.
26471 + * We have a duplicate that will be discarded, but
26472 + * we first have to suck out resize info if it is a file.
26475 + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
26477 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
26478 + (tags.extra_available &&
26479 + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) {
26481 + (oh) ? oh->file_size : tags.
26483 + __u32 parent_obj_id =
26485 + parent_obj_id : tags.
26490 + (oh) ? oh->is_shrink : tags.
26493 + /* If it is deleted (unlinked at start also means deleted)
26494 + * we treat the file size as being zeroed at this point.
26496 + if (parent_obj_id ==
26497 + YAFFS_OBJECTID_DELETED
26498 + || parent_obj_id ==
26499 + YAFFS_OBJECTID_UNLINKED) {
26504 + if (is_shrink && in->variant.file_variant.shrink_size > thisSize)
26505 + in->variant.file_variant.shrink_size = thisSize;
26508 + bi->has_shrink_hdr = 1;
26511 + /* Use existing - destroy this one. */
26512 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
26516 + if (!in->valid && in->variant_type !=
26517 + (oh ? oh->type : tags.extra_obj_type))
26518 + T(YAFFS_TRACE_ERROR, (
26519 + TSTR("yaffs tragedy: Bad object type, "
26520 + TCONT("%d != %d, for object %d at chunk ")
26521 + TCONT("%d during scan")
26523 + oh->type : tags.extra_obj_type,
26524 + in->variant_type, tags.obj_id,
26527 + if (!in->valid &&
26528 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
26530 + YAFFS_OBJECTID_LOSTNFOUND)) {
26531 + /* We only load some info, don't fiddle with directory structure */
26536 + in->yst_mode = oh->yst_mode;
26537 +#ifdef CONFIG_YAFFS_WINCE
26538 + in->win_atime[0] = oh->win_atime[0];
26539 + in->win_ctime[0] = oh->win_ctime[0];
26540 + in->win_mtime[0] = oh->win_mtime[0];
26541 + in->win_atime[1] = oh->win_atime[1];
26542 + in->win_ctime[1] = oh->win_ctime[1];
26543 + in->win_mtime[1] = oh->win_mtime[1];
26545 + in->yst_uid = oh->yst_uid;
26546 + in->yst_gid = oh->yst_gid;
26547 + in->yst_atime = oh->yst_atime;
26548 + in->yst_mtime = oh->yst_mtime;
26549 + in->yst_ctime = oh->yst_ctime;
26550 + in->yst_rdev = oh->yst_rdev;
26552 + in->lazy_loaded = 0;
26556 + in->lazy_loaded = 1;
26558 + in->hdr_chunk = chunk;
26560 + } else if (!in->valid) {
26561 + /* we need to load this info */
26564 + in->hdr_chunk = chunk;
26567 + in->variant_type = oh->type;
26569 + in->yst_mode = oh->yst_mode;
26570 +#ifdef CONFIG_YAFFS_WINCE
26571 + in->win_atime[0] = oh->win_atime[0];
26572 + in->win_ctime[0] = oh->win_ctime[0];
26573 + in->win_mtime[0] = oh->win_mtime[0];
26574 + in->win_atime[1] = oh->win_atime[1];
26575 + in->win_ctime[1] = oh->win_ctime[1];
26576 + in->win_mtime[1] = oh->win_mtime[1];
26578 + in->yst_uid = oh->yst_uid;
26579 + in->yst_gid = oh->yst_gid;
26580 + in->yst_atime = oh->yst_atime;
26581 + in->yst_mtime = oh->yst_mtime;
26582 + in->yst_ctime = oh->yst_ctime;
26583 + in->yst_rdev = oh->yst_rdev;
26586 + if (oh->shadows_obj > 0)
26587 + yaffs_handle_shadowed_obj(dev,
26594 + yaffs_set_obj_name_from_oh(in, oh);
26596 + yaffs_find_or_create_by_number
26597 + (dev, oh->parent_obj_id,
26598 + YAFFS_OBJECT_TYPE_DIRECTORY);
26600 + file_size = oh->file_size;
26601 + is_shrink = oh->is_shrink;
26602 + equiv_id = oh->equiv_id;
26605 + in->variant_type = tags.extra_obj_type;
26607 + yaffs_find_or_create_by_number
26608 + (dev, tags.extra_parent_id,
26609 + YAFFS_OBJECT_TYPE_DIRECTORY);
26610 + file_size = tags.extra_length;
26611 + is_shrink = tags.extra_is_shrink;
26612 + equiv_id = tags.extra_equiv_id;
26613 + in->lazy_loaded = 1;
26619 + alloc_failed = 1;
26621 + /* directory stuff...
26622 + * hook up to parent
26625 + if (parent && parent->variant_type ==
26626 + YAFFS_OBJECT_TYPE_UNKNOWN) {
26627 + /* Set up as a directory */
26628 + parent->variant_type =
26629 + YAFFS_OBJECT_TYPE_DIRECTORY;
26630 + YINIT_LIST_HEAD(&parent->variant.
26633 + } else if (!parent || parent->variant_type !=
26634 + YAFFS_OBJECT_TYPE_DIRECTORY) {
26635 + /* Hoosterman, another problem....
26636 + * We're trying to use a non-directory as a directory
26639 + T(YAFFS_TRACE_ERROR,
26641 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
26643 + parent = dev->lost_n_found;
26646 + yaffs_add_obj_to_dir(parent, in);
26648 + itsUnlinked = (parent == dev->del_dir) ||
26649 + (parent == dev->unlinked_dir);
26652 + /* Mark the block as having a shrinkHeader */
26653 + bi->has_shrink_hdr = 1;
26656 + /* Note re hardlinks.
26657 + * Since we might scan a hardlink before its equivalent object is scanned
26658 + * we put them all in a list.
26659 + * After scanning is complete, we should have all the objects, so we run
26660 + * through this list and fix up all the chains.
26663 + switch (in->variant_type) {
26664 + case YAFFS_OBJECT_TYPE_UNKNOWN:
26665 + /* Todo got a problem */
26667 + case YAFFS_OBJECT_TYPE_FILE:
26669 + if (in->variant.file_variant.
26670 + scanned_size < file_size) {
26671 + /* This covers the case where the file size is greater
26672 + * than where the data is
26673 + * This will happen if the file is resized to be larger
26674 + * than its current data extents.
26676 + in->variant.file_variant.file_size = file_size;
26677 + in->variant.file_variant.scanned_size = file_size;
26680 + if (in->variant.file_variant.shrink_size > file_size)
26681 + in->variant.file_variant.shrink_size = file_size;
26685 + case YAFFS_OBJECT_TYPE_HARDLINK:
26686 + if (!itsUnlinked) {
26687 + in->variant.hardlink_variant.equiv_id =
26689 + in->hard_links.next =
26690 + (struct ylist_head *) hard_list;
26694 + case YAFFS_OBJECT_TYPE_DIRECTORY:
26697 + case YAFFS_OBJECT_TYPE_SPECIAL:
26700 + case YAFFS_OBJECT_TYPE_SYMLINK:
26702 + in->variant.symlink_variant.alias =
26703 + yaffs_clone_str(oh->alias);
26704 + if (!in->variant.symlink_variant.alias)
26705 + alloc_failed = 1;
26714 + } /* End of scanning for each chunk */
26716 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
26717 + /* If we got this far while scanning, then the block is fully allocated. */
26718 + state = YAFFS_BLOCK_STATE_FULL;
26722 + bi->block_state = state;
26724 + /* Now let's see if it was dirty */
26725 + if (bi->pages_in_use == 0 &&
26726 + !bi->has_shrink_hdr &&
26727 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
26728 + yaffs_block_became_dirty(dev, blk);
26733 + yaffs_skip_rest_of_block(dev);
26735 + if (altBlockIndex)
26736 + YFREE_ALT(blockIndex);
26738 + YFREE(blockIndex);
26740 + /* Ok, we've done all the scanning.
26741 + * Fix up the hard link chains.
26742 + * We should now have scanned all the objects, now it's time to add these
26745 + yaffs_link_fixup(dev, hard_list);
26748 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
26750 + if (alloc_failed)
26751 + return YAFFS_FAIL;
26753 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
26757 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.h
26758 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 02:00:00.000000000 +0200
26759 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.h 2010-10-20 13:28:16.067000294 +0300
26762 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
26764 + * Copyright (C) 2002-2010 Aleph One Ltd.
26765 + * for Toby Churchill Ltd and Brightstar Engineering
26767 + * Created by Charles Manning <charles@aleph1.co.uk>
26769 + * This program is free software; you can redistribute it and/or modify
26770 + * it under the terms of the GNU General Public License version 2 as
26771 + * published by the Free Software Foundation.
26774 +#ifndef __YAFFS_YAFFS2_H__
26775 +#define __YAFFS_YAFFS2_H__
26777 +#include "yaffs_guts.h"
26779 +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev);
26780 +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev);
26781 +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi);
26782 +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi);
26783 +int yaffs_block_ok_for_gc(yaffs_dev_t *dev, yaffs_block_info_t *bi);
26784 +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev);
26785 +int yaffs2_checkpt_required(yaffs_dev_t *dev);
26786 +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev);
26789 +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev);
26790 +int yaffs2_checkpt_save(yaffs_dev_t *dev);
26791 +int yaffs2_checkpt_restore(yaffs_dev_t *dev);
26793 +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size);
26794 +int yaffs2_scan_backwards(yaffs_dev_t *dev);
26797 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yportenv.h linux-2.6.36-rc8.new/fs/yaffs2/yportenv.h
26798 --- linux-2.6.36-rc8/fs/yaffs2/yportenv.h 2010-10-20 13:17:58.988000294 +0300
26799 +++ linux-2.6.36-rc8.new/fs/yaffs2/yportenv.h 2010-10-20 13:28:16.067000294 +0300
26802 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
26804 - * Copyright (C) 2002-2007 Aleph One Ltd.
26805 + * Copyright (C) 2002-2010 Aleph One Ltd.
26806 * for Toby Churchill Ltd and Brightstar Engineering
26808 * Created by Charles Manning <charles@aleph1.co.uk>
26809 @@ -41,12 +41,14 @@
26810 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
26811 #include <linux/config.h>
26814 #include <linux/kernel.h>
26815 #include <linux/mm.h>
26816 #include <linux/sched.h>
26817 #include <linux/string.h>
26818 #include <linux/slab.h>
26819 #include <linux/vmalloc.h>
26820 +#include <linux/xattr.h>
26823 #define YUCHAR unsigned char
26824 @@ -55,11 +57,11 @@
26825 #define yaffs_strcpy(a, b) strcpy(a, b)
26826 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
26827 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
26828 -#define yaffs_strlen(s) strlen(s)
26829 +#define yaffs_strnlen(s,m) strnlen(s,m)
26830 #define yaffs_sprintf sprintf
26831 #define yaffs_toupper(a) toupper(a)
26833 -#define Y_INLINE inline
26834 +#define Y_INLINE __inline__
26836 #define YAFFS_LOSTNFOUND_NAME "lost+found"
26837 #define YAFFS_LOSTNFOUND_PREFIX "obj"
26838 @@ -71,11 +73,11 @@
26839 #define YFREE_ALT(x) vfree(x)
26840 #define YMALLOC_DMA(x) YMALLOC(x)
26842 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
26843 #define YYIELD() schedule()
26844 +#define Y_DUMP_STACK() dump_stack()
26846 -#define YAFFS_ROOT_MODE 0666
26847 -#define YAFFS_LOSTNFOUND_MODE 0666
26848 +#define YAFFS_ROOT_MODE 0755
26849 +#define YAFFS_LOSTNFOUND_MODE 0700
26851 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
26852 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
26853 @@ -85,19 +87,14 @@
26854 #define Y_TIME_CONVERT(x) (x)
26857 -#define yaffs_SumCompare(x, y) ((x) == (y))
26858 +#define yaffs_sum_cmp(x, y) ((x) == (y))
26859 #define yaffs_strcmp(a, b) strcmp(a, b)
26861 #define TENDSTR "\n"
26862 -#define TSTR(x) KERN_WARNING x
26863 +#define TSTR(x) KERN_DEBUG x
26865 #define TOUT(p) printk p
26867 -#define yaffs_trace(mask, fmt, args...) \
26868 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
26869 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
26872 #define compile_time_assertion(assertion) \
26873 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
26875 @@ -116,7 +113,6 @@
26877 #include "string.h"
26879 -#include "devextras.h"
26881 #define YMALLOC(x) malloc(x)
26882 #define YFREE(x) free(x)
26883 @@ -129,7 +125,7 @@
26884 #define yaffs_strcat(a, b) strcat(a, b)
26885 #define yaffs_strcpy(a, b) strcpy(a, b)
26886 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
26887 -#define yaffs_strlen(s) strlen(s)
26888 +#define yaffs_strnlen(s,m) strnlen(s,m)
26889 #define yaffs_sprintf sprintf
26890 #define yaffs_toupper(a) toupper(a)
26892 @@ -146,10 +142,10 @@
26893 #define YAFFS_LOSTNFOUND_PREFIX "obj"
26894 /* #define YPRINTF(x) printf x */
26896 -#define YAFFS_ROOT_MODE 0666
26897 -#define YAFFS_LOSTNFOUND_MODE 0666
26898 +#define YAFFS_ROOT_MODE 0755
26899 +#define YAFFS_LOSTNFOUND_MODE 0700
26901 -#define yaffs_SumCompare(x, y) ((x) == (y))
26902 +#define yaffs_sum_cmp(x, y) ((x) == (y))
26903 #define yaffs_strcmp(a, b) strcmp(a, b)
26906 @@ -158,46 +154,180 @@
26910 -/* see yaffs_fs.c */
26911 -extern unsigned int yaffs_traceMask;
26912 -extern unsigned int yaffs_wr_attempts;
26913 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
26917 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
26919 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
26922 +#define O_RDONLY 00
26926 +#define O_WRONLY 01
26934 +#define O_CREAT 0100
26938 +#define O_EXCL 0200
26942 +#define O_TRUNC 01000
26946 +#define O_APPEND 02000
26950 +#define SEEK_SET 0
26954 +#define SEEK_CUR 1
26958 +#define SEEK_END 2
26998 +#define ENODATA 61
27002 +#define ENOTEMPTY 39
27005 +#ifndef ENAMETOOLONG
27006 +#define ENAMETOOLONG 36
27018 +#define ENOTDIR 20
27029 +#define S_IFMT 0170000
27033 +#define S_IFLNK 0120000
27036 -#define YAFFS_TRACE_OS 0x00000002
27037 -#define YAFFS_TRACE_ALLOCATE 0x00000004
27038 -#define YAFFS_TRACE_SCAN 0x00000008
27039 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
27040 -#define YAFFS_TRACE_ERASE 0x00000020
27041 -#define YAFFS_TRACE_GC 0x00000040
27042 -#define YAFFS_TRACE_WRITE 0x00000080
27043 -#define YAFFS_TRACE_TRACING 0x00000100
27044 -#define YAFFS_TRACE_DELETION 0x00000200
27045 -#define YAFFS_TRACE_BUFFERS 0x00000400
27046 -#define YAFFS_TRACE_NANDACCESS 0x00000800
27047 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
27048 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
27049 -#define YAFFS_TRACE_MTD 0x00004000
27050 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
27052 -#define YAFFS_TRACE_VERIFY 0x00010000
27053 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
27054 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
27055 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
27058 -#define YAFFS_TRACE_ERROR 0x40000000
27059 -#define YAFFS_TRACE_BUG 0x80000000
27060 -#define YAFFS_TRACE_ALWAYS 0xF0000000
27062 +#define S_IFDIR 0040000
27066 +#define S_IFREG 0100000
27070 +#define S_IREAD 0000400
27074 +#define S_IWRITE 0000200
27077 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
27079 +#define S_IEXEC 0000100
27082 +#ifndef XATTR_CREATE
27083 +#define XATTR_CREATE 1
27086 +#ifndef XATTR_REPLACE
27087 +#define XATTR_REPLACE 2
27098 +#include <errno.h>
27099 +#include <sys/stat.h>
27100 +#include <fcntl.h>
27105 +#ifndef Y_DUMP_STACK
27106 +#define Y_DUMP_STACK() do { } while (0)
27110 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
27111 +#define YBUG() do {\
27112 + T(YAFFS_TRACE_BUG,\
27113 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\