linux/atheros: fix another 2.6.36 patch issue
[openwrt.git] / target / linux / generic / patches-2.6.36 / 511-yaffs-git-2010-10-01.patch
1 --- a/fs/yaffs2/devextras.h
2 +++ b/fs/yaffs2/devextras.h
3 @@ -1,7 +1,7 @@
4 /*
5 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
6 *
7 - * Copyright (C) 2002-2007 Aleph One Ltd.
8 + * Copyright (C) 2002-2010 Aleph One Ltd.
9 * for Toby Churchill Ltd and Brightstar Engineering
10 *
11 * Created by Charles Manning <charles@aleph1.co.uk>
12 @@ -24,6 +24,8 @@
13 #define __EXTRAS_H__
14
15
16 +#include "yportenv.h"
17 +
18 #if !(defined __KERNEL__)
19
20 /* Definition of types */
21 @@ -33,103 +35,6 @@ typedef unsigned __u32;
22
23 #endif
24
25 -/*
26 - * This is a simple doubly linked list implementation that matches the
27 - * way the Linux kernel doubly linked list implementation works.
28 - */
29 -
30 -struct ylist_head {
31 - struct ylist_head *next; /* next in chain */
32 - struct ylist_head *prev; /* previous in chain */
33 -};
34 -
35 -
36 -/* Initialise a static list */
37 -#define YLIST_HEAD(name) \
38 -struct ylist_head name = { &(name), &(name)}
39 -
40 -
41 -
42 -/* Initialise a list head to an empty list */
43 -#define YINIT_LIST_HEAD(p) \
44 -do { \
45 - (p)->next = (p);\
46 - (p)->prev = (p); \
47 -} while (0)
48 -
49 -
50 -/* Add an element to a list */
51 -static __inline__ void ylist_add(struct ylist_head *newEntry,
52 - struct ylist_head *list)
53 -{
54 - struct ylist_head *listNext = list->next;
55 -
56 - list->next = newEntry;
57 - newEntry->prev = list;
58 - newEntry->next = listNext;
59 - listNext->prev = newEntry;
60 -
61 -}
62 -
63 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
64 - struct ylist_head *list)
65 -{
66 - struct ylist_head *listPrev = list->prev;
67 -
68 - list->prev = newEntry;
69 - newEntry->next = list;
70 - newEntry->prev = listPrev;
71 - listPrev->next = newEntry;
72 -
73 -}
74 -
75 -
76 -/* Take an element out of its current list, with or without
77 - * reinitialising the links.of the entry*/
78 -static __inline__ void ylist_del(struct ylist_head *entry)
79 -{
80 - struct ylist_head *listNext = entry->next;
81 - struct ylist_head *listPrev = entry->prev;
82 -
83 - listNext->prev = listPrev;
84 - listPrev->next = listNext;
85 -
86 -}
87 -
88 -static __inline__ void ylist_del_init(struct ylist_head *entry)
89 -{
90 - ylist_del(entry);
91 - entry->next = entry->prev = entry;
92 -}
93 -
94 -
95 -/* Test if the list is empty */
96 -static __inline__ int ylist_empty(struct ylist_head *entry)
97 -{
98 - return (entry->next == entry);
99 -}
100 -
101 -
102 -/* ylist_entry takes a pointer to a list entry and offsets it to that
103 - * we can find a pointer to the object it is embedded in.
104 - */
105 -
106 -
107 -#define ylist_entry(entry, type, member) \
108 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
109 -
110 -
111 -/* ylist_for_each and list_for_each_safe iterate over lists.
112 - * ylist_for_each_safe uses temporary storage to make the list delete safe
113 - */
114 -
115 -#define ylist_for_each(itervar, list) \
116 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
117 -
118 -#define ylist_for_each_safe(itervar, saveVar, list) \
119 - for (itervar = (list)->next, saveVar = (list)->next->next; \
120 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
121 -
122
123 #if !(defined __KERNEL__)
124
125 --- a/fs/yaffs2/Kconfig
126 +++ b/fs/yaffs2/Kconfig
127 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
128
129 If unsure, say Y.
130
131 -config YAFFS_DISABLE_LAZY_LOAD
132 - bool "Disable lazy loading"
133 - depends on YAFFS_YAFFS2
134 +config YAFFS_DISABLE_TAGS_ECC
135 + bool "Disable YAFFS from doing ECC on tags by default"
136 + depends on YAFFS_FS && YAFFS_YAFFS2
137 default n
138 help
139 - "Lazy loading" defers loading file details until they are
140 - required. This saves mount time, but makes the first look-up
141 - a bit longer.
142 -
143 - Lazy loading will only happen if enabled by this option being 'n'
144 - and if the appropriate tags are available, else yaffs2 will
145 - automatically fall back to immediate loading and do the right
146 - thing.
147 -
148 - Lazy laoding will be required by checkpointing.
149 -
150 - Setting this to 'y' will disable lazy loading.
151 + This defaults Yaffs to using its own ECC calculations on tags instead of
152 + just relying on the MTD.
153 + This behavior can also be overridden with tags_ecc_on and
154 + tags_ecc_off mount options.
155
156 If unsure, say N.
157
158 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
159 but makes look-ups faster.
160
161 If unsure, say Y.
162 +
163 +config YAFFS_EMPTY_LOST_AND_FOUND
164 + bool "Empty lost and found on boot"
165 + depends on YAFFS_FS
166 + default n
167 + help
168 + If this is enabled then the contents of lost and found is
169 + automatically dumped at mount.
170 +
171 + If unsure, say N.
172 +
173 +config YAFFS_DISABLE_BLOCK_REFRESHING
174 + bool "Disable yaffs2 block refreshing"
175 + depends on YAFFS_FS
176 + default n
177 + help
178 + If this is set, then block refreshing is disabled.
179 + Block refreshing infrequently refreshes the oldest block in
180 + a yaffs2 file system. This mechanism helps to refresh flash to
181 + mitigate against data loss. This is particularly useful for MLC.
182 +
183 + If unsure, say N.
184 +
185 +config YAFFS_DISABLE_BACKGROUND
186 + bool "Disable yaffs2 background processing"
187 + depends on YAFFS_FS
188 + default n
189 + help
190 + If this is set, then background processing is disabled.
191 + Background processing makes many foreground activities faster.
192 +
193 + If unsure, say N.
194 +
195 +config YAFFS_XATTR
196 + bool "Enable yaffs2 xattr support"
197 + depends on YAFFS_FS
198 + default y
199 + help
200 + If this is set then yaffs2 will provide xattr support.
201 + If unsure, say Y.
202 +
203 +
204 --- a/fs/yaffs2/Makefile
205 +++ b/fs/yaffs2/Makefile
206 @@ -4,7 +4,14 @@
207
208 obj-$(CONFIG_YAFFS_FS) += yaffs.o
209
210 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
211 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
212 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
213 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
214 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
215 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
216 +yaffs-y += yaffs_nameval.o
217 +yaffs-y += yaffs_allocator.o
218 +yaffs-y += yaffs_yaffs1.o
219 +yaffs-y += yaffs_yaffs2.o
220 +yaffs-y += yaffs_bitmap.o
221 +yaffs-y += yaffs_verify.o
222 +
223 --- a/fs/yaffs2/moduleconfig.h
224 +++ b/fs/yaffs2/moduleconfig.h
225 @@ -1,7 +1,7 @@
226 /*
227 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
228 *
229 - * Copyright (C) 2002-2007 Aleph One Ltd.
230 + * Copyright (C) 2002-2010 Aleph One Ltd.
231 * for Toby Churchill Ltd and Brightstar Engineering
232 *
233 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
234 @@ -29,22 +29,43 @@
235 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
236 /* #define CONFIG_YAFFS_DOES_ECC */
237
238 +/* Default: Selected */
239 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
240 +#define CONFIG_YAFFS_DOES_TAGS_ECC
241 +
242 /* Default: Not selected */
243 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
244 /* CONFIG_YAFFS_DOES_ECC is set */
245 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
246
247 -/* Default: Selected */
248 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
249 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
250 +/* Default: Not selected */
251 +/* Meaning: Always test whether chunks are erased before writing to them.
252 + Use during mtd debugging and init. */
253 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
254 +
255 +/* Default: Not Selected */
256 +/* Meaning: At mount automatically empty all files from lost and found. */
257 +/* This is done to fix an old problem where rmdir was not checking for an */
258 +/* empty directory. This can also be achieved with a mount option. */
259 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
260
261 /* Default: Selected */
262 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
263 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
264
265 -/* Default: 10 */
266 -/* Meaning: set the count of blocks to reserve for checkpointing */
267 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
268 +/* Default: Unselected */
269 +/* Meaning: Select to disable block refreshing. */
270 +/* Block Refreshing periodically rewrites the oldest block. */
271 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
272 +
273 +/* Default: Unselected */
274 +/* Meaning: Select to disable background processing */
275 +/* #define CONFIG_DISABLE_BACKGROUND */
276 +
277 +
278 +/* Default: Selected */
279 +/* Meaning: Enable XATTR support */
280 +#define CONFIG_YAFFS_XATTR
281
282 /*
283 Older-style on-NAND data format has a "pageStatus" byte to record
284 --- /dev/null
285 +++ b/fs/yaffs2/yaffs_allocator.c
286 @@ -0,0 +1,409 @@
287 +/*
288 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
289 + *
290 + * Copyright (C) 2002-2010 Aleph One Ltd.
291 + * for Toby Churchill Ltd and Brightstar Engineering
292 + *
293 + * Created by Charles Manning <charles@aleph1.co.uk>
294 + *
295 + * This program is free software; you can redistribute it and/or modify
296 + * it under the terms of the GNU Lesser General Public License version 2.1 as
297 + * published by the Free Software Foundation.
298 + *
299 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
300 + */
301 +
302 +
303 +#include "yaffs_allocator.h"
304 +#include "yaffs_guts.h"
305 +#include "yaffs_trace.h"
306 +#include "yportenv.h"
307 +
308 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
309 +
310 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
311 +{
312 + dev = dev;
313 +}
314 +
315 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
316 +{
317 + dev = dev;
318 +}
319 +
320 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
321 +{
322 + return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
323 +}
324 +
325 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
326 +{
327 + dev = dev;
328 + YFREE(tn);
329 +}
330 +
331 +void yaffs_InitialiseRawObjects(yaffs_Device *dev)
332 +{
333 + dev = dev;
334 +}
335 +
336 +void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
337 +{
338 + dev = dev;
339 +}
340 +
341 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
342 +{
343 + dev = dev;
344 + return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
345 +}
346 +
347 +
348 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
349 +{
350 +
351 + dev = dev;
352 + YFREE(obj);
353 +}
354 +
355 +#else
356 +
357 +struct yaffs_TnodeList_struct {
358 + struct yaffs_TnodeList_struct *next;
359 + yaffs_Tnode *tnodes;
360 +};
361 +
362 +typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
363 +
364 +struct yaffs_ObjectList_struct {
365 + yaffs_Object *objects;
366 + struct yaffs_ObjectList_struct *next;
367 +};
368 +
369 +typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
370 +
371 +
372 +struct yaffs_AllocatorStruct {
373 + int nTnodesCreated;
374 + yaffs_Tnode *freeTnodes;
375 + int nFreeTnodes;
376 + yaffs_TnodeList *allocatedTnodeList;
377 +
378 + int nObjectsCreated;
379 + yaffs_Object *freeObjects;
380 + int nFreeObjects;
381 +
382 + yaffs_ObjectList *allocatedObjectList;
383 +};
384 +
385 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
386 +
387 +
388 +static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
389 +{
390 +
391 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
392 +
393 + yaffs_TnodeList *tmp;
394 +
395 + if(!allocator){
396 + YBUG();
397 + return;
398 + }
399 +
400 + while (allocator->allocatedTnodeList) {
401 + tmp = allocator->allocatedTnodeList->next;
402 +
403 + YFREE(allocator->allocatedTnodeList->tnodes);
404 + YFREE(allocator->allocatedTnodeList);
405 + allocator->allocatedTnodeList = tmp;
406 +
407 + }
408 +
409 + allocator->freeTnodes = NULL;
410 + allocator->nFreeTnodes = 0;
411 + allocator->nTnodesCreated = 0;
412 +}
413 +
414 +static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
415 +{
416 + yaffs_Allocator *allocator = dev->allocator;
417 +
418 + if(allocator){
419 + allocator->allocatedTnodeList = NULL;
420 + allocator->freeTnodes = NULL;
421 + allocator->nFreeTnodes = 0;
422 + allocator->nTnodesCreated = 0;
423 + } else
424 + YBUG();
425 +}
426 +
427 +static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
428 +{
429 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
430 + int i;
431 + yaffs_Tnode *newTnodes;
432 + __u8 *mem;
433 + yaffs_Tnode *curr;
434 + yaffs_Tnode *next;
435 + yaffs_TnodeList *tnl;
436 +
437 + if(!allocator){
438 + YBUG();
439 + return YAFFS_FAIL;
440 + }
441 +
442 + if (nTnodes < 1)
443 + return YAFFS_OK;
444 +
445 +
446 + /* make these things */
447 +
448 + newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
449 + mem = (__u8 *)newTnodes;
450 +
451 + if (!newTnodes) {
452 + T(YAFFS_TRACE_ERROR,
453 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
454 + return YAFFS_FAIL;
455 + }
456 +
457 + /* New hookup for wide tnodes */
458 + for (i = 0; i < nTnodes - 1; i++) {
459 + curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
460 + next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
461 + curr->internal[0] = next;
462 + }
463 +
464 + curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
465 + curr->internal[0] = allocator->freeTnodes;
466 + allocator->freeTnodes = (yaffs_Tnode *)mem;
467 +
468 + allocator->nFreeTnodes += nTnodes;
469 + allocator->nTnodesCreated += nTnodes;
470 +
471 + /* Now add this bunch of tnodes to a list for freeing up.
472 + * NB If we can't add this to the management list it isn't fatal
473 + * but it just means we can't free this bunch of tnodes later.
474 + */
475 +
476 + tnl = YMALLOC(sizeof(yaffs_TnodeList));
477 + if (!tnl) {
478 + T(YAFFS_TRACE_ERROR,
479 + (TSTR
480 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
481 + return YAFFS_FAIL;
482 + } else {
483 + tnl->tnodes = newTnodes;
484 + tnl->next = allocator->allocatedTnodeList;
485 + allocator->allocatedTnodeList = tnl;
486 + }
487 +
488 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
489 +
490 + return YAFFS_OK;
491 +}
492 +
493 +
494 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
495 +{
496 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
497 + yaffs_Tnode *tn = NULL;
498 +
499 + if(!allocator){
500 + YBUG();
501 + return NULL;
502 + }
503 +
504 + /* If there are none left make more */
505 + if (!allocator->freeTnodes)
506 + yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
507 +
508 + if (allocator->freeTnodes) {
509 + tn = allocator->freeTnodes;
510 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
511 + allocator->nFreeTnodes--;
512 + }
513 +
514 + return tn;
515 +}
516 +
517 +/* FreeTnode frees up a tnode and puts it back on the free list */
518 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
519 +{
520 + yaffs_Allocator *allocator = dev->allocator;
521 +
522 + if(!allocator){
523 + YBUG();
524 + return;
525 + }
526 +
527 + if (tn) {
528 + tn->internal[0] = allocator->freeTnodes;
529 + allocator->freeTnodes = tn;
530 + allocator->nFreeTnodes++;
531 + }
532 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
533 +}
534 +
535 +
536 +
537 +static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
538 +{
539 + yaffs_Allocator *allocator = dev->allocator;
540 +
541 + if(allocator) {
542 + allocator->allocatedObjectList = NULL;
543 + allocator->freeObjects = NULL;
544 + allocator->nFreeObjects = 0;
545 + } else
546 + YBUG();
547 +}
548 +
549 +static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
550 +{
551 + yaffs_Allocator *allocator = dev->allocator;
552 + yaffs_ObjectList *tmp;
553 +
554 + if(!allocator){
555 + YBUG();
556 + return;
557 + }
558 +
559 + while (allocator->allocatedObjectList) {
560 + tmp = allocator->allocatedObjectList->next;
561 + YFREE(allocator->allocatedObjectList->objects);
562 + YFREE(allocator->allocatedObjectList);
563 +
564 + allocator->allocatedObjectList = tmp;
565 + }
566 +
567 + allocator->freeObjects = NULL;
568 + allocator->nFreeObjects = 0;
569 + allocator->nObjectsCreated = 0;
570 +}
571 +
572 +
573 +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
574 +{
575 + yaffs_Allocator *allocator = dev->allocator;
576 +
577 + int i;
578 + yaffs_Object *newObjects;
579 + yaffs_ObjectList *list;
580 +
581 + if(!allocator){
582 + YBUG();
583 + return YAFFS_FAIL;
584 + }
585 +
586 + if (nObjects < 1)
587 + return YAFFS_OK;
588 +
589 + /* make these things */
590 + newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
591 + list = YMALLOC(sizeof(yaffs_ObjectList));
592 +
593 + if (!newObjects || !list) {
594 + if (newObjects){
595 + YFREE(newObjects);
596 + newObjects = NULL;
597 + }
598 + if (list){
599 + YFREE(list);
600 + list = NULL;
601 + }
602 + T(YAFFS_TRACE_ALLOCATE,
603 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
604 + return YAFFS_FAIL;
605 + }
606 +
607 + /* Hook them into the free list */
608 + for (i = 0; i < nObjects - 1; i++) {
609 + newObjects[i].siblings.next =
610 + (struct ylist_head *)(&newObjects[i + 1]);
611 + }
612 +
613 + newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
614 + allocator->freeObjects = newObjects;
615 + allocator->nFreeObjects += nObjects;
616 + allocator->nObjectsCreated += nObjects;
617 +
618 + /* Now add this bunch of Objects to a list for freeing up. */
619 +
620 + list->objects = newObjects;
621 + list->next = allocator->allocatedObjectList;
622 + allocator->allocatedObjectList = list;
623 +
624 + return YAFFS_OK;
625 +}
626 +
627 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
628 +{
629 + yaffs_Object *obj = NULL;
630 + yaffs_Allocator *allocator = dev->allocator;
631 +
632 + if(!allocator) {
633 + YBUG();
634 + return obj;
635 + }
636 +
637 + /* If there are none left make more */
638 + if (!allocator->freeObjects)
639 + yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
640 +
641 + if (allocator->freeObjects) {
642 + obj = allocator->freeObjects;
643 + allocator->freeObjects =
644 + (yaffs_Object *) (allocator->freeObjects->siblings.next);
645 + allocator->nFreeObjects--;
646 + }
647 +
648 + return obj;
649 +}
650 +
651 +
652 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
653 +{
654 +
655 + yaffs_Allocator *allocator = dev->allocator;
656 +
657 + if(!allocator)
658 + YBUG();
659 + else {
660 + /* Link into the free list. */
661 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
662 + allocator->freeObjects = obj;
663 + allocator->nFreeObjects++;
664 + }
665 +}
666 +
667 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
668 +{
669 + if(dev->allocator){
670 + yaffs_DeinitialiseRawTnodes(dev);
671 + yaffs_DeinitialiseRawObjects(dev);
672 +
673 + YFREE(dev->allocator);
674 + dev->allocator=NULL;
675 + } else
676 + YBUG();
677 +}
678 +
679 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
680 +{
681 + yaffs_Allocator *allocator;
682 +
683 + if(!dev->allocator){
684 + allocator = YMALLOC(sizeof(yaffs_Allocator));
685 + if(allocator){
686 + dev->allocator = allocator;
687 + yaffs_InitialiseRawTnodes(dev);
688 + yaffs_InitialiseRawObjects(dev);
689 + }
690 + } else
691 + YBUG();
692 +}
693 +
694 +
695 +#endif
696 --- /dev/null
697 +++ b/fs/yaffs2/yaffs_allocator.h
698 @@ -0,0 +1,30 @@
699 +/*
700 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
701 + *
702 + * Copyright (C) 2002-2010 Aleph One Ltd.
703 + * for Toby Churchill Ltd and Brightstar Engineering
704 + *
705 + * Created by Charles Manning <charles@aleph1.co.uk>
706 + *
707 + * This program is free software; you can redistribute it and/or modify
708 + * it under the terms of the GNU Lesser General Public License version 2.1 as
709 + * published by the Free Software Foundation.
710 + *
711 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
712 + */
713 +
714 +#ifndef __YAFFS_ALLOCATOR_H__
715 +#define __YAFFS_ALLOCATOR_H__
716 +
717 +#include "yaffs_guts.h"
718 +
719 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
720 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
721 +
722 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
723 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
724 +
725 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
726 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
727 +
728 +#endif
729 --- /dev/null
730 +++ b/fs/yaffs2/yaffs_bitmap.c
731 @@ -0,0 +1,105 @@
732 +/*
733 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
734 + *
735 + * Copyright (C) 2002-2010 Aleph One Ltd.
736 + * for Toby Churchill Ltd and Brightstar Engineering
737 + *
738 + * Created by Charles Manning <charles@aleph1.co.uk>
739 + *
740 + * This program is free software; you can redistribute it and/or modify
741 + * it under the terms of the GNU General Public License version 2 as
742 + * published by the Free Software Foundation.
743 + */
744 +
745 +#include "yaffs_bitmap.h"
746 +#include "yaffs_trace.h"
747 +/*
748 + * Chunk bitmap manipulations
749 + */
750 +
751 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
752 +{
753 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
754 + T(YAFFS_TRACE_ERROR,
755 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
756 + blk));
757 + YBUG();
758 + }
759 + return dev->chunkBits +
760 + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
761 +}
762 +
763 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
764 +{
765 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
766 + chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
767 + T(YAFFS_TRACE_ERROR,
768 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
769 + blk, chunk));
770 + YBUG();
771 + }
772 +}
773 +
774 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
775 +{
776 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
777 +
778 + memset(blkBits, 0, dev->chunkBitmapStride);
779 +}
780 +
781 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
782 +{
783 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
784 +
785 + yaffs_VerifyChunkBitId(dev, blk, chunk);
786 +
787 + blkBits[chunk / 8] &= ~(1 << (chunk & 7));
788 +}
789 +
790 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
791 +{
792 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
793 +
794 + yaffs_VerifyChunkBitId(dev, blk, chunk);
795 +
796 + blkBits[chunk / 8] |= (1 << (chunk & 7));
797 +}
798 +
799 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
800 +{
801 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
802 + yaffs_VerifyChunkBitId(dev, blk, chunk);
803 +
804 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
805 +}
806 +
807 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
808 +{
809 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
810 + int i;
811 + for (i = 0; i < dev->chunkBitmapStride; i++) {
812 + if (*blkBits)
813 + return 1;
814 + blkBits++;
815 + }
816 + return 0;
817 +}
818 +
819 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
820 +{
821 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
822 + int i;
823 + int n = 0;
824 + for (i = 0; i < dev->chunkBitmapStride; i++) {
825 + __u8 x = *blkBits;
826 + while (x) {
827 + if (x & 1)
828 + n++;
829 + x >>= 1;
830 + }
831 +
832 + blkBits++;
833 + }
834 + return n;
835 +}
836 +
837 --- /dev/null
838 +++ b/fs/yaffs2/yaffs_bitmap.h
839 @@ -0,0 +1,31 @@
840 +/*
841 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
842 + *
843 + * Copyright (C) 2002-2010 Aleph One Ltd.
844 + * for Toby Churchill Ltd and Brightstar Engineering
845 + *
846 + * Created by Charles Manning <charles@aleph1.co.uk>
847 + *
848 + * This program is free software; you can redistribute it and/or modify
849 + * it under the terms of the GNU General Public License version 2 as
850 + * published by the Free Software Foundation.
851 + */
852 +
853 +/*
854 + * Chunk bitmap manipulations
855 + */
856 +
857 +#ifndef __YAFFS_BITMAP_H__
858 +#define __YAFFS_BITMAP_H__
859 +
860 +#include "yaffs_guts.h"
861 +
862 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
863 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
864 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
865 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
866 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
867 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
868 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
869 +
870 +#endif
871 --- a/fs/yaffs2/yaffs_checkptrw.c
872 +++ b/fs/yaffs2/yaffs_checkptrw.c
873 @@ -1,7 +1,7 @@
874 /*
875 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
876 *
877 - * Copyright (C) 2002-2007 Aleph One Ltd.
878 + * Copyright (C) 2002-2010 Aleph One Ltd.
879 * for Toby Churchill Ltd and Brightstar Engineering
880 *
881 * Created by Charles Manning <charles@aleph1.co.uk>
882 @@ -11,16 +11,12 @@
883 * published by the Free Software Foundation.
884 */
885
886 -const char *yaffs_checkptrw_c_version =
887 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
888 -
889 -
890 #include "yaffs_checkptrw.h"
891 #include "yaffs_getblockinfo.h"
892
893 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
894 +static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev)
895 {
896 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
897 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
898
899 T(YAFFS_TRACE_CHECKPOINT,
900 (TSTR("checkpt blocks available = %d" TENDSTR),
901 @@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs
902 }
903
904
905 -static int yaffs_CheckpointErase(yaffs_Device *dev)
906 +static int yaffs2_CheckpointErase(yaffs_Device *dev)
907 {
908 int i;
909
910 - if (!dev->eraseBlockInNAND)
911 + if (!dev->param.eraseBlockInNAND)
912 return 0;
913 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
914 dev->internalStartBlock, dev->internalEndBlock));
915 @@ -43,12 +39,15 @@ static int yaffs_CheckpointErase(yaffs_D
916 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
917 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
918 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
919 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
920 +
921 + dev->nBlockErasures++;
922 +
923 + if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
924 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
925 dev->nErasedBlocks++;
926 - dev->nFreeChunks += dev->nChunksPerBlock;
927 + dev->nFreeChunks += dev->param.nChunksPerBlock;
928 } else {
929 - dev->markNANDBlockBad(dev, i);
930 + dev->param.markNANDBlockBad(dev, i);
931 bi->blockState = YAFFS_BLOCK_STATE_DEAD;
932 }
933 }
934 @@ -60,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_D
935 }
936
937
938 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
939 +static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev)
940 {
941 int i;
942 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
943 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
944 T(YAFFS_TRACE_CHECKPOINT,
945 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
946 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
947 + dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
948
949 if (dev->checkpointNextBlock >= 0 &&
950 dev->checkpointNextBlock <= dev->internalEndBlock &&
951 @@ -88,7 +87,7 @@ static void yaffs_CheckpointFindNextEras
952 dev->checkpointCurrentBlock = -1;
953 }
954
955 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
956 +static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
957 {
958 int i;
959 yaffs_ExtendedTags tags;
960 @@ -98,10 +97,10 @@ static void yaffs_CheckpointFindNextChec
961
962 if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
963 for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
964 - int chunk = i * dev->nChunksPerBlock;
965 + int chunk = i * dev->param.nChunksPerBlock;
966 int realignedChunk = chunk - dev->chunkOffset;
967
968 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
969 + dev->param.readChunkWithTagsFromNAND(dev, realignedChunk,
970 NULL, &tags);
971 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
972 i, tags.objectId, tags.sequenceNumber, tags.eccResult));
973 @@ -124,29 +123,29 @@ static void yaffs_CheckpointFindNextChec
974 }
975
976
977 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
978 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting)
979 {
980
981 +
982 + dev->checkpointOpenForWrite = forWriting;
983 +
984 /* Got the functions we need? */
985 - if (!dev->writeChunkWithTagsToNAND ||
986 - !dev->readChunkWithTagsFromNAND ||
987 - !dev->eraseBlockInNAND ||
988 - !dev->markNANDBlockBad)
989 + if (!dev->param.writeChunkWithTagsToNAND ||
990 + !dev->param.readChunkWithTagsFromNAND ||
991 + !dev->param.eraseBlockInNAND ||
992 + !dev->param.markNANDBlockBad)
993 return 0;
994
995 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
996 + if (forWriting && !yaffs2_CheckpointSpaceOk(dev))
997 return 0;
998
999 if (!dev->checkpointBuffer)
1000 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1001 + dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk);
1002 if (!dev->checkpointBuffer)
1003 return 0;
1004
1005
1006 dev->checkpointPageSequence = 0;
1007 -
1008 - dev->checkpointOpenForWrite = forWriting;
1009 -
1010 dev->checkpointByteCount = 0;
1011 dev->checkpointSum = 0;
1012 dev->checkpointXor = 0;
1013 @@ -158,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1014 if (forWriting) {
1015 memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1016 dev->checkpointByteOffset = 0;
1017 - return yaffs_CheckpointErase(dev);
1018 + return yaffs2_CheckpointErase(dev);
1019 } else {
1020 int i;
1021 /* Set to a value that will kick off a read */
1022 @@ -168,6 +167,9 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1023 dev->blocksInCheckpoint = 0;
1024 dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1025 dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1026 + if(!dev->checkpointBlockList)
1027 + return 0;
1028 +
1029 for (i = 0; i < dev->checkpointMaxBlocks; i++)
1030 dev->checkpointBlockList[i] = -1;
1031 }
1032 @@ -175,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1033 return 1;
1034 }
1035
1036 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1037 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1038 {
1039 __u32 compositeSum;
1040 compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1041 @@ -183,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device
1042 return 1;
1043 }
1044
1045 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1046 +static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev)
1047 {
1048 int chunk;
1049 int realignedChunk;
1050 @@ -191,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(y
1051 yaffs_ExtendedTags tags;
1052
1053 if (dev->checkpointCurrentBlock < 0) {
1054 - yaffs_CheckpointFindNextErasedBlock(dev);
1055 + yaffs2_CheckpointFindNextErasedBlock(dev);
1056 dev->checkpointCurrentChunk = 0;
1057 }
1058
1059 @@ -211,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(y
1060 dev->blocksInCheckpoint++;
1061 }
1062
1063 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1064 + chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk;
1065
1066
1067 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1068 @@ -219,12 +221,14 @@ static int yaffs_CheckpointFlushBuffer(y
1069
1070 realignedChunk = chunk - dev->chunkOffset;
1071
1072 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1073 + dev->nPageWrites++;
1074 +
1075 + dev->param.writeChunkWithTagsToNAND(dev, realignedChunk,
1076 dev->checkpointBuffer, &tags);
1077 dev->checkpointByteOffset = 0;
1078 dev->checkpointPageSequence++;
1079 dev->checkpointCurrentChunk++;
1080 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1081 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) {
1082 dev->checkpointCurrentChunk = 0;
1083 dev->checkpointCurrentBlock = -1;
1084 }
1085 @@ -234,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(y
1086 }
1087
1088
1089 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1090 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1091 {
1092 int i = 0;
1093 int ok = 1;
1094 @@ -263,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *
1095
1096 if (dev->checkpointByteOffset < 0 ||
1097 dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1098 - ok = yaffs_CheckpointFlushBuffer(dev);
1099 + ok = yaffs2_CheckpointFlushBuffer(dev);
1100 }
1101
1102 return i;
1103 }
1104
1105 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1106 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1107 {
1108 int i = 0;
1109 int ok = 1;
1110 @@ -294,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1111 dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1112
1113 if (dev->checkpointCurrentBlock < 0) {
1114 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1115 + yaffs2_CheckpointFindNextCheckpointBlock(dev);
1116 dev->checkpointCurrentChunk = 0;
1117 }
1118
1119 @@ -302,14 +306,16 @@ int yaffs_CheckpointRead(yaffs_Device *d
1120 ok = 0;
1121 else {
1122 chunk = dev->checkpointCurrentBlock *
1123 - dev->nChunksPerBlock +
1124 + dev->param.nChunksPerBlock +
1125 dev->checkpointCurrentChunk;
1126
1127 realignedChunk = chunk - dev->chunkOffset;
1128 +
1129 + dev->nPageReads++;
1130
1131 /* read in the next chunk */
1132 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1133 - dev->readChunkWithTagsFromNAND(dev,
1134 + dev->param.readChunkWithTagsFromNAND(dev,
1135 realignedChunk,
1136 dev->checkpointBuffer,
1137 &tags);
1138 @@ -323,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1139 dev->checkpointPageSequence++;
1140 dev->checkpointCurrentChunk++;
1141
1142 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1143 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock)
1144 dev->checkpointCurrentBlock = -1;
1145 }
1146 }
1147 @@ -342,17 +348,20 @@ int yaffs_CheckpointRead(yaffs_Device *d
1148 return i;
1149 }
1150
1151 -int yaffs_CheckpointClose(yaffs_Device *dev)
1152 +int yaffs2_CheckpointClose(yaffs_Device *dev)
1153 {
1154
1155 if (dev->checkpointOpenForWrite) {
1156 if (dev->checkpointByteOffset != 0)
1157 - yaffs_CheckpointFlushBuffer(dev);
1158 - } else {
1159 + yaffs2_CheckpointFlushBuffer(dev);
1160 + } else if(dev->checkpointBlockList){
1161 int i;
1162 for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1163 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1164 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1165 + int blk = dev->checkpointBlockList[i];
1166 + yaffs_BlockInfo *bi = NULL;
1167 + if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
1168 + bi = yaffs_GetBlockInfo(dev, blk);
1169 + if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1170 bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1171 else {
1172 /* Todo this looks odd... */
1173 @@ -362,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *
1174 dev->checkpointBlockList = NULL;
1175 }
1176
1177 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1178 + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock;
1179 dev->nErasedBlocks -= dev->blocksInCheckpoint;
1180
1181
1182 @@ -378,16 +387,14 @@ int yaffs_CheckpointClose(yaffs_Device *
1183 return 0;
1184 }
1185
1186 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1187 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev)
1188 {
1189 - /* Erase the first checksum block */
1190 -
1191 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1192 + /* Erase the checkpoint data */
1193
1194 - if (!yaffs_CheckpointSpaceOk(dev))
1195 - return 0;
1196 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1197 + dev->blocksInCheckpoint));
1198
1199 - return yaffs_CheckpointErase(dev);
1200 + return yaffs2_CheckpointErase(dev);
1201 }
1202
1203
1204 --- a/fs/yaffs2/yaffs_checkptrw.h
1205 +++ b/fs/yaffs2/yaffs_checkptrw.h
1206 @@ -1,7 +1,7 @@
1207 /*
1208 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1209 *
1210 - * Copyright (C) 2002-2007 Aleph One Ltd.
1211 + * Copyright (C) 2002-2010 Aleph One Ltd.
1212 * for Toby Churchill Ltd and Brightstar Engineering
1213 *
1214 * Created by Charles Manning <charles@aleph1.co.uk>
1215 @@ -18,18 +18,17 @@
1216
1217 #include "yaffs_guts.h"
1218
1219 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1220 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting);
1221
1222 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1223 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1224
1225 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1226 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1227
1228 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1229 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1230
1231 -int yaffs_CheckpointClose(yaffs_Device *dev);
1232 +int yaffs2_CheckpointClose(yaffs_Device *dev);
1233
1234 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1235 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev);
1236
1237
1238 #endif
1239 -
1240 --- a/fs/yaffs2/yaffs_ecc.c
1241 +++ b/fs/yaffs2/yaffs_ecc.c
1242 @@ -1,7 +1,7 @@
1243 /*
1244 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1245 *
1246 - * Copyright (C) 2002-2007 Aleph One Ltd.
1247 + * Copyright (C) 2002-2010 Aleph One Ltd.
1248 * for Toby Churchill Ltd and Brightstar Engineering
1249 *
1250 * Created by Charles Manning <charles@aleph1.co.uk>
1251 @@ -28,9 +28,6 @@
1252 * this bytes influence on the line parity.
1253 */
1254
1255 -const char *yaffs_ecc_c_version =
1256 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1257 -
1258 #include "yportenv.h"
1259
1260 #include "yaffs_ecc.h"
1261 --- a/fs/yaffs2/yaffs_ecc.h
1262 +++ b/fs/yaffs2/yaffs_ecc.h
1263 @@ -1,7 +1,7 @@
1264 /*
1265 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1266 *
1267 - * Copyright (C) 2002-2007 Aleph One Ltd.
1268 + * Copyright (C) 2002-2010 Aleph One Ltd.
1269 * for Toby Churchill Ltd and Brightstar Engineering
1270 *
1271 * Created by Charles Manning <charles@aleph1.co.uk>
1272 --- a/fs/yaffs2/yaffs_fs.c
1273 +++ /dev/null
1274 @@ -1,2529 +0,0 @@
1275 -/*
1276 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1277 - *
1278 - * Copyright (C) 2002-2009 Aleph One Ltd.
1279 - * for Toby Churchill Ltd and Brightstar Engineering
1280 - *
1281 - * Created by Charles Manning <charles@aleph1.co.uk>
1282 - * Acknowledgements:
1283 - * Luc van OostenRyck for numerous patches.
1284 - * Nick Bane for numerous patches.
1285 - * Nick Bane for 2.5/2.6 integration.
1286 - * Andras Toth for mknod rdev issue.
1287 - * Michael Fischer for finding the problem with inode inconsistency.
1288 - * Some code bodily lifted from JFFS
1289 - *
1290 - * This program is free software; you can redistribute it and/or modify
1291 - * it under the terms of the GNU General Public License version 2 as
1292 - * published by the Free Software Foundation.
1293 - */
1294 -
1295 -/*
1296 - *
1297 - * This is the file system front-end to YAFFS that hooks it up to
1298 - * the VFS.
1299 - *
1300 - * Special notes:
1301 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1302 - * this superblock
1303 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1304 - * superblock
1305 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1306 - */
1307 -
1308 -const char *yaffs_fs_c_version =
1309 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1310 -extern const char *yaffs_guts_c_version;
1311 -
1312 -#include <linux/version.h>
1313 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1314 -#include <linux/config.h>
1315 -#endif
1316 -#include <linux/kernel.h>
1317 -#include <linux/module.h>
1318 -#include <linux/slab.h>
1319 -#include <linux/init.h>
1320 -#include <linux/fs.h>
1321 -#include <linux/proc_fs.h>
1322 -#include <linux/smp_lock.h>
1323 -#include <linux/pagemap.h>
1324 -#include <linux/mtd/mtd.h>
1325 -#include <linux/interrupt.h>
1326 -#include <linux/string.h>
1327 -#include <linux/ctype.h>
1328 -
1329 -#include "asm/div64.h"
1330 -
1331 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1332 -
1333 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1334 -#include <linux/statfs.h>
1335 -#define UnlockPage(p) unlock_page(p)
1336 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1337 -
1338 -/* FIXME: use sb->s_id instead ? */
1339 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1340 -
1341 -#else
1342 -
1343 -#include <linux/locks.h>
1344 -#define BDEVNAME_SIZE 0
1345 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1346 -
1347 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1348 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1349 -#define __user
1350 -#endif
1351 -
1352 -#endif
1353 -
1354 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1355 -#define YPROC_ROOT (&proc_root)
1356 -#else
1357 -#define YPROC_ROOT NULL
1358 -#endif
1359 -
1360 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1361 -#define WRITE_SIZE_STR "writesize"
1362 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1363 -#else
1364 -#define WRITE_SIZE_STR "oobblock"
1365 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1366 -#endif
1367 -
1368 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1369 -#define YAFFS_USE_WRITE_BEGIN_END 1
1370 -#else
1371 -#define YAFFS_USE_WRITE_BEGIN_END 0
1372 -#endif
1373 -
1374 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1375 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1376 -{
1377 - uint64_t result = partition_size;
1378 - do_div(result, block_size);
1379 - return (uint32_t)result;
1380 -}
1381 -#else
1382 -#define YCALCBLOCKS(s, b) ((s)/(b))
1383 -#endif
1384 -
1385 -#include <linux/uaccess.h>
1386 -
1387 -#include "yportenv.h"
1388 -#include "yaffs_guts.h"
1389 -
1390 -#include <linux/mtd/mtd.h>
1391 -#include "yaffs_mtdif.h"
1392 -#include "yaffs_mtdif1.h"
1393 -#include "yaffs_mtdif2.h"
1394 -
1395 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1396 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1397 -unsigned int yaffs_auto_checkpoint = 1;
1398 -
1399 -/* Module Parameters */
1400 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1401 -module_param(yaffs_traceMask, uint, 0644);
1402 -module_param(yaffs_wr_attempts, uint, 0644);
1403 -module_param(yaffs_auto_checkpoint, uint, 0644);
1404 -#else
1405 -MODULE_PARM(yaffs_traceMask, "i");
1406 -MODULE_PARM(yaffs_wr_attempts, "i");
1407 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1408 -#endif
1409 -
1410 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1411 -/* use iget and read_inode */
1412 -#define Y_IGET(sb, inum) iget((sb), (inum))
1413 -static void yaffs_read_inode(struct inode *inode);
1414 -
1415 -#else
1416 -/* Call local equivalent */
1417 -#define YAFFS_USE_OWN_IGET
1418 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1419 -
1420 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1421 -#endif
1422 -
1423 -/*#define T(x) printk x */
1424 -
1425 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1426 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1427 -#else
1428 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1429 -#endif
1430 -
1431 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1432 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1433 -
1434 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1435 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1436 -#else
1437 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1438 -#endif
1439 -
1440 -static void yaffs_put_super(struct super_block *sb);
1441 -
1442 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1443 - loff_t *pos);
1444 -static ssize_t yaffs_hold_space(struct file *f);
1445 -static void yaffs_release_space(struct file *f);
1446 -
1447 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1448 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1449 -#else
1450 -static int yaffs_file_flush(struct file *file);
1451 -#endif
1452 -
1453 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1454 - int datasync);
1455 -
1456 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1457 -
1458 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1459 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1460 - struct nameidata *n);
1461 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1462 - struct nameidata *n);
1463 -#else
1464 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1465 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1466 -#endif
1467 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1468 - struct dentry *dentry);
1469 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1470 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1471 - const char *symname);
1472 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1473 -
1474 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1475 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1476 - dev_t dev);
1477 -#else
1478 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1479 - int dev);
1480 -#endif
1481 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1482 - struct inode *new_dir, struct dentry *new_dentry);
1483 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1484 -
1485 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1486 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1487 -static void yaffs_write_super(struct super_block *sb);
1488 -#else
1489 -static int yaffs_sync_fs(struct super_block *sb);
1490 -static int yaffs_write_super(struct super_block *sb);
1491 -#endif
1492 -
1493 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1494 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1495 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1496 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1497 -#else
1498 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1499 -#endif
1500 -
1501 -#ifdef YAFFS_HAS_PUT_INODE
1502 -static void yaffs_put_inode(struct inode *inode);
1503 -#endif
1504 -
1505 -static void yaffs_delete_inode(struct inode *);
1506 -static void yaffs_clear_inode(struct inode *);
1507 -
1508 -static int yaffs_readpage(struct file *file, struct page *page);
1509 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1510 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1511 -#else
1512 -static int yaffs_writepage(struct page *page);
1513 -#endif
1514 -
1515 -
1516 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1517 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1518 - loff_t pos, unsigned len, unsigned flags,
1519 - struct page **pagep, void **fsdata);
1520 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1521 - loff_t pos, unsigned len, unsigned copied,
1522 - struct page *pg, void *fsdadata);
1523 -#else
1524 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1525 - unsigned offset, unsigned to);
1526 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1527 - unsigned to);
1528 -
1529 -#endif
1530 -
1531 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1532 - int buflen);
1533 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1534 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1535 -#else
1536 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1537 -#endif
1538 -
1539 -static struct address_space_operations yaffs_file_address_operations = {
1540 - .readpage = yaffs_readpage,
1541 - .writepage = yaffs_writepage,
1542 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1543 - .write_begin = yaffs_write_begin,
1544 - .write_end = yaffs_write_end,
1545 -#else
1546 - .prepare_write = yaffs_prepare_write,
1547 - .commit_write = yaffs_commit_write,
1548 -#endif
1549 -};
1550 -
1551 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1552 -static const struct file_operations yaffs_file_operations = {
1553 - .read = do_sync_read,
1554 - .write = do_sync_write,
1555 - .aio_read = generic_file_aio_read,
1556 - .aio_write = generic_file_aio_write,
1557 - .mmap = generic_file_mmap,
1558 - .flush = yaffs_file_flush,
1559 - .fsync = yaffs_sync_object,
1560 - .splice_read = generic_file_splice_read,
1561 - .splice_write = generic_file_splice_write,
1562 - .llseek = generic_file_llseek,
1563 -};
1564 -
1565 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1566 -
1567 -static const struct file_operations yaffs_file_operations = {
1568 - .read = do_sync_read,
1569 - .write = do_sync_write,
1570 - .aio_read = generic_file_aio_read,
1571 - .aio_write = generic_file_aio_write,
1572 - .mmap = generic_file_mmap,
1573 - .flush = yaffs_file_flush,
1574 - .fsync = yaffs_sync_object,
1575 - .sendfile = generic_file_sendfile,
1576 -};
1577 -
1578 -#else
1579 -
1580 -static const struct file_operations yaffs_file_operations = {
1581 - .read = generic_file_read,
1582 - .write = generic_file_write,
1583 - .mmap = generic_file_mmap,
1584 - .flush = yaffs_file_flush,
1585 - .fsync = yaffs_sync_object,
1586 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1587 - .sendfile = generic_file_sendfile,
1588 -#endif
1589 -};
1590 -#endif
1591 -
1592 -static const struct inode_operations yaffs_file_inode_operations = {
1593 - .setattr = yaffs_setattr,
1594 -};
1595 -
1596 -static const struct inode_operations yaffs_symlink_inode_operations = {
1597 - .readlink = yaffs_readlink,
1598 - .follow_link = yaffs_follow_link,
1599 - .setattr = yaffs_setattr,
1600 -};
1601 -
1602 -static const struct inode_operations yaffs_dir_inode_operations = {
1603 - .create = yaffs_create,
1604 - .lookup = yaffs_lookup,
1605 - .link = yaffs_link,
1606 - .unlink = yaffs_unlink,
1607 - .symlink = yaffs_symlink,
1608 - .mkdir = yaffs_mkdir,
1609 - .rmdir = yaffs_unlink,
1610 - .mknod = yaffs_mknod,
1611 - .rename = yaffs_rename,
1612 - .setattr = yaffs_setattr,
1613 -};
1614 -
1615 -static const struct file_operations yaffs_dir_operations = {
1616 - .read = generic_read_dir,
1617 - .readdir = yaffs_readdir,
1618 - .fsync = yaffs_sync_object,
1619 -};
1620 -
1621 -static const struct super_operations yaffs_super_ops = {
1622 - .statfs = yaffs_statfs,
1623 -
1624 -#ifndef YAFFS_USE_OWN_IGET
1625 - .read_inode = yaffs_read_inode,
1626 -#endif
1627 -#ifdef YAFFS_HAS_PUT_INODE
1628 - .put_inode = yaffs_put_inode,
1629 -#endif
1630 - .put_super = yaffs_put_super,
1631 - .delete_inode = yaffs_delete_inode,
1632 - .clear_inode = yaffs_clear_inode,
1633 - .sync_fs = yaffs_sync_fs,
1634 - .write_super = yaffs_write_super,
1635 -};
1636 -
1637 -static void yaffs_GrossLock(yaffs_Device *dev)
1638 -{
1639 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
1640 - down(&dev->grossLock);
1641 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
1642 -}
1643 -
1644 -static void yaffs_GrossUnlock(yaffs_Device *dev)
1645 -{
1646 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
1647 - up(&dev->grossLock);
1648 -}
1649 -
1650 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1651 - int buflen)
1652 -{
1653 - unsigned char *alias;
1654 - int ret;
1655 -
1656 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1657 -
1658 - yaffs_GrossLock(dev);
1659 -
1660 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1661 -
1662 - yaffs_GrossUnlock(dev);
1663 -
1664 - if (!alias)
1665 - return -ENOMEM;
1666 -
1667 - ret = vfs_readlink(dentry, buffer, buflen, alias);
1668 - kfree(alias);
1669 - return ret;
1670 -}
1671 -
1672 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1673 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1674 -#else
1675 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1676 -#endif
1677 -{
1678 - unsigned char *alias;
1679 - int ret;
1680 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1681 -
1682 - yaffs_GrossLock(dev);
1683 -
1684 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1685 -
1686 - yaffs_GrossUnlock(dev);
1687 -
1688 - if (!alias) {
1689 - ret = -ENOMEM;
1690 - goto out;
1691 - }
1692 -
1693 - ret = vfs_follow_link(nd, alias);
1694 - kfree(alias);
1695 -out:
1696 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1697 - return ERR_PTR(ret);
1698 -#else
1699 - return ret;
1700 -#endif
1701 -}
1702 -
1703 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1704 - yaffs_Object *obj);
1705 -
1706 -/*
1707 - * Lookup is used to find objects in the fs
1708 - */
1709 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1710 -
1711 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1712 - struct nameidata *n)
1713 -#else
1714 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
1715 -#endif
1716 -{
1717 - yaffs_Object *obj;
1718 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
1719 -
1720 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
1721 -
1722 - yaffs_GrossLock(dev);
1723 -
1724 - T(YAFFS_TRACE_OS,
1725 - ("yaffs_lookup for %d:%s\n",
1726 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
1727 -
1728 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
1729 - dentry->d_name.name);
1730 -
1731 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
1732 -
1733 - /* Can't hold gross lock when calling yaffs_get_inode() */
1734 - yaffs_GrossUnlock(dev);
1735 -
1736 - if (obj) {
1737 - T(YAFFS_TRACE_OS,
1738 - ("yaffs_lookup found %d\n", obj->objectId));
1739 -
1740 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1741 -
1742 - if (inode) {
1743 - T(YAFFS_TRACE_OS,
1744 - ("yaffs_loookup dentry \n"));
1745 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
1746 - * d_add even if NULL inode */
1747 -#if 0
1748 - /*dget(dentry); // try to solve directory bug */
1749 - d_add(dentry, inode);
1750 -
1751 - /* return dentry; */
1752 - return NULL;
1753 -#endif
1754 - }
1755 -
1756 - } else {
1757 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
1758 -
1759 - }
1760 -
1761 -/* added NCB for 2.5/6 compatability - forces add even if inode is
1762 - * NULL which creates dentry hash */
1763 - d_add(dentry, inode);
1764 -
1765 - return NULL;
1766 -}
1767 -
1768 -
1769 -#ifdef YAFFS_HAS_PUT_INODE
1770 -
1771 -/* For now put inode is just for debugging
1772 - * Put inode is called when the inode **structure** is put.
1773 - */
1774 -static void yaffs_put_inode(struct inode *inode)
1775 -{
1776 - T(YAFFS_TRACE_OS,
1777 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
1778 - atomic_read(&inode->i_count)));
1779 -
1780 -}
1781 -#endif
1782 -
1783 -/* clear is called to tell the fs to release any per-inode data it holds */
1784 -static void yaffs_clear_inode(struct inode *inode)
1785 -{
1786 - yaffs_Object *obj;
1787 - yaffs_Device *dev;
1788 -
1789 - obj = yaffs_InodeToObject(inode);
1790 -
1791 - T(YAFFS_TRACE_OS,
1792 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1793 - atomic_read(&inode->i_count),
1794 - obj ? "object exists" : "null object"));
1795 -
1796 - if (obj) {
1797 - dev = obj->myDev;
1798 - yaffs_GrossLock(dev);
1799 -
1800 - /* Clear the association between the inode and
1801 - * the yaffs_Object.
1802 - */
1803 - obj->myInode = NULL;
1804 - yaffs_InodeToObjectLV(inode) = NULL;
1805 -
1806 - /* If the object freeing was deferred, then the real
1807 - * free happens now.
1808 - * This should fix the inode inconsistency problem.
1809 - */
1810 -
1811 - yaffs_HandleDeferedFree(obj);
1812 -
1813 - yaffs_GrossUnlock(dev);
1814 - }
1815 -
1816 -}
1817 -
1818 -/* delete is called when the link count is zero and the inode
1819 - * is put (ie. nobody wants to know about it anymore, time to
1820 - * delete the file).
1821 - * NB Must call clear_inode()
1822 - */
1823 -static void yaffs_delete_inode(struct inode *inode)
1824 -{
1825 - yaffs_Object *obj = yaffs_InodeToObject(inode);
1826 - yaffs_Device *dev;
1827 -
1828 - T(YAFFS_TRACE_OS,
1829 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1830 - atomic_read(&inode->i_count),
1831 - obj ? "object exists" : "null object"));
1832 -
1833 - if (obj) {
1834 - dev = obj->myDev;
1835 - yaffs_GrossLock(dev);
1836 - yaffs_DeleteObject(obj);
1837 - yaffs_GrossUnlock(dev);
1838 - }
1839 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1840 - truncate_inode_pages(&inode->i_data, 0);
1841 -#endif
1842 - clear_inode(inode);
1843 -}
1844 -
1845 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1846 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
1847 -#else
1848 -static int yaffs_file_flush(struct file *file)
1849 -#endif
1850 -{
1851 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1852 -
1853 - yaffs_Device *dev = obj->myDev;
1854 -
1855 - T(YAFFS_TRACE_OS,
1856 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
1857 - obj->dirty ? "dirty" : "clean"));
1858 -
1859 - yaffs_GrossLock(dev);
1860 -
1861 - yaffs_FlushFile(obj, 1);
1862 -
1863 - yaffs_GrossUnlock(dev);
1864 -
1865 - return 0;
1866 -}
1867 -
1868 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
1869 -{
1870 - /* Lifted from jffs2 */
1871 -
1872 - yaffs_Object *obj;
1873 - unsigned char *pg_buf;
1874 - int ret;
1875 -
1876 - yaffs_Device *dev;
1877 -
1878 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
1879 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
1880 - (unsigned)PAGE_CACHE_SIZE));
1881 -
1882 - obj = yaffs_DentryToObject(f->f_dentry);
1883 -
1884 - dev = obj->myDev;
1885 -
1886 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1887 - BUG_ON(!PageLocked(pg));
1888 -#else
1889 - if (!PageLocked(pg))
1890 - PAGE_BUG(pg);
1891 -#endif
1892 -
1893 - pg_buf = kmap(pg);
1894 - /* FIXME: Can kmap fail? */
1895 -
1896 - yaffs_GrossLock(dev);
1897 -
1898 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
1899 - pg->index << PAGE_CACHE_SHIFT,
1900 - PAGE_CACHE_SIZE);
1901 -
1902 - yaffs_GrossUnlock(dev);
1903 -
1904 - if (ret >= 0)
1905 - ret = 0;
1906 -
1907 - if (ret) {
1908 - ClearPageUptodate(pg);
1909 - SetPageError(pg);
1910 - } else {
1911 - SetPageUptodate(pg);
1912 - ClearPageError(pg);
1913 - }
1914 -
1915 - flush_dcache_page(pg);
1916 - kunmap(pg);
1917 -
1918 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
1919 - return ret;
1920 -}
1921 -
1922 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1923 -{
1924 - int ret = yaffs_readpage_nolock(f, pg);
1925 - UnlockPage(pg);
1926 - return ret;
1927 -}
1928 -
1929 -static int yaffs_readpage(struct file *f, struct page *pg)
1930 -{
1931 - return yaffs_readpage_unlock(f, pg);
1932 -}
1933 -
1934 -/* writepage inspired by/stolen from smbfs */
1935 -
1936 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1937 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1938 -#else
1939 -static int yaffs_writepage(struct page *page)
1940 -#endif
1941 -{
1942 - struct address_space *mapping = page->mapping;
1943 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
1944 - struct inode *inode;
1945 - unsigned long end_index;
1946 - char *buffer;
1947 - yaffs_Object *obj;
1948 - int nWritten = 0;
1949 - unsigned nBytes;
1950 -
1951 - if (!mapping)
1952 - BUG();
1953 - inode = mapping->host;
1954 - if (!inode)
1955 - BUG();
1956 -
1957 - if (offset > inode->i_size) {
1958 - T(YAFFS_TRACE_OS,
1959 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
1960 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
1961 - (unsigned)inode->i_size));
1962 - T(YAFFS_TRACE_OS,
1963 - (" -> don't care!!\n"));
1964 - unlock_page(page);
1965 - return 0;
1966 - }
1967 -
1968 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1969 -
1970 - /* easy case */
1971 - if (page->index < end_index)
1972 - nBytes = PAGE_CACHE_SIZE;
1973 - else
1974 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
1975 -
1976 - get_page(page);
1977 -
1978 - buffer = kmap(page);
1979 -
1980 - obj = yaffs_InodeToObject(inode);
1981 - yaffs_GrossLock(obj->myDev);
1982 -
1983 - T(YAFFS_TRACE_OS,
1984 - ("yaffs_writepage at %08x, size %08x\n",
1985 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
1986 - T(YAFFS_TRACE_OS,
1987 - ("writepag0: obj = %05x, ino = %05x\n",
1988 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
1989 -
1990 - nWritten = yaffs_WriteDataToFile(obj, buffer,
1991 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
1992 -
1993 - T(YAFFS_TRACE_OS,
1994 - ("writepag1: obj = %05x, ino = %05x\n",
1995 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
1996 -
1997 - yaffs_GrossUnlock(obj->myDev);
1998 -
1999 - kunmap(page);
2000 - SetPageUptodate(page);
2001 - UnlockPage(page);
2002 - put_page(page);
2003 -
2004 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2005 -}
2006 -
2007 -
2008 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2009 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2010 - loff_t pos, unsigned len, unsigned flags,
2011 - struct page **pagep, void **fsdata)
2012 -{
2013 - struct page *pg = NULL;
2014 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2015 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2016 - uint32_t to = offset + len;
2017 -
2018 - int ret = 0;
2019 - int space_held = 0;
2020 -
2021 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2022 - /* Get a page */
2023 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2024 - pg = grab_cache_page_write_begin(mapping, index, flags);
2025 -#else
2026 - pg = __grab_cache_page(mapping, index);
2027 -#endif
2028 -
2029 - *pagep = pg;
2030 - if (!pg) {
2031 - ret = -ENOMEM;
2032 - goto out;
2033 - }
2034 - /* Get fs space */
2035 - space_held = yaffs_hold_space(filp);
2036 -
2037 - if (!space_held) {
2038 - ret = -ENOSPC;
2039 - goto out;
2040 - }
2041 -
2042 - /* Update page if required */
2043 -
2044 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2045 - ret = yaffs_readpage_nolock(filp, pg);
2046 -
2047 - if (ret)
2048 - goto out;
2049 -
2050 - /* Happy path return */
2051 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2052 -
2053 - return 0;
2054 -
2055 -out:
2056 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2057 - if (space_held)
2058 - yaffs_release_space(filp);
2059 - if (pg) {
2060 - unlock_page(pg);
2061 - page_cache_release(pg);
2062 - }
2063 - return ret;
2064 -}
2065 -
2066 -#else
2067 -
2068 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2069 - unsigned offset, unsigned to)
2070 -{
2071 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2072 -
2073 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2074 - return yaffs_readpage_nolock(f, pg);
2075 - return 0;
2076 -}
2077 -#endif
2078 -
2079 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2080 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2081 - loff_t pos, unsigned len, unsigned copied,
2082 - struct page *pg, void *fsdadata)
2083 -{
2084 - int ret = 0;
2085 - void *addr, *kva;
2086 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2087 -
2088 - kva = kmap(pg);
2089 - addr = kva + offset_into_page;
2090 -
2091 - T(YAFFS_TRACE_OS,
2092 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2093 - (unsigned) addr,
2094 - (int)pos, copied));
2095 -
2096 - ret = yaffs_file_write(filp, addr, copied, &pos);
2097 -
2098 - if (ret != copied) {
2099 - T(YAFFS_TRACE_OS,
2100 - ("yaffs_write_end not same size ret %d copied %d\n",
2101 - ret, copied));
2102 - SetPageError(pg);
2103 - ClearPageUptodate(pg);
2104 - } else {
2105 - SetPageUptodate(pg);
2106 - }
2107 -
2108 - kunmap(pg);
2109 -
2110 - yaffs_release_space(filp);
2111 - unlock_page(pg);
2112 - page_cache_release(pg);
2113 - return ret;
2114 -}
2115 -#else
2116 -
2117 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2118 - unsigned to)
2119 -{
2120 - void *addr, *kva;
2121 -
2122 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2123 - int nBytes = to - offset;
2124 - int nWritten;
2125 -
2126 - unsigned spos = pos;
2127 - unsigned saddr;
2128 -
2129 - kva = kmap(pg);
2130 - addr = kva + offset;
2131 -
2132 - saddr = (unsigned) addr;
2133 -
2134 - T(YAFFS_TRACE_OS,
2135 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2136 - saddr, spos, nBytes));
2137 -
2138 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2139 -
2140 - if (nWritten != nBytes) {
2141 - T(YAFFS_TRACE_OS,
2142 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2143 - nWritten, nBytes));
2144 - SetPageError(pg);
2145 - ClearPageUptodate(pg);
2146 - } else {
2147 - SetPageUptodate(pg);
2148 - }
2149 -
2150 - kunmap(pg);
2151 -
2152 - T(YAFFS_TRACE_OS,
2153 - ("yaffs_commit_write returning %d\n",
2154 - nWritten == nBytes ? 0 : nWritten));
2155 -
2156 - return nWritten == nBytes ? 0 : nWritten;
2157 -}
2158 -#endif
2159 -
2160 -
2161 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2162 -{
2163 - if (inode && obj) {
2164 -
2165 -
2166 - /* Check mode against the variant type and attempt to repair if broken. */
2167 - __u32 mode = obj->yst_mode;
2168 - switch (obj->variantType) {
2169 - case YAFFS_OBJECT_TYPE_FILE:
2170 - if (!S_ISREG(mode)) {
2171 - obj->yst_mode &= ~S_IFMT;
2172 - obj->yst_mode |= S_IFREG;
2173 - }
2174 -
2175 - break;
2176 - case YAFFS_OBJECT_TYPE_SYMLINK:
2177 - if (!S_ISLNK(mode)) {
2178 - obj->yst_mode &= ~S_IFMT;
2179 - obj->yst_mode |= S_IFLNK;
2180 - }
2181 -
2182 - break;
2183 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2184 - if (!S_ISDIR(mode)) {
2185 - obj->yst_mode &= ~S_IFMT;
2186 - obj->yst_mode |= S_IFDIR;
2187 - }
2188 -
2189 - break;
2190 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2191 - case YAFFS_OBJECT_TYPE_HARDLINK:
2192 - case YAFFS_OBJECT_TYPE_SPECIAL:
2193 - default:
2194 - /* TODO? */
2195 - break;
2196 - }
2197 -
2198 - inode->i_flags |= S_NOATIME;
2199 -
2200 - inode->i_ino = obj->objectId;
2201 - inode->i_mode = obj->yst_mode;
2202 - inode->i_uid = obj->yst_uid;
2203 - inode->i_gid = obj->yst_gid;
2204 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2205 - inode->i_blksize = inode->i_sb->s_blocksize;
2206 -#endif
2207 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2208 -
2209 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2210 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2211 - inode->i_atime.tv_nsec = 0;
2212 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2213 - inode->i_mtime.tv_nsec = 0;
2214 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2215 - inode->i_ctime.tv_nsec = 0;
2216 -#else
2217 - inode->i_rdev = obj->yst_rdev;
2218 - inode->i_atime = obj->yst_atime;
2219 - inode->i_mtime = obj->yst_mtime;
2220 - inode->i_ctime = obj->yst_ctime;
2221 -#endif
2222 - inode->i_size = yaffs_GetObjectFileLength(obj);
2223 - inode->i_blocks = (inode->i_size + 511) >> 9;
2224 -
2225 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2226 -
2227 - T(YAFFS_TRACE_OS,
2228 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2229 - inode->i_mode, inode->i_uid, inode->i_gid,
2230 - (int)inode->i_size, atomic_read(&inode->i_count)));
2231 -
2232 - switch (obj->yst_mode & S_IFMT) {
2233 - default: /* fifo, device or socket */
2234 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2235 - init_special_inode(inode, obj->yst_mode,
2236 - old_decode_dev(obj->yst_rdev));
2237 -#else
2238 - init_special_inode(inode, obj->yst_mode,
2239 - (dev_t) (obj->yst_rdev));
2240 -#endif
2241 - break;
2242 - case S_IFREG: /* file */
2243 - inode->i_op = &yaffs_file_inode_operations;
2244 - inode->i_fop = &yaffs_file_operations;
2245 - inode->i_mapping->a_ops =
2246 - &yaffs_file_address_operations;
2247 - break;
2248 - case S_IFDIR: /* directory */
2249 - inode->i_op = &yaffs_dir_inode_operations;
2250 - inode->i_fop = &yaffs_dir_operations;
2251 - break;
2252 - case S_IFLNK: /* symlink */
2253 - inode->i_op = &yaffs_symlink_inode_operations;
2254 - break;
2255 - }
2256 -
2257 - yaffs_InodeToObjectLV(inode) = obj;
2258 -
2259 - obj->myInode = inode;
2260 -
2261 - } else {
2262 - T(YAFFS_TRACE_OS,
2263 - ("yaffs_FileInode invalid parameters\n"));
2264 - }
2265 -
2266 -}
2267 -
2268 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2269 - yaffs_Object *obj)
2270 -{
2271 - struct inode *inode;
2272 -
2273 - if (!sb) {
2274 - T(YAFFS_TRACE_OS,
2275 - ("yaffs_get_inode for NULL super_block!!\n"));
2276 - return NULL;
2277 -
2278 - }
2279 -
2280 - if (!obj) {
2281 - T(YAFFS_TRACE_OS,
2282 - ("yaffs_get_inode for NULL object!!\n"));
2283 - return NULL;
2284 -
2285 - }
2286 -
2287 - T(YAFFS_TRACE_OS,
2288 - ("yaffs_get_inode for object %d\n", obj->objectId));
2289 -
2290 - inode = Y_IGET(sb, obj->objectId);
2291 - if (IS_ERR(inode))
2292 - return NULL;
2293 -
2294 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2295 - /* iget also increments the inode's i_count */
2296 - /* NB You can't be holding grossLock or deadlock will happen! */
2297 -
2298 - return inode;
2299 -}
2300 -
2301 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2302 - loff_t *pos)
2303 -{
2304 - yaffs_Object *obj;
2305 - int nWritten, ipos;
2306 - struct inode *inode;
2307 - yaffs_Device *dev;
2308 -
2309 - obj = yaffs_DentryToObject(f->f_dentry);
2310 -
2311 - dev = obj->myDev;
2312 -
2313 - yaffs_GrossLock(dev);
2314 -
2315 - inode = f->f_dentry->d_inode;
2316 -
2317 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2318 - ipos = inode->i_size;
2319 - else
2320 - ipos = *pos;
2321 -
2322 - if (!obj)
2323 - T(YAFFS_TRACE_OS,
2324 - ("yaffs_file_write: hey obj is null!\n"));
2325 - else
2326 - T(YAFFS_TRACE_OS,
2327 - ("yaffs_file_write about to write writing %zu bytes"
2328 - "to object %d at %d\n",
2329 - n, obj->objectId, ipos));
2330 -
2331 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2332 -
2333 - T(YAFFS_TRACE_OS,
2334 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2335 - n, nWritten, ipos));
2336 -
2337 - if (nWritten > 0) {
2338 - ipos += nWritten;
2339 - *pos = ipos;
2340 - if (ipos > inode->i_size) {
2341 - inode->i_size = ipos;
2342 - inode->i_blocks = (ipos + 511) >> 9;
2343 -
2344 - T(YAFFS_TRACE_OS,
2345 - ("yaffs_file_write size updated to %d bytes, "
2346 - "%d blocks\n",
2347 - ipos, (int)(inode->i_blocks)));
2348 - }
2349 -
2350 - }
2351 - yaffs_GrossUnlock(dev);
2352 - return nWritten == 0 ? -ENOSPC : nWritten;
2353 -}
2354 -
2355 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2356 -/* For now we just assume few parallel writes and check against a small number. */
2357 -/* Todo: need to do this with a counter to handle parallel reads better */
2358 -
2359 -static ssize_t yaffs_hold_space(struct file *f)
2360 -{
2361 - yaffs_Object *obj;
2362 - yaffs_Device *dev;
2363 -
2364 - int nFreeChunks;
2365 -
2366 -
2367 - obj = yaffs_DentryToObject(f->f_dentry);
2368 -
2369 - dev = obj->myDev;
2370 -
2371 - yaffs_GrossLock(dev);
2372 -
2373 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2374 -
2375 - yaffs_GrossUnlock(dev);
2376 -
2377 - return (nFreeChunks > 20) ? 1 : 0;
2378 -}
2379 -
2380 -static void yaffs_release_space(struct file *f)
2381 -{
2382 - yaffs_Object *obj;
2383 - yaffs_Device *dev;
2384 -
2385 -
2386 - obj = yaffs_DentryToObject(f->f_dentry);
2387 -
2388 - dev = obj->myDev;
2389 -
2390 - yaffs_GrossLock(dev);
2391 -
2392 -
2393 - yaffs_GrossUnlock(dev);
2394 -}
2395 -
2396 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2397 -{
2398 - yaffs_Object *obj;
2399 - yaffs_Device *dev;
2400 - struct inode *inode = f->f_dentry->d_inode;
2401 - unsigned long offset, curoffs;
2402 - struct ylist_head *i;
2403 - yaffs_Object *l;
2404 -
2405 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2406 -
2407 - obj = yaffs_DentryToObject(f->f_dentry);
2408 - dev = obj->myDev;
2409 -
2410 - yaffs_GrossLock(dev);
2411 -
2412 - offset = f->f_pos;
2413 -
2414 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2415 -
2416 - if (offset == 0) {
2417 - T(YAFFS_TRACE_OS,
2418 - ("yaffs_readdir: entry . ino %d \n",
2419 - (int)inode->i_ino));
2420 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2421 - goto out;
2422 - offset++;
2423 - f->f_pos++;
2424 - }
2425 - if (offset == 1) {
2426 - T(YAFFS_TRACE_OS,
2427 - ("yaffs_readdir: entry .. ino %d \n",
2428 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2429 - if (filldir(dirent, "..", 2, offset,
2430 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2431 - goto out;
2432 - offset++;
2433 - f->f_pos++;
2434 - }
2435 -
2436 - curoffs = 1;
2437 -
2438 - /* If the directory has changed since the open or last call to
2439 - readdir, rewind to after the 2 canned entries. */
2440 -
2441 - if (f->f_version != inode->i_version) {
2442 - offset = 2;
2443 - f->f_pos = offset;
2444 - f->f_version = inode->i_version;
2445 - }
2446 -
2447 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2448 - curoffs++;
2449 - if (curoffs >= offset) {
2450 - l = ylist_entry(i, yaffs_Object, siblings);
2451 -
2452 - yaffs_GetObjectName(l, name,
2453 - YAFFS_MAX_NAME_LENGTH + 1);
2454 - T(YAFFS_TRACE_OS,
2455 - ("yaffs_readdir: %s inode %d\n", name,
2456 - yaffs_GetObjectInode(l)));
2457 -
2458 - if (filldir(dirent,
2459 - name,
2460 - strlen(name),
2461 - offset,
2462 - yaffs_GetObjectInode(l),
2463 - yaffs_GetObjectType(l)) < 0)
2464 - goto up_and_out;
2465 -
2466 - offset++;
2467 - f->f_pos++;
2468 - }
2469 - }
2470 -
2471 -up_and_out:
2472 -out:
2473 - yaffs_GrossUnlock(dev);
2474 -
2475 - return 0;
2476 -}
2477 -
2478 -/*
2479 - * File creation. Allocate an inode, and we're done..
2480 - */
2481 -
2482 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2483 -#define YCRED(x) x
2484 -#else
2485 -#define YCRED(x) (x->cred)
2486 -#endif
2487 -
2488 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2489 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2490 - dev_t rdev)
2491 -#else
2492 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2493 - int rdev)
2494 -#endif
2495 -{
2496 - struct inode *inode;
2497 -
2498 - yaffs_Object *obj = NULL;
2499 - yaffs_Device *dev;
2500 -
2501 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2502 -
2503 - int error = -ENOSPC;
2504 - uid_t uid = YCRED(current)->fsuid;
2505 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2506 -
2507 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2508 - mode |= S_ISGID;
2509 -
2510 - if (parent) {
2511 - T(YAFFS_TRACE_OS,
2512 - ("yaffs_mknod: parent object %d type %d\n",
2513 - parent->objectId, parent->variantType));
2514 - } else {
2515 - T(YAFFS_TRACE_OS,
2516 - ("yaffs_mknod: could not get parent object\n"));
2517 - return -EPERM;
2518 - }
2519 -
2520 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2521 - "mode %x dev %x\n",
2522 - dentry->d_name.name, mode, rdev));
2523 -
2524 - dev = parent->myDev;
2525 -
2526 - yaffs_GrossLock(dev);
2527 -
2528 - switch (mode & S_IFMT) {
2529 - default:
2530 - /* Special (socket, fifo, device...) */
2531 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2532 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2533 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2534 - gid, old_encode_dev(rdev));
2535 -#else
2536 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2537 - gid, rdev);
2538 -#endif
2539 - break;
2540 - case S_IFREG: /* file */
2541 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2542 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2543 - gid);
2544 - break;
2545 - case S_IFDIR: /* directory */
2546 - T(YAFFS_TRACE_OS,
2547 - ("yaffs_mknod: making directory\n"));
2548 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2549 - uid, gid);
2550 - break;
2551 - case S_IFLNK: /* symlink */
2552 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2553 - obj = NULL; /* Do we ever get here? */
2554 - break;
2555 - }
2556 -
2557 - /* Can not call yaffs_get_inode() with gross lock held */
2558 - yaffs_GrossUnlock(dev);
2559 -
2560 - if (obj) {
2561 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2562 - d_instantiate(dentry, inode);
2563 - T(YAFFS_TRACE_OS,
2564 - ("yaffs_mknod created object %d count = %d\n",
2565 - obj->objectId, atomic_read(&inode->i_count)));
2566 - error = 0;
2567 - } else {
2568 - T(YAFFS_TRACE_OS,
2569 - ("yaffs_mknod failed making object\n"));
2570 - error = -ENOMEM;
2571 - }
2572 -
2573 - return error;
2574 -}
2575 -
2576 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2577 -{
2578 - int retVal;
2579 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2580 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2581 - return retVal;
2582 -}
2583 -
2584 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2585 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2586 - struct nameidata *n)
2587 -#else
2588 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2589 -#endif
2590 -{
2591 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
2592 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
2593 -}
2594 -
2595 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
2596 -{
2597 - int retVal;
2598 -
2599 - yaffs_Device *dev;
2600 -
2601 - T(YAFFS_TRACE_OS,
2602 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
2603 - dentry->d_name.name));
2604 -
2605 - dev = yaffs_InodeToObject(dir)->myDev;
2606 -
2607 - yaffs_GrossLock(dev);
2608 -
2609 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
2610 -
2611 - if (retVal == YAFFS_OK) {
2612 - dentry->d_inode->i_nlink--;
2613 - dir->i_version++;
2614 - yaffs_GrossUnlock(dev);
2615 - mark_inode_dirty(dentry->d_inode);
2616 - return 0;
2617 - }
2618 - yaffs_GrossUnlock(dev);
2619 - return -ENOTEMPTY;
2620 -}
2621 -
2622 -/*
2623 - * Create a link...
2624 - */
2625 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
2626 - struct dentry *dentry)
2627 -{
2628 - struct inode *inode = old_dentry->d_inode;
2629 - yaffs_Object *obj = NULL;
2630 - yaffs_Object *link = NULL;
2631 - yaffs_Device *dev;
2632 -
2633 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
2634 -
2635 - obj = yaffs_InodeToObject(inode);
2636 - dev = obj->myDev;
2637 -
2638 - yaffs_GrossLock(dev);
2639 -
2640 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
2641 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
2642 - obj);
2643 -
2644 - if (link) {
2645 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2646 - d_instantiate(dentry, old_dentry->d_inode);
2647 - atomic_inc(&old_dentry->d_inode->i_count);
2648 - T(YAFFS_TRACE_OS,
2649 - ("yaffs_link link count %d i_count %d\n",
2650 - old_dentry->d_inode->i_nlink,
2651 - atomic_read(&old_dentry->d_inode->i_count)));
2652 - }
2653 -
2654 - yaffs_GrossUnlock(dev);
2655 -
2656 - if (link)
2657 - return 0;
2658 -
2659 - return -EPERM;
2660 -}
2661 -
2662 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
2663 - const char *symname)
2664 -{
2665 - yaffs_Object *obj;
2666 - yaffs_Device *dev;
2667 - uid_t uid = YCRED(current)->fsuid;
2668 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2669 -
2670 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
2671 -
2672 - dev = yaffs_InodeToObject(dir)->myDev;
2673 - yaffs_GrossLock(dev);
2674 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
2675 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
2676 - yaffs_GrossUnlock(dev);
2677 -
2678 - if (obj) {
2679 - struct inode *inode;
2680 -
2681 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2682 - d_instantiate(dentry, inode);
2683 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
2684 - return 0;
2685 - } else {
2686 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
2687 - }
2688 -
2689 - return -ENOMEM;
2690 -}
2691 -
2692 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
2693 - int datasync)
2694 -{
2695 -
2696 - yaffs_Object *obj;
2697 - yaffs_Device *dev;
2698 -
2699 - obj = yaffs_DentryToObject(dentry);
2700 -
2701 - dev = obj->myDev;
2702 -
2703 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
2704 - yaffs_GrossLock(dev);
2705 - yaffs_FlushFile(obj, 1);
2706 - yaffs_GrossUnlock(dev);
2707 - return 0;
2708 -}
2709 -
2710 -/*
2711 - * The VFS layer already does all the dentry stuff for rename.
2712 - *
2713 - * NB: POSIX says you can rename an object over an old object of the same name
2714 - */
2715 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
2716 - struct inode *new_dir, struct dentry *new_dentry)
2717 -{
2718 - yaffs_Device *dev;
2719 - int retVal = YAFFS_FAIL;
2720 - yaffs_Object *target;
2721 -
2722 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
2723 - dev = yaffs_InodeToObject(old_dir)->myDev;
2724 -
2725 - yaffs_GrossLock(dev);
2726 -
2727 - /* Check if the target is an existing directory that is not empty. */
2728 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
2729 - new_dentry->d_name.name);
2730 -
2731 -
2732 -
2733 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
2734 - !ylist_empty(&target->variant.directoryVariant.children)) {
2735 -
2736 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
2737 -
2738 - retVal = YAFFS_FAIL;
2739 - } else {
2740 - /* Now does unlinking internally using shadowing mechanism */
2741 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
2742 -
2743 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
2744 - old_dentry->d_name.name,
2745 - yaffs_InodeToObject(new_dir),
2746 - new_dentry->d_name.name);
2747 - }
2748 - yaffs_GrossUnlock(dev);
2749 -
2750 - if (retVal == YAFFS_OK) {
2751 - if (target) {
2752 - new_dentry->d_inode->i_nlink--;
2753 - mark_inode_dirty(new_dentry->d_inode);
2754 - }
2755 -
2756 - return 0;
2757 - } else {
2758 - return -ENOTEMPTY;
2759 - }
2760 -}
2761 -
2762 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
2763 -{
2764 - struct inode *inode = dentry->d_inode;
2765 - int error;
2766 - yaffs_Device *dev;
2767 -
2768 - T(YAFFS_TRACE_OS,
2769 - ("yaffs_setattr of object %d\n",
2770 - yaffs_InodeToObject(inode)->objectId));
2771 -
2772 - error = inode_change_ok(inode, attr);
2773 - if (error == 0) {
2774 - dev = yaffs_InodeToObject(inode)->myDev;
2775 - yaffs_GrossLock(dev);
2776 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
2777 - YAFFS_OK) {
2778 - error = 0;
2779 - } else {
2780 - error = -EPERM;
2781 - }
2782 - yaffs_GrossUnlock(dev);
2783 - if (!error)
2784 - error = inode_setattr(inode, attr);
2785 - }
2786 - return error;
2787 -}
2788 -
2789 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2790 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
2791 -{
2792 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2793 - struct super_block *sb = dentry->d_sb;
2794 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2795 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
2796 -{
2797 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2798 -#else
2799 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
2800 -{
2801 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2802 -#endif
2803 -
2804 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
2805 -
2806 - yaffs_GrossLock(dev);
2807 -
2808 - buf->f_type = YAFFS_MAGIC;
2809 - buf->f_bsize = sb->s_blocksize;
2810 - buf->f_namelen = 255;
2811 -
2812 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
2813 - /* Do this if chunk size is not a power of 2 */
2814 -
2815 - uint64_t bytesInDev;
2816 - uint64_t bytesFree;
2817 -
2818 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
2819 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
2820 -
2821 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
2822 - buf->f_blocks = bytesInDev;
2823 -
2824 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
2825 - ((uint64_t)(dev->nDataBytesPerChunk));
2826 -
2827 - do_div(bytesFree, sb->s_blocksize);
2828 -
2829 - buf->f_bfree = bytesFree;
2830 -
2831 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
2832 -
2833 - buf->f_blocks =
2834 - (dev->endBlock - dev->startBlock + 1) *
2835 - dev->nChunksPerBlock /
2836 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2837 - buf->f_bfree =
2838 - yaffs_GetNumberOfFreeChunks(dev) /
2839 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2840 - } else {
2841 - buf->f_blocks =
2842 - (dev->endBlock - dev->startBlock + 1) *
2843 - dev->nChunksPerBlock *
2844 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2845 -
2846 - buf->f_bfree =
2847 - yaffs_GetNumberOfFreeChunks(dev) *
2848 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2849 - }
2850 -
2851 - buf->f_files = 0;
2852 - buf->f_ffree = 0;
2853 - buf->f_bavail = buf->f_bfree;
2854 -
2855 - yaffs_GrossUnlock(dev);
2856 - return 0;
2857 -}
2858 -
2859 -
2860 -static int yaffs_do_sync_fs(struct super_block *sb)
2861 -{
2862 -
2863 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2864 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
2865 -
2866 - if (sb->s_dirt) {
2867 - yaffs_GrossLock(dev);
2868 -
2869 - if (dev) {
2870 - yaffs_FlushEntireDeviceCache(dev);
2871 - yaffs_CheckpointSave(dev);
2872 - }
2873 -
2874 - yaffs_GrossUnlock(dev);
2875 -
2876 - sb->s_dirt = 0;
2877 - }
2878 - return 0;
2879 -}
2880 -
2881 -
2882 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2883 -static void yaffs_write_super(struct super_block *sb)
2884 -#else
2885 -static int yaffs_write_super(struct super_block *sb)
2886 -#endif
2887 -{
2888 -
2889 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
2890 - if (yaffs_auto_checkpoint >= 2)
2891 - yaffs_do_sync_fs(sb);
2892 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
2893 - return 0;
2894 -#endif
2895 -}
2896 -
2897 -
2898 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2899 -static int yaffs_sync_fs(struct super_block *sb, int wait)
2900 -#else
2901 -static int yaffs_sync_fs(struct super_block *sb)
2902 -#endif
2903 -{
2904 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
2905 -
2906 - if (yaffs_auto_checkpoint >= 1)
2907 - yaffs_do_sync_fs(sb);
2908 -
2909 - return 0;
2910 -}
2911 -
2912 -#ifdef YAFFS_USE_OWN_IGET
2913 -
2914 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
2915 -{
2916 - struct inode *inode;
2917 - yaffs_Object *obj;
2918 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2919 -
2920 - T(YAFFS_TRACE_OS,
2921 - ("yaffs_iget for %lu\n", ino));
2922 -
2923 - inode = iget_locked(sb, ino);
2924 - if (!inode)
2925 - return ERR_PTR(-ENOMEM);
2926 - if (!(inode->i_state & I_NEW))
2927 - return inode;
2928 -
2929 - /* NB This is called as a side effect of other functions, but
2930 - * we had to release the lock to prevent deadlocks, so
2931 - * need to lock again.
2932 - */
2933 -
2934 - yaffs_GrossLock(dev);
2935 -
2936 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2937 -
2938 - yaffs_FillInodeFromObject(inode, obj);
2939 -
2940 - yaffs_GrossUnlock(dev);
2941 -
2942 - unlock_new_inode(inode);
2943 - return inode;
2944 -}
2945 -
2946 -#else
2947 -
2948 -static void yaffs_read_inode(struct inode *inode)
2949 -{
2950 - /* NB This is called as a side effect of other functions, but
2951 - * we had to release the lock to prevent deadlocks, so
2952 - * need to lock again.
2953 - */
2954 -
2955 - yaffs_Object *obj;
2956 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
2957 -
2958 - T(YAFFS_TRACE_OS,
2959 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
2960 -
2961 - yaffs_GrossLock(dev);
2962 -
2963 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2964 -
2965 - yaffs_FillInodeFromObject(inode, obj);
2966 -
2967 - yaffs_GrossUnlock(dev);
2968 -}
2969 -
2970 -#endif
2971 -
2972 -static YLIST_HEAD(yaffs_dev_list);
2973 -
2974 -#if 0 /* not used */
2975 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
2976 -{
2977 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2978 -
2979 - if (*flags & MS_RDONLY) {
2980 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
2981 -
2982 - T(YAFFS_TRACE_OS,
2983 - ("yaffs_remount_fs: %s: RO\n", dev->name));
2984 -
2985 - yaffs_GrossLock(dev);
2986 -
2987 - yaffs_FlushEntireDeviceCache(dev);
2988 -
2989 - yaffs_CheckpointSave(dev);
2990 -
2991 - if (mtd->sync)
2992 - mtd->sync(mtd);
2993 -
2994 - yaffs_GrossUnlock(dev);
2995 - } else {
2996 - T(YAFFS_TRACE_OS,
2997 - ("yaffs_remount_fs: %s: RW\n", dev->name));
2998 - }
2999 -
3000 - return 0;
3001 -}
3002 -#endif
3003 -
3004 -static void yaffs_put_super(struct super_block *sb)
3005 -{
3006 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3007 -
3008 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3009 -
3010 - yaffs_GrossLock(dev);
3011 -
3012 - yaffs_FlushEntireDeviceCache(dev);
3013 -
3014 - yaffs_CheckpointSave(dev);
3015 -
3016 - if (dev->putSuperFunc)
3017 - dev->putSuperFunc(sb);
3018 -
3019 - yaffs_Deinitialise(dev);
3020 -
3021 - yaffs_GrossUnlock(dev);
3022 -
3023 - /* we assume this is protected by lock_kernel() in mount/umount */
3024 - ylist_del(&dev->devList);
3025 -
3026 - if (dev->spareBuffer) {
3027 - YFREE(dev->spareBuffer);
3028 - dev->spareBuffer = NULL;
3029 - }
3030 -
3031 - kfree(dev);
3032 -}
3033 -
3034 -
3035 -static void yaffs_MTDPutSuper(struct super_block *sb)
3036 -{
3037 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3038 -
3039 - if (mtd->sync)
3040 - mtd->sync(mtd);
3041 -
3042 - put_mtd_device(mtd);
3043 -}
3044 -
3045 -
3046 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3047 -{
3048 - struct super_block *sb = (struct super_block *)vsb;
3049 -
3050 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3051 - if (sb)
3052 - sb->s_dirt = 1;
3053 -}
3054 -
3055 -typedef struct {
3056 - int inband_tags;
3057 - int skip_checkpoint_read;
3058 - int skip_checkpoint_write;
3059 - int no_cache;
3060 -} yaffs_options;
3061 -
3062 -#define MAX_OPT_LEN 20
3063 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3064 -{
3065 - char cur_opt[MAX_OPT_LEN + 1];
3066 - int p;
3067 - int error = 0;
3068 -
3069 - /* Parse through the options which is a comma seperated list */
3070 -
3071 - while (options_str && *options_str && !error) {
3072 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3073 - p = 0;
3074 -
3075 - while (*options_str && *options_str != ',') {
3076 - if (p < MAX_OPT_LEN) {
3077 - cur_opt[p] = *options_str;
3078 - p++;
3079 - }
3080 - options_str++;
3081 - }
3082 -
3083 - if (!strcmp(cur_opt, "inband-tags"))
3084 - options->inband_tags = 1;
3085 - else if (!strcmp(cur_opt, "no-cache"))
3086 - options->no_cache = 1;
3087 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3088 - options->skip_checkpoint_read = 1;
3089 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3090 - options->skip_checkpoint_write = 1;
3091 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3092 - options->skip_checkpoint_read = 1;
3093 - options->skip_checkpoint_write = 1;
3094 - } else {
3095 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3096 - cur_opt);
3097 - error = 1;
3098 - }
3099 - }
3100 -
3101 - return error;
3102 -}
3103 -
3104 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3105 - struct super_block *sb,
3106 - void *data, int silent)
3107 -{
3108 - int nBlocks;
3109 - struct inode *inode = NULL;
3110 - struct dentry *root;
3111 - yaffs_Device *dev = 0;
3112 - char devname_buf[BDEVNAME_SIZE + 1];
3113 - struct mtd_info *mtd;
3114 - int err;
3115 - char *data_str = (char *)data;
3116 -
3117 - yaffs_options options;
3118 -
3119 - sb->s_magic = YAFFS_MAGIC;
3120 - sb->s_op = &yaffs_super_ops;
3121 - sb->s_flags |= MS_NOATIME;
3122 -
3123 - if (!sb)
3124 - printk(KERN_INFO "yaffs: sb is NULL\n");
3125 - else if (!sb->s_dev)
3126 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3127 - else if (!yaffs_devname(sb, devname_buf))
3128 - printk(KERN_INFO "yaffs: devname is NULL\n");
3129 - else
3130 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3131 - sb->s_dev,
3132 - yaffs_devname(sb, devname_buf));
3133 -
3134 - if (!data_str)
3135 - data_str = "";
3136 -
3137 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3138 -
3139 - memset(&options, 0, sizeof(options));
3140 -
3141 - if (yaffs_parse_options(&options, data_str)) {
3142 - /* Option parsing failed */
3143 - return NULL;
3144 - }
3145 -
3146 -
3147 - sb->s_blocksize = PAGE_CACHE_SIZE;
3148 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3149 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3150 - T(YAFFS_TRACE_OS,
3151 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3152 -
3153 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3154 - T(YAFFS_TRACE_OS,
3155 - ("yaffs: Write verification disabled. All guarantees "
3156 - "null and void\n"));
3157 -#endif
3158 -
3159 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3160 - "\"%s\"\n",
3161 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3162 - yaffs_devname(sb, devname_buf)));
3163 -
3164 - /* Check it's an mtd device..... */
3165 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3166 - return NULL; /* This isn't an mtd device */
3167 -
3168 - /* Get the device */
3169 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3170 - if (!mtd) {
3171 - T(YAFFS_TRACE_ALWAYS,
3172 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3173 - MINOR(sb->s_dev)));
3174 - return NULL;
3175 - }
3176 - /* Check it's NAND */
3177 - if (mtd->type != MTD_NANDFLASH) {
3178 - T(YAFFS_TRACE_ALWAYS,
3179 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3180 - return NULL;
3181 - }
3182 -
3183 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3184 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3185 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3186 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3187 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3188 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3189 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3190 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3191 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3192 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3193 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3194 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3195 -#else
3196 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3197 -#endif
3198 -
3199 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3200 -
3201 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3202 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3203 - yaffsVersion = 2;
3204 - }
3205 -
3206 - /* Added NCB 26/5/2006 for completeness */
3207 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3208 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3209 - yaffsVersion = 1;
3210 - }
3211 -
3212 -#endif
3213 -
3214 - if (yaffsVersion == 2) {
3215 - /* Check for version 2 style functions */
3216 - if (!mtd->erase ||
3217 - !mtd->block_isbad ||
3218 - !mtd->block_markbad ||
3219 - !mtd->read ||
3220 - !mtd->write ||
3221 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3222 - !mtd->read_oob || !mtd->write_oob) {
3223 -#else
3224 - !mtd->write_ecc ||
3225 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3226 -#endif
3227 - T(YAFFS_TRACE_ALWAYS,
3228 - ("yaffs: MTD device does not support required "
3229 - "functions\n"));;
3230 - return NULL;
3231 - }
3232 -
3233 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3234 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3235 - !options.inband_tags) {
3236 - T(YAFFS_TRACE_ALWAYS,
3237 - ("yaffs: MTD device does not have the "
3238 - "right page sizes\n"));
3239 - return NULL;
3240 - }
3241 - } else {
3242 - /* Check for V1 style functions */
3243 - if (!mtd->erase ||
3244 - !mtd->read ||
3245 - !mtd->write ||
3246 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3247 - !mtd->read_oob || !mtd->write_oob) {
3248 -#else
3249 - !mtd->write_ecc ||
3250 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3251 -#endif
3252 - T(YAFFS_TRACE_ALWAYS,
3253 - ("yaffs: MTD device does not support required "
3254 - "functions\n"));;
3255 - return NULL;
3256 - }
3257 -
3258 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3259 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3260 - T(YAFFS_TRACE_ALWAYS,
3261 - ("yaffs: MTD device does not support have the "
3262 - "right page sizes\n"));
3263 - return NULL;
3264 - }
3265 - }
3266 -
3267 - /* OK, so if we got here, we have an MTD that's NAND and looks
3268 - * like it has the right capabilities
3269 - * Set the yaffs_Device up for mtd
3270 - */
3271 -
3272 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3273 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3274 -#else
3275 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3276 -#endif
3277 - if (!dev) {
3278 - /* Deep shit could not allocate device structure */
3279 - T(YAFFS_TRACE_ALWAYS,
3280 - ("yaffs_read_super: Failed trying to allocate "
3281 - "yaffs_Device. \n"));
3282 - return NULL;
3283 - }
3284 -
3285 - memset(dev, 0, sizeof(yaffs_Device));
3286 - dev->genericDevice = mtd;
3287 - dev->name = mtd->name;
3288 -
3289 - /* Set up the memory size parameters.... */
3290 -
3291 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3292 -
3293 - dev->startBlock = 0;
3294 - dev->endBlock = nBlocks - 1;
3295 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3296 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3297 - dev->nReservedBlocks = 5;
3298 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3299 - dev->inbandTags = options.inband_tags;
3300 -
3301 - /* ... and the functions. */
3302 - if (yaffsVersion == 2) {
3303 - dev->writeChunkWithTagsToNAND =
3304 - nandmtd2_WriteChunkWithTagsToNAND;
3305 - dev->readChunkWithTagsFromNAND =
3306 - nandmtd2_ReadChunkWithTagsFromNAND;
3307 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3308 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3309 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3310 - dev->isYaffs2 = 1;
3311 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3312 - dev->totalBytesPerChunk = mtd->writesize;
3313 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3314 -#else
3315 - dev->totalBytesPerChunk = mtd->oobblock;
3316 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3317 -#endif
3318 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3319 -
3320 - dev->startBlock = 0;
3321 - dev->endBlock = nBlocks - 1;
3322 - } else {
3323 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3324 - /* use the MTD interface in yaffs_mtdif1.c */
3325 - dev->writeChunkWithTagsToNAND =
3326 - nandmtd1_WriteChunkWithTagsToNAND;
3327 - dev->readChunkWithTagsFromNAND =
3328 - nandmtd1_ReadChunkWithTagsFromNAND;
3329 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3330 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3331 -#else
3332 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3333 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3334 -#endif
3335 - dev->isYaffs2 = 0;
3336 - }
3337 - /* ... and common functions */
3338 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3339 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3340 -
3341 - dev->putSuperFunc = yaffs_MTDPutSuper;
3342 -
3343 - dev->superBlock = (void *)sb;
3344 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3345 -
3346 -
3347 -#ifndef CONFIG_YAFFS_DOES_ECC
3348 - dev->useNANDECC = 1;
3349 -#endif
3350 -
3351 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3352 - dev->wideTnodesDisabled = 1;
3353 -#endif
3354 -
3355 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3356 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3357 -
3358 - /* we assume this is protected by lock_kernel() in mount/umount */
3359 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3360 -
3361 - init_MUTEX(&dev->grossLock);
3362 -
3363 - yaffs_GrossLock(dev);
3364 -
3365 - err = yaffs_GutsInitialise(dev);
3366 -
3367 - T(YAFFS_TRACE_OS,
3368 - ("yaffs_read_super: guts initialised %s\n",
3369 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3370 -
3371 - /* Release lock before yaffs_get_inode() */
3372 - yaffs_GrossUnlock(dev);
3373 -
3374 - /* Create root inode */
3375 - if (err == YAFFS_OK)
3376 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3377 - yaffs_Root(dev));
3378 -
3379 - if (!inode)
3380 - return NULL;
3381 -
3382 - inode->i_op = &yaffs_dir_inode_operations;
3383 - inode->i_fop = &yaffs_dir_operations;
3384 -
3385 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3386 -
3387 - root = d_alloc_root(inode);
3388 -
3389 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3390 -
3391 - if (!root) {
3392 - iput(inode);
3393 - return NULL;
3394 - }
3395 - sb->s_root = root;
3396 - sb->s_dirt = !dev->isCheckpointed;
3397 - T(YAFFS_TRACE_ALWAYS,
3398 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3399 -
3400 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3401 - return sb;
3402 -}
3403 -
3404 -
3405 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3406 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3407 - int silent)
3408 -{
3409 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3410 -}
3411 -
3412 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3413 -static int yaffs_read_super(struct file_system_type *fs,
3414 - int flags, const char *dev_name,
3415 - void *data, struct vfsmount *mnt)
3416 -{
3417 -
3418 - return get_sb_bdev(fs, flags, dev_name, data,
3419 - yaffs_internal_read_super_mtd, mnt);
3420 -}
3421 -#else
3422 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3423 - int flags, const char *dev_name,
3424 - void *data)
3425 -{
3426 -
3427 - return get_sb_bdev(fs, flags, dev_name, data,
3428 - yaffs_internal_read_super_mtd);
3429 -}
3430 -#endif
3431 -
3432 -static struct file_system_type yaffs_fs_type = {
3433 - .owner = THIS_MODULE,
3434 - .name = "yaffs",
3435 - .get_sb = yaffs_read_super,
3436 - .kill_sb = kill_block_super,
3437 - .fs_flags = FS_REQUIRES_DEV,
3438 -};
3439 -#else
3440 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3441 - int silent)
3442 -{
3443 - return yaffs_internal_read_super(1, sb, data, silent);
3444 -}
3445 -
3446 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3447 - FS_REQUIRES_DEV);
3448 -#endif
3449 -
3450 -
3451 -#ifdef CONFIG_YAFFS_YAFFS2
3452 -
3453 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3454 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3455 - int silent)
3456 -{
3457 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3458 -}
3459 -
3460 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3461 -static int yaffs2_read_super(struct file_system_type *fs,
3462 - int flags, const char *dev_name, void *data,
3463 - struct vfsmount *mnt)
3464 -{
3465 - return get_sb_bdev(fs, flags, dev_name, data,
3466 - yaffs2_internal_read_super_mtd, mnt);
3467 -}
3468 -#else
3469 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3470 - int flags, const char *dev_name,
3471 - void *data)
3472 -{
3473 -
3474 - return get_sb_bdev(fs, flags, dev_name, data,
3475 - yaffs2_internal_read_super_mtd);
3476 -}
3477 -#endif
3478 -
3479 -static struct file_system_type yaffs2_fs_type = {
3480 - .owner = THIS_MODULE,
3481 - .name = "yaffs2",
3482 - .get_sb = yaffs2_read_super,
3483 - .kill_sb = kill_block_super,
3484 - .fs_flags = FS_REQUIRES_DEV,
3485 -};
3486 -#else
3487 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3488 - void *data, int silent)
3489 -{
3490 - return yaffs_internal_read_super(2, sb, data, silent);
3491 -}
3492 -
3493 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3494 - FS_REQUIRES_DEV);
3495 -#endif
3496 -
3497 -#endif /* CONFIG_YAFFS_YAFFS2 */
3498 -
3499 -static struct proc_dir_entry *my_proc_entry;
3500 -
3501 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3502 -{
3503 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3504 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3505 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3506 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3507 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3508 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3509 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3510 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3511 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3512 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3513 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3514 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3515 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3516 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3517 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3518 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3519 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3520 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3521 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3522 - buf += sprintf(buf, "passiveGCs......... %d\n",
3523 - dev->passiveGarbageCollections);
3524 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3525 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3526 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3527 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3528 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3529 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3530 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3531 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3532 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3533 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3534 - buf +=
3535 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3536 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3537 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3538 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3539 -
3540 - return buf;
3541 -}
3542 -
3543 -static int yaffs_proc_read(char *page,
3544 - char **start,
3545 - off_t offset, int count, int *eof, void *data)
3546 -{
3547 - struct ylist_head *item;
3548 - char *buf = page;
3549 - int step = offset;
3550 - int n = 0;
3551 -
3552 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3553 - * We use 'offset' (*ppos) to indicate where we are in devList.
3554 - * This also assumes the user has posted a read buffer large
3555 - * enough to hold the complete output; but that's life in /proc.
3556 - */
3557 -
3558 - *(int *)start = 1;
3559 -
3560 - /* Print header first */
3561 - if (step == 0) {
3562 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3563 - "\n%s\n%s\n", yaffs_fs_c_version,
3564 - yaffs_guts_c_version);
3565 - }
3566 -
3567 - /* hold lock_kernel while traversing yaffs_dev_list */
3568 - lock_kernel();
3569 -
3570 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3571 - ylist_for_each(item, &yaffs_dev_list) {
3572 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3573 - if (n < step) {
3574 - n++;
3575 - continue;
3576 - }
3577 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3578 - buf = yaffs_dump_dev(buf, dev);
3579 - break;
3580 - }
3581 - unlock_kernel();
3582 -
3583 - return buf - page < count ? buf - page : count;
3584 -}
3585 -
3586 -/**
3587 - * Set the verbosity of the warnings and error messages.
3588 - *
3589 - * Note that the names can only be a..z or _ with the current code.
3590 - */
3591 -
3592 -static struct {
3593 - char *mask_name;
3594 - unsigned mask_bitfield;
3595 -} mask_flags[] = {
3596 - {"allocate", YAFFS_TRACE_ALLOCATE},
3597 - {"always", YAFFS_TRACE_ALWAYS},
3598 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3599 - {"buffers", YAFFS_TRACE_BUFFERS},
3600 - {"bug", YAFFS_TRACE_BUG},
3601 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
3602 - {"deletion", YAFFS_TRACE_DELETION},
3603 - {"erase", YAFFS_TRACE_ERASE},
3604 - {"error", YAFFS_TRACE_ERROR},
3605 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
3606 - {"gc", YAFFS_TRACE_GC},
3607 - {"mtd", YAFFS_TRACE_MTD},
3608 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
3609 - {"os", YAFFS_TRACE_OS},
3610 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
3611 - {"scan", YAFFS_TRACE_SCAN},
3612 - {"tracing", YAFFS_TRACE_TRACING},
3613 -
3614 - {"verify", YAFFS_TRACE_VERIFY},
3615 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
3616 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
3617 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
3618 -
3619 - {"write", YAFFS_TRACE_WRITE},
3620 - {"all", 0xffffffff},
3621 - {"none", 0},
3622 - {NULL, 0},
3623 -};
3624 -
3625 -#define MAX_MASK_NAME_LENGTH 40
3626 -static int yaffs_proc_write(struct file *file, const char *buf,
3627 - unsigned long count, void *data)
3628 -{
3629 - unsigned rg = 0, mask_bitfield;
3630 - char *end;
3631 - char *mask_name;
3632 - const char *x;
3633 - char substring[MAX_MASK_NAME_LENGTH + 1];
3634 - int i;
3635 - int done = 0;
3636 - int add, len = 0;
3637 - int pos = 0;
3638 -
3639 - rg = yaffs_traceMask;
3640 -
3641 - while (!done && (pos < count)) {
3642 - done = 1;
3643 - while ((pos < count) && isspace(buf[pos]))
3644 - pos++;
3645 -
3646 - switch (buf[pos]) {
3647 - case '+':
3648 - case '-':
3649 - case '=':
3650 - add = buf[pos];
3651 - pos++;
3652 - break;
3653 -
3654 - default:
3655 - add = ' ';
3656 - break;
3657 - }
3658 - mask_name = NULL;
3659 -
3660 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
3661 -
3662 - if (end > buf + pos) {
3663 - mask_name = "numeral";
3664 - len = end - (buf + pos);
3665 - pos += len;
3666 - done = 0;
3667 - } else {
3668 - for (x = buf + pos, i = 0;
3669 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
3670 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
3671 - substring[i] = *x;
3672 - substring[i] = '\0';
3673 -
3674 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3675 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
3676 - mask_name = mask_flags[i].mask_name;
3677 - mask_bitfield = mask_flags[i].mask_bitfield;
3678 - done = 0;
3679 - break;
3680 - }
3681 - }
3682 - }
3683 -
3684 - if (mask_name != NULL) {
3685 - done = 0;
3686 - switch (add) {
3687 - case '-':
3688 - rg &= ~mask_bitfield;
3689 - break;
3690 - case '+':
3691 - rg |= mask_bitfield;
3692 - break;
3693 - case '=':
3694 - rg = mask_bitfield;
3695 - break;
3696 - default:
3697 - rg |= mask_bitfield;
3698 - break;
3699 - }
3700 - }
3701 - }
3702 -
3703 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
3704 -
3705 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
3706 -
3707 - if (rg & YAFFS_TRACE_ALWAYS) {
3708 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3709 - char flag;
3710 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
3711 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
3712 - }
3713 - }
3714 -
3715 - return count;
3716 -}
3717 -
3718 -/* Stuff to handle installation of file systems */
3719 -struct file_system_to_install {
3720 - struct file_system_type *fst;
3721 - int installed;
3722 -};
3723 -
3724 -static struct file_system_to_install fs_to_install[] = {
3725 - {&yaffs_fs_type, 0},
3726 - {&yaffs2_fs_type, 0},
3727 - {NULL, 0}
3728 -};
3729 -
3730 -static int __init init_yaffs_fs(void)
3731 -{
3732 - int error = 0;
3733 - struct file_system_to_install *fsinst;
3734 -
3735 - T(YAFFS_TRACE_ALWAYS,
3736 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
3737 -
3738 - /* Install the proc_fs entry */
3739 - my_proc_entry = create_proc_entry("yaffs",
3740 - S_IRUGO | S_IFREG,
3741 - YPROC_ROOT);
3742 -
3743 - if (my_proc_entry) {
3744 - my_proc_entry->write_proc = yaffs_proc_write;
3745 - my_proc_entry->read_proc = yaffs_proc_read;
3746 - my_proc_entry->data = NULL;
3747 - } else
3748 - return -ENOMEM;
3749 -
3750 - /* Now add the file system entries */
3751 -
3752 - fsinst = fs_to_install;
3753 -
3754 - while (fsinst->fst && !error) {
3755 - error = register_filesystem(fsinst->fst);
3756 - if (!error)
3757 - fsinst->installed = 1;
3758 - fsinst++;
3759 - }
3760 -
3761 - /* Any errors? uninstall */
3762 - if (error) {
3763 - fsinst = fs_to_install;
3764 -
3765 - while (fsinst->fst) {
3766 - if (fsinst->installed) {
3767 - unregister_filesystem(fsinst->fst);
3768 - fsinst->installed = 0;
3769 - }
3770 - fsinst++;
3771 - }
3772 - }
3773 -
3774 - return error;
3775 -}
3776 -
3777 -static void __exit exit_yaffs_fs(void)
3778 -{
3779 -
3780 - struct file_system_to_install *fsinst;
3781 -
3782 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
3783 - " removing. \n"));
3784 -
3785 - remove_proc_entry("yaffs", YPROC_ROOT);
3786 -
3787 - fsinst = fs_to_install;
3788 -
3789 - while (fsinst->fst) {
3790 - if (fsinst->installed) {
3791 - unregister_filesystem(fsinst->fst);
3792 - fsinst->installed = 0;
3793 - }
3794 - fsinst++;
3795 - }
3796 -}
3797 -
3798 -module_init(init_yaffs_fs)
3799 -module_exit(exit_yaffs_fs)
3800 -
3801 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
3802 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
3803 -MODULE_LICENSE("GPL");
3804 --- a/fs/yaffs2/yaffs_getblockinfo.h
3805 +++ b/fs/yaffs2/yaffs_getblockinfo.h
3806 @@ -1,7 +1,7 @@
3807 /*
3808 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3809 *
3810 - * Copyright (C) 2002-2007 Aleph One Ltd.
3811 + * Copyright (C) 2002-2010 Aleph One Ltd.
3812 * for Toby Churchill Ltd and Brightstar Engineering
3813 *
3814 * Created by Charles Manning <charles@aleph1.co.uk>
3815 @@ -17,6 +17,7 @@
3816 #define __YAFFS_GETBLOCKINFO_H__
3817
3818 #include "yaffs_guts.h"
3819 +#include "yaffs_trace.h"
3820
3821 /* Function to manipulate block info */
3822 static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
3823 --- a/fs/yaffs2/yaffs_guts.c
3824 +++ b/fs/yaffs2/yaffs_guts.c
3825 @@ -1,7 +1,7 @@
3826 /*
3827 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3828 *
3829 - * Copyright (C) 2002-2007 Aleph One Ltd.
3830 + * Copyright (C) 2002-2010 Aleph One Ltd.
3831 * for Toby Churchill Ltd and Brightstar Engineering
3832 *
3833 * Created by Charles Manning <charles@aleph1.co.uk>
3834 @@ -10,11 +10,8 @@
3835 * it under the terms of the GNU General Public License version 2 as
3836 * published by the Free Software Foundation.
3837 */
3838 -
3839 -const char *yaffs_guts_c_version =
3840 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
3841 -
3842 #include "yportenv.h"
3843 +#include "yaffs_trace.h"
3844
3845 #include "yaffsinterface.h"
3846 #include "yaffs_guts.h"
3847 @@ -22,22 +19,28 @@ const char *yaffs_guts_c_version =
3848 #include "yaffs_getblockinfo.h"
3849
3850 #include "yaffs_tagscompat.h"
3851 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
3852 -#include "yaffs_qsort.h"
3853 -#endif
3854 +
3855 #include "yaffs_nand.h"
3856
3857 -#include "yaffs_checkptrw.h"
3858 +#include "yaffs_yaffs1.h"
3859 +#include "yaffs_yaffs2.h"
3860 +#include "yaffs_bitmap.h"
3861 +#include "yaffs_verify.h"
3862
3863 #include "yaffs_nand.h"
3864 #include "yaffs_packedtags2.h"
3865
3866 +#include "yaffs_nameval.h"
3867 +#include "yaffs_allocator.h"
3868
3869 -#define YAFFS_PASSIVE_GC_CHUNKS 2
3870 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
3871 +#define YAFFS_GC_GOOD_ENOUGH 2
3872 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
3873
3874 #include "yaffs_ecc.h"
3875
3876
3877 +
3878 /* Robustification (if it ever comes about...) */
3879 static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
3880 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
3881 @@ -49,33 +52,26 @@ static void yaffs_HandleUpdateChunk(yaff
3882 const yaffs_ExtendedTags *tags);
3883
3884 /* Other local prototypes */
3885 +static void yaffs_UpdateParent(yaffs_Object *obj);
3886 static int yaffs_UnlinkObject(yaffs_Object *obj);
3887 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
3888
3889 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
3890 -
3891 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
3892 const __u8 *buffer,
3893 yaffs_ExtendedTags *tags,
3894 int useReserve);
3895 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
3896 - int chunkInNAND, int inScan);
3897 +
3898
3899 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
3900 yaffs_ObjectType type);
3901 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
3902 - yaffs_Object *obj);
3903 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
3904 - int force, int isShrink, int shadows);
3905 +
3906 +
3907 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
3908 +
3909 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
3910 static int yaffs_CheckStructures(void);
3911 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
3912 - int chunkOffset, int *limit);
3913 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
3914
3915 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
3916 -
3917 -
3918 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
3919 int chunkInNAND);
3920
3921 @@ -87,30 +83,22 @@ static int yaffs_TagsMatch(const yaffs_E
3922 static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
3923 yaffs_BlockInfo **blockUsedPtr);
3924
3925 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
3926 -
3927 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
3928
3929 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
3930 -#ifdef YAFFS_PARANOID
3931 -static int yaffs_CheckFileSanity(yaffs_Object *in);
3932 -#else
3933 -#define yaffs_CheckFileSanity(in)
3934 -#endif
3935 -
3936 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
3937 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
3938
3939 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
3940 -
3941 static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
3942 yaffs_ExtendedTags *tags);
3943
3944 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
3945 - unsigned pos);
3946 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
3947 - yaffs_FileStructure *fStruct,
3948 - __u32 chunkId);
3949 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
3950 + int chunkInNAND,
3951 + const __u8 *data,
3952 + yaffs_ExtendedTags *tags);
3953 +
3954 +
3955 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
3956 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
3957
3958
3959 /* Function to calculate chunk and offset */
3960 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
3961
3962 static __u32 Shifts(__u32 x)
3963 {
3964 - int nShifts;
3965 + __u32 nShifts;
3966
3967 nShifts = 0;
3968
3969 @@ -203,7 +191,7 @@ static int yaffs_InitialiseTempBuffers(y
3970 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
3971 dev->tempBuffer[i].line = 0; /* not in use */
3972 dev->tempBuffer[i].buffer = buf =
3973 - YMALLOC_DMA(dev->totalBytesPerChunk);
3974 + YMALLOC_DMA(dev->param.totalBytesPerChunk);
3975 }
3976
3977 return buf ? YAFFS_OK : YAFFS_FAIL;
3978 @@ -286,7 +274,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
3979 return 1;
3980 }
3981
3982 - for (i = 0; i < dev->nShortOpCaches; i++) {
3983 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
3984 if (dev->srCache[i].data == buffer)
3985 return 1;
3986 }
3987 @@ -299,6374 +287,4183 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
3988 return 0;
3989 }
3990
3991 -
3992 -
3993 /*
3994 - * Chunk bitmap manipulations
3995 + * Verification code
3996 */
3997
3998 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
3999 -{
4000 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4001 - T(YAFFS_TRACE_ERROR,
4002 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4003 - blk));
4004 - YBUG();
4005 - }
4006 - return dev->chunkBits +
4007 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4008 -}
4009
4010 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4011 -{
4012 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4013 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4014 - T(YAFFS_TRACE_ERROR,
4015 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4016 - blk, chunk));
4017 - YBUG();
4018 - }
4019 -}
4020
4021 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4022 -{
4023 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4024
4025 - memset(blkBits, 0, dev->chunkBitmapStride);
4026 -}
4027 +/*
4028 + * Simple hash function. Needs to have a reasonable spread
4029 + */
4030
4031 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4032 +static Y_INLINE int yaffs_HashFunction(int n)
4033 {
4034 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4035 -
4036 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4037 -
4038 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4039 + n = abs(n);
4040 + return n % YAFFS_NOBJECT_BUCKETS;
4041 }
4042
4043 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4044 -{
4045 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4046 -
4047 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4048 -
4049 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4050 -}
4051 +/*
4052 + * Access functions to useful fake objects.
4053 + * Note that root might have a presence in NAND if permissions are set.
4054 + */
4055
4056 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4057 +yaffs_Object *yaffs_Root(yaffs_Device *dev)
4058 {
4059 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4060 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4061 -
4062 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4063 + return dev->rootDir;
4064 }
4065
4066 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4067 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4068 {
4069 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4070 - int i;
4071 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4072 - if (*blkBits)
4073 - return 1;
4074 - blkBits++;
4075 - }
4076 - return 0;
4077 + return dev->lostNFoundDir;
4078 }
4079
4080 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4081 -{
4082 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4083 - int i;
4084 - int n = 0;
4085 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4086 - __u8 x = *blkBits;
4087 - while (x) {
4088 - if (x & 1)
4089 - n++;
4090 - x >>= 1;
4091 - }
4092 -
4093 - blkBits++;
4094 - }
4095 - return n;
4096 -}
4097
4098 /*
4099 - * Verification code
4100 + * Erased NAND checking functions
4101 */
4102
4103 -static int yaffs_SkipVerification(yaffs_Device *dev)
4104 -{
4105 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4106 -}
4107 -
4108 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4109 -{
4110 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4111 -}
4112 -
4113 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4114 +int yaffs_CheckFF(__u8 *buffer, int nBytes)
4115 {
4116 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4117 + /* Horrible, slow implementation */
4118 + while (nBytes--) {
4119 + if (*buffer != 0xFF)
4120 + return 0;
4121 + buffer++;
4122 + }
4123 + return 1;
4124 }
4125
4126 -static const char *blockStateName[] = {
4127 -"Unknown",
4128 -"Needs scanning",
4129 -"Scanning",
4130 -"Empty",
4131 -"Allocating",
4132 -"Full",
4133 -"Dirty",
4134 -"Checkpoint",
4135 -"Collecting",
4136 -"Dead"
4137 -};
4138 -
4139 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4140 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4141 + int chunkInNAND)
4142 {
4143 - int actuallyUsed;
4144 - int inUse;
4145 + int retval = YAFFS_OK;
4146 + __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4147 + yaffs_ExtendedTags tags;
4148 + int result;
4149
4150 - if (yaffs_SkipVerification(dev))
4151 - return;
4152 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4153
4154 - /* Report illegal runtime states */
4155 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4156 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4157 + if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4158 + retval = YAFFS_FAIL;
4159
4160 - switch (bi->blockState) {
4161 - case YAFFS_BLOCK_STATE_UNKNOWN:
4162 - case YAFFS_BLOCK_STATE_SCANNING:
4163 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4164 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4165 - n, blockStateName[bi->blockState]));
4166 + if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4167 + T(YAFFS_TRACE_NANDACCESS,
4168 + (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
4169 + retval = YAFFS_FAIL;
4170 }
4171
4172 - /* Check pages in use and soft deletions are legal */
4173 -
4174 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4175 -
4176 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4177 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4178 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4179 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4180 - n, bi->pagesInUse, bi->softDeletions));
4181 -
4182 + yaffs_ReleaseTempBuffer(dev, data, __LINE__);
4183
4184 - /* Check chunk bitmap legal */
4185 - inUse = yaffs_CountChunkBits(dev, n);
4186 - if (inUse != bi->pagesInUse)
4187 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4188 - n, bi->pagesInUse, inUse));
4189 + return retval;
4190
4191 - /* Check that the sequence number is valid.
4192 - * Ten million is legal, but is very unlikely
4193 - */
4194 - if (dev->isYaffs2 &&
4195 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4196 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4197 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4198 - n, bi->sequenceNumber));
4199 }
4200
4201 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4202 - int n)
4203 +
4204 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
4205 + int chunkInNAND,
4206 + const __u8 *data,
4207 + yaffs_ExtendedTags *tags)
4208 {
4209 - yaffs_VerifyBlock(dev, bi, n);
4210 + int retval = YAFFS_OK;
4211 + yaffs_ExtendedTags tempTags;
4212 + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
4213 + int result;
4214 +
4215 + result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
4216 + if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
4217 + tempTags.objectId != tags->objectId ||
4218 + tempTags.chunkId != tags->chunkId ||
4219 + tempTags.byteCount != tags->byteCount)
4220 + retval = YAFFS_FAIL;
4221
4222 - /* After collection the block should be in the erased state */
4223 - /* This will need to change if we do partial gc */
4224 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4225
4226 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4227 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4228 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4229 - n, bi->blockState));
4230 - }
4231 + return retval;
4232 }
4233
4234 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4235 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
4236 + const __u8 *data,
4237 + yaffs_ExtendedTags *tags,
4238 + int useReserve)
4239 {
4240 - int i;
4241 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4242 - int nIllegalBlockStates = 0;
4243 -
4244 - if (yaffs_SkipVerification(dev))
4245 - return;
4246 -
4247 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4248 -
4249 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4250 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4251 - yaffs_VerifyBlock(dev, bi, i);
4252 -
4253 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4254 - nBlocksPerState[bi->blockState]++;
4255 - else
4256 - nIllegalBlockStates++;
4257 - }
4258 + int attempts = 0;
4259 + int writeOk = 0;
4260 + int chunk;
4261
4262 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4263 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4264 + yaffs2_InvalidateCheckpoint(dev);
4265
4266 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4267 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4268 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4269 + do {
4270 + yaffs_BlockInfo *bi = 0;
4271 + int erasedOk = 0;
4272
4273 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4274 - T(YAFFS_TRACE_VERIFY,
4275 - (TSTR("%s %d blocks"TENDSTR),
4276 - blockStateName[i], nBlocksPerState[i]));
4277 + chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
4278 + if (chunk < 0) {
4279 + /* no space */
4280 + break;
4281 + }
4282
4283 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4284 - T(YAFFS_TRACE_VERIFY,
4285 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4286 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4287 + /* First check this chunk is erased, if it needs
4288 + * checking. The checking policy (unless forced
4289 + * always on) is as follows:
4290 + *
4291 + * Check the first page we try to write in a block.
4292 + * If the check passes then we don't need to check any
4293 + * more. If the check fails, we check again...
4294 + * If the block has been erased, we don't need to check.
4295 + *
4296 + * However, if the block has been prioritised for gc,
4297 + * then we think there might be something odd about
4298 + * this block and stop using it.
4299 + *
4300 + * Rationale: We should only ever see chunks that have
4301 + * not been erased if there was a partially written
4302 + * chunk due to power loss. This checking policy should
4303 + * catch that case with very few checks and thus save a
4304 + * lot of checks that are most likely not needed.
4305 + *
4306 + * Mods to the above
4307 + * If an erase check fails or the write fails we skip the
4308 + * rest of the block.
4309 + */
4310
4311 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4312 - T(YAFFS_TRACE_VERIFY,
4313 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4314 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4315 + /* let's give it a try */
4316 + attempts++;
4317
4318 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4319 - T(YAFFS_TRACE_VERIFY,
4320 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4321 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4322 + if(dev->param.alwaysCheckErased)
4323 + bi->skipErasedCheck = 0;
4324
4325 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4326 + if (!bi->skipErasedCheck) {
4327 + erasedOk = yaffs_CheckChunkErased(dev, chunk);
4328 + if (erasedOk != YAFFS_OK) {
4329 + T(YAFFS_TRACE_ERROR,
4330 + (TSTR("**>> yaffs chunk %d was not erased"
4331 + TENDSTR), chunk));
4332
4333 -}
4334 + /* If not erased, delete this one,
4335 + * skip rest of block and
4336 + * try another chunk */
4337 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4338 + yaffs_SkipRestOfBlock(dev);
4339 + continue;
4340 + }
4341 + }
4342
4343 -/*
4344 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4345 - * case those tests will not be performed.
4346 - */
4347 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4348 -{
4349 - if (obj && yaffs_SkipVerification(obj->myDev))
4350 - return;
4351 + writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
4352 + data, tags);
4353
4354 - if (!(tags && obj && oh)) {
4355 - T(YAFFS_TRACE_VERIFY,
4356 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4357 - (__u32)tags, (__u32)obj, (__u32)oh));
4358 - return;
4359 - }
4360 + if(!bi->skipErasedCheck)
4361 + writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
4362
4363 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4364 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4365 - T(YAFFS_TRACE_VERIFY,
4366 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4367 - tags->objectId, oh->type));
4368 + if (writeOk != YAFFS_OK) {
4369 + /* Clean up aborted write, skip to next block and
4370 + * try another chunk */
4371 + yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
4372 + continue;
4373 + }
4374
4375 - if (tags->objectId != obj->objectId)
4376 - T(YAFFS_TRACE_VERIFY,
4377 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4378 - tags->objectId, obj->objectId));
4379 + bi->skipErasedCheck = 1;
4380
4381 + /* Copy the data into the robustification buffer */
4382 + yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
4383
4384 - /*
4385 - * Check that the object's parent ids match if parentCheck requested.
4386 - *
4387 - * Tests do not apply to the root object.
4388 - */
4389 + } while (writeOk != YAFFS_OK &&
4390 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4391
4392 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4393 - T(YAFFS_TRACE_VERIFY,
4394 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4395 - tags->objectId, oh->parentObjectId));
4396 + if (!writeOk)
4397 + chunk = -1;
4398
4399 - if (parentCheck && obj->parent &&
4400 - oh->parentObjectId != obj->parent->objectId &&
4401 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
4402 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
4403 - T(YAFFS_TRACE_VERIFY,
4404 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
4405 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
4406 + if (attempts > 1) {
4407 + T(YAFFS_TRACE_ERROR,
4408 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
4409 + attempts));
4410
4411 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
4412 - T(YAFFS_TRACE_VERIFY,
4413 - (TSTR("Obj %d header name is NULL"TENDSTR),
4414 - obj->objectId));
4415 + dev->nRetriedWrites += (attempts - 1);
4416 + }
4417
4418 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
4419 - T(YAFFS_TRACE_VERIFY,
4420 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
4421 - obj->objectId));
4422 + return chunk;
4423 }
4424
4425
4426 +
4427 +/*
4428 + * Block retiring for handling a broken block.
4429 + */
4430
4431 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
4432 - __u32 level, int chunkOffset)
4433 +static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
4434 {
4435 - int i;
4436 - yaffs_Device *dev = obj->myDev;
4437 - int ok = 1;
4438 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4439
4440 - if (tn) {
4441 - if (level > 0) {
4442 + yaffs2_InvalidateCheckpoint(dev);
4443 +
4444 + yaffs2_ClearOldestDirtySequence(dev,bi);
4445
4446 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
4447 - if (tn->internal[i]) {
4448 - ok = yaffs_VerifyTnodeWorker(obj,
4449 - tn->internal[i],
4450 - level - 1,
4451 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
4452 - }
4453 - }
4454 - } else if (level == 0) {
4455 + if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
4456 + if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
4457 + T(YAFFS_TRACE_ALWAYS, (TSTR(
4458 + "yaffs: Failed to mark bad and erase block %d"
4459 + TENDSTR), blockInNAND));
4460 + } else {
4461 yaffs_ExtendedTags tags;
4462 - __u32 objectId = obj->objectId;
4463 + int chunkId = blockInNAND * dev->param.nChunksPerBlock;
4464
4465 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
4466 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4467
4468 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
4469 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4470 + memset(buffer, 0xff, dev->nDataBytesPerChunk);
4471 + yaffs_InitialiseTags(&tags);
4472 + tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
4473 + if (dev->param.writeChunkWithTagsToNAND(dev, chunkId -
4474 + dev->chunkOffset, buffer, &tags) != YAFFS_OK)
4475 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
4476 + TCONT("write bad block marker to block %d")
4477 + TENDSTR), blockInNAND));
4478
4479 - if (theChunk > 0) {
4480 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
4481 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4482 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
4483 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4484 - objectId, chunkOffset, theChunk,
4485 - tags.objectId, tags.chunkId));
4486 - }
4487 - }
4488 - chunkOffset++;
4489 - }
4490 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4491 }
4492 }
4493
4494 - return ok;
4495 + bi->blockState = YAFFS_BLOCK_STATE_DEAD;
4496 + bi->gcPrioritise = 0;
4497 + bi->needsRetiring = 0;
4498
4499 + dev->nRetiredBlocks++;
4500 }
4501
4502 +/*
4503 + * Functions for robustisizing TODO
4504 + *
4505 + */
4506
4507 -static void yaffs_VerifyFile(yaffs_Object *obj)
4508 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4509 + const __u8 *data,
4510 + const yaffs_ExtendedTags *tags)
4511 {
4512 - int requiredTallness;
4513 - int actualTallness;
4514 - __u32 lastChunk;
4515 - __u32 x;
4516 - __u32 i;
4517 - yaffs_Device *dev;
4518 - yaffs_ExtendedTags tags;
4519 - yaffs_Tnode *tn;
4520 - __u32 objectId;
4521 + dev=dev;
4522 + chunkInNAND=chunkInNAND;
4523 + data=data;
4524 + tags=tags;
4525 +}
4526
4527 - if (!obj)
4528 - return;
4529 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4530 + const yaffs_ExtendedTags *tags)
4531 +{
4532 + dev=dev;
4533 + chunkInNAND=chunkInNAND;
4534 + tags=tags;
4535 +}
4536
4537 - if (yaffs_SkipVerification(obj->myDev))
4538 - return;
4539 +void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
4540 +{
4541 + if (!bi->gcPrioritise) {
4542 + bi->gcPrioritise = 1;
4543 + dev->hasPendingPrioritisedGCs = 1;
4544 + bi->chunkErrorStrikes++;
4545
4546 - dev = obj->myDev;
4547 - objectId = obj->objectId;
4548 + if (bi->chunkErrorStrikes > 3) {
4549 + bi->needsRetiring = 1; /* Too many stikes, so retire this */
4550 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
4551
4552 - /* Check file size is consistent with tnode depth */
4553 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
4554 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
4555 - requiredTallness = 0;
4556 - while (x > 0) {
4557 - x >>= YAFFS_TNODES_INTERNAL_BITS;
4558 - requiredTallness++;
4559 + }
4560 }
4561 +}
4562 +
4563 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4564 + int erasedOk)
4565 +{
4566 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
4567 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4568
4569 - actualTallness = obj->variant.fileVariant.topLevel;
4570 + yaffs_HandleChunkError(dev, bi);
4571
4572 - if (requiredTallness > actualTallness)
4573 - T(YAFFS_TRACE_VERIFY,
4574 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
4575 - obj->objectId, actualTallness, requiredTallness));
4576 + if (erasedOk) {
4577 + /* Was an actual write failure, so mark the block for retirement */
4578 + bi->needsRetiring = 1;
4579 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4580 + (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
4581 + }
4582 +
4583 + /* Delete the chunk */
4584 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
4585 + yaffs_SkipRestOfBlock(dev);
4586 +}
4587
4588
4589 - /* Check that the chunks in the tnode tree are all correct.
4590 - * We do this by scanning through the tnode tree and
4591 - * checking the tags for every chunk match.
4592 - */
4593 +/*---------------- Name handling functions ------------*/
4594
4595 - if (yaffs_SkipNANDVerification(dev))
4596 - return;
4597 +static __u16 yaffs_CalcNameSum(const YCHAR *name)
4598 +{
4599 + __u16 sum = 0;
4600 + __u16 i = 1;
4601
4602 - for (i = 1; i <= lastChunk; i++) {
4603 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
4604 + const YUCHAR *bname = (const YUCHAR *) name;
4605 + if (bname) {
4606 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
4607
4608 - if (tn) {
4609 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4610 - if (theChunk > 0) {
4611 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
4612 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4613 - if (tags.objectId != objectId || tags.chunkId != i) {
4614 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4615 - objectId, i, theChunk,
4616 - tags.objectId, tags.chunkId));
4617 - }
4618 - }
4619 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4620 + sum += yaffs_toupper(*bname) * i;
4621 +#else
4622 + sum += (*bname) * i;
4623 +#endif
4624 + i++;
4625 + bname++;
4626 }
4627 }
4628 + return sum;
4629 }
4630
4631 -
4632 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
4633 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
4634 {
4635 - if (obj && yaffs_SkipVerification(obj->myDev))
4636 - return;
4637 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
4638 + memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
4639 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
4640 + yaffs_strcpy(obj->shortName, name);
4641 + else
4642 + obj->shortName[0] = _Y('\0');
4643 +#endif
4644 + obj->sum = yaffs_CalcNameSum(name);
4645 +}
4646
4647 - /* Verify sane equivalent object */
4648 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
4649 +{
4650 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
4651 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
4652 + memset(tmpName,0,sizeof(tmpName));
4653 + yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
4654 + yaffs_SetObjectName(obj,tmpName);
4655 +#else
4656 + yaffs_SetObjectName(obj,oh->name);
4657 +#endif
4658 }
4659
4660 -static void yaffs_VerifySymlink(yaffs_Object *obj)
4661 +/*-------------------- TNODES -------------------
4662 +
4663 + * List of spare tnodes
4664 + * The list is hooked together using the first pointer
4665 + * in the tnode.
4666 + */
4667 +
4668 +
4669 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
4670 {
4671 - if (obj && yaffs_SkipVerification(obj->myDev))
4672 - return;
4673 + yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev);
4674 + if (tn){
4675 + memset(tn, 0, dev->tnodeSize);
4676 + dev->nTnodes++;
4677 + }
4678 +
4679 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4680
4681 - /* Verify symlink string */
4682 + return tn;
4683 }
4684
4685 -static void yaffs_VerifySpecial(yaffs_Object *obj)
4686 +/* FreeTnode frees up a tnode and puts it back on the free list */
4687 +static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
4688 {
4689 - if (obj && yaffs_SkipVerification(obj->myDev))
4690 - return;
4691 + yaffs_FreeRawTnode(dev,tn);
4692 + dev->nTnodes--;
4693 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4694 }
4695
4696 -static void yaffs_VerifyObject(yaffs_Object *obj)
4697 +static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev)
4698 {
4699 - yaffs_Device *dev;
4700 -
4701 - __u32 chunkMin;
4702 - __u32 chunkMax;
4703 -
4704 - __u32 chunkIdOk;
4705 - __u32 chunkInRange;
4706 - __u32 chunkShouldNotBeDeleted;
4707 - __u32 chunkValid;
4708 -
4709 - if (!obj)
4710 - return;
4711 + yaffs_DeinitialiseRawTnodesAndObjects(dev);
4712 + dev->nObjects = 0;
4713 + dev->nTnodes = 0;
4714 +}
4715
4716 - if (obj->beingCreated)
4717 - return;
4718
4719 - dev = obj->myDev;
4720 +void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
4721 + unsigned val)
4722 +{
4723 + __u32 *map = (__u32 *)tn;
4724 + __u32 bitInMap;
4725 + __u32 bitInWord;
4726 + __u32 wordInMap;
4727 + __u32 mask;
4728
4729 - if (yaffs_SkipVerification(dev))
4730 - return;
4731 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4732 + val >>= dev->chunkGroupBits;
4733
4734 - /* Check sane object header chunk */
4735 + bitInMap = pos * dev->tnodeWidth;
4736 + wordInMap = bitInMap / 32;
4737 + bitInWord = bitInMap & (32 - 1);
4738
4739 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
4740 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
4741 + mask = dev->tnodeMask << bitInWord;
4742
4743 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
4744 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
4745 - chunkValid = chunkInRange &&
4746 - yaffs_CheckChunkBit(dev,
4747 - obj->hdrChunk / dev->nChunksPerBlock,
4748 - obj->hdrChunk % dev->nChunksPerBlock);
4749 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
4750 + map[wordInMap] &= ~mask;
4751 + map[wordInMap] |= (mask & (val << bitInWord));
4752
4753 - if (!obj->fake &&
4754 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
4755 - T(YAFFS_TRACE_VERIFY,
4756 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
4757 - obj->objectId, obj->hdrChunk,
4758 - chunkIdOk ? "" : ",out of range",
4759 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
4760 + if (dev->tnodeWidth > (32 - bitInWord)) {
4761 + bitInWord = (32 - bitInWord);
4762 + wordInMap++;;
4763 + mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
4764 + map[wordInMap] &= ~mask;
4765 + map[wordInMap] |= (mask & (val >> bitInWord));
4766 }
4767 +}
4768
4769 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
4770 - yaffs_ExtendedTags tags;
4771 - yaffs_ObjectHeader *oh;
4772 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4773 -
4774 - oh = (yaffs_ObjectHeader *)buffer;
4775 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4776 + unsigned pos)
4777 +{
4778 + __u32 *map = (__u32 *)tn;
4779 + __u32 bitInMap;
4780 + __u32 bitInWord;
4781 + __u32 wordInMap;
4782 + __u32 val;
4783
4784 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
4785 - &tags);
4786 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4787
4788 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
4789 + bitInMap = pos * dev->tnodeWidth;
4790 + wordInMap = bitInMap / 32;
4791 + bitInWord = bitInMap & (32 - 1);
4792
4793 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4794 - }
4795 + val = map[wordInMap] >> bitInWord;
4796
4797 - /* Verify it has a parent */
4798 - if (obj && !obj->fake &&
4799 - (!obj->parent || obj->parent->myDev != dev)) {
4800 - T(YAFFS_TRACE_VERIFY,
4801 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
4802 - obj->objectId, obj->parent));
4803 + if (dev->tnodeWidth > (32 - bitInWord)) {
4804 + bitInWord = (32 - bitInWord);
4805 + wordInMap++;;
4806 + val |= (map[wordInMap] << bitInWord);
4807 }
4808
4809 - /* Verify parent is a directory */
4810 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
4811 - T(YAFFS_TRACE_VERIFY,
4812 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
4813 - obj->objectId, obj->parent->variantType));
4814 - }
4815 + val &= dev->tnodeMask;
4816 + val <<= dev->chunkGroupBits;
4817
4818 - switch (obj->variantType) {
4819 - case YAFFS_OBJECT_TYPE_FILE:
4820 - yaffs_VerifyFile(obj);
4821 - break;
4822 - case YAFFS_OBJECT_TYPE_SYMLINK:
4823 - yaffs_VerifySymlink(obj);
4824 - break;
4825 - case YAFFS_OBJECT_TYPE_DIRECTORY:
4826 - yaffs_VerifyDirectory(obj);
4827 - break;
4828 - case YAFFS_OBJECT_TYPE_HARDLINK:
4829 - yaffs_VerifyHardLink(obj);
4830 - break;
4831 - case YAFFS_OBJECT_TYPE_SPECIAL:
4832 - yaffs_VerifySpecial(obj);
4833 - break;
4834 - case YAFFS_OBJECT_TYPE_UNKNOWN:
4835 - default:
4836 - T(YAFFS_TRACE_VERIFY,
4837 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
4838 - obj->objectId, obj->variantType));
4839 - break;
4840 - }
4841 + return val;
4842 }
4843
4844 -static void yaffs_VerifyObjects(yaffs_Device *dev)
4845 +/* ------------------- End of individual tnode manipulation -----------------*/
4846 +
4847 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
4848 + * The look up tree is represented by the top tnode and the number of topLevel
4849 + * in the tree. 0 means only the level 0 tnode is in the tree.
4850 + */
4851 +
4852 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
4853 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4854 + yaffs_FileStructure *fStruct,
4855 + __u32 chunkId)
4856 {
4857 - yaffs_Object *obj;
4858 - int i;
4859 - struct ylist_head *lh;
4860 + yaffs_Tnode *tn = fStruct->top;
4861 + __u32 i;
4862 + int requiredTallness;
4863 + int level = fStruct->topLevel;
4864
4865 - if (yaffs_SkipVerification(dev))
4866 - return;
4867 + dev=dev;
4868
4869 - /* Iterate through the objects in each hash entry */
4870 + /* Check sane level and chunk Id */
4871 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
4872 + return NULL;
4873
4874 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
4875 - ylist_for_each(lh, &dev->objectBucket[i].list) {
4876 - if (lh) {
4877 - obj = ylist_entry(lh, yaffs_Object, hashLink);
4878 - yaffs_VerifyObject(obj);
4879 - }
4880 - }
4881 + if (chunkId > YAFFS_MAX_CHUNK_ID)
4882 + return NULL;
4883 +
4884 + /* First check we're tall enough (ie enough topLevel) */
4885 +
4886 + i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
4887 + requiredTallness = 0;
4888 + while (i) {
4889 + i >>= YAFFS_TNODES_INTERNAL_BITS;
4890 + requiredTallness++;
4891 }
4892 -}
4893
4894 + if (requiredTallness > fStruct->topLevel)
4895 + return NULL; /* Not tall enough, so we can't find it */
4896
4897 -/*
4898 - * Simple hash function. Needs to have a reasonable spread
4899 - */
4900 + /* Traverse down to level 0 */
4901 + while (level > 0 && tn) {
4902 + tn = tn->internal[(chunkId >>
4903 + (YAFFS_TNODES_LEVEL0_BITS +
4904 + (level - 1) *
4905 + YAFFS_TNODES_INTERNAL_BITS)) &
4906 + YAFFS_TNODES_INTERNAL_MASK];
4907 + level--;
4908 + }
4909
4910 -static Y_INLINE int yaffs_HashFunction(int n)
4911 -{
4912 - n = abs(n);
4913 - return n % YAFFS_NOBJECT_BUCKETS;
4914 + return tn;
4915 }
4916
4917 -/*
4918 - * Access functions to useful fake objects.
4919 - * Note that root might have a presence in NAND if permissions are set.
4920 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
4921 + * This happens in two steps:
4922 + * 1. If the tree isn't tall enough, then make it taller.
4923 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
4924 + *
4925 + * Used when modifying the tree.
4926 + *
4927 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
4928 + * be plugged into the ttree.
4929 */
4930
4931 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
4932 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
4933 + yaffs_FileStructure *fStruct,
4934 + __u32 chunkId,
4935 + yaffs_Tnode *passedTn)
4936 {
4937 - return dev->rootDir;
4938 -}
4939 + int requiredTallness;
4940 + int i;
4941 + int l;
4942 + yaffs_Tnode *tn;
4943
4944 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4945 -{
4946 - return dev->lostNFoundDir;
4947 -}
4948 + __u32 x;
4949
4950
4951 -/*
4952 - * Erased NAND checking functions
4953 - */
4954 + /* Check sane level and page Id */
4955 + if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
4956 + return NULL;
4957
4958 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
4959 -{
4960 - /* Horrible, slow implementation */
4961 - while (nBytes--) {
4962 - if (*buffer != 0xFF)
4963 - return 0;
4964 - buffer++;
4965 - }
4966 - return 1;
4967 -}
4968 -
4969 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4970 - int chunkInNAND)
4971 -{
4972 - int retval = YAFFS_OK;
4973 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4974 - yaffs_ExtendedTags tags;
4975 - int result;
4976 -
4977 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4978 -
4979 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4980 - retval = YAFFS_FAIL;
4981 -
4982 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4983 - T(YAFFS_TRACE_NANDACCESS,
4984 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
4985 - retval = YAFFS_FAIL;
4986 - }
4987 -
4988 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
4989 -
4990 - return retval;
4991 -
4992 -}
4993 -
4994 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
4995 - const __u8 *data,
4996 - yaffs_ExtendedTags *tags,
4997 - int useReserve)
4998 -{
4999 - int attempts = 0;
5000 - int writeOk = 0;
5001 - int chunk;
5002 -
5003 - yaffs_InvalidateCheckpoint(dev);
5004 -
5005 - do {
5006 - yaffs_BlockInfo *bi = 0;
5007 - int erasedOk = 0;
5008 -
5009 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5010 - if (chunk < 0) {
5011 - /* no space */
5012 - break;
5013 - }
5014 -
5015 - /* First check this chunk is erased, if it needs
5016 - * checking. The checking policy (unless forced
5017 - * always on) is as follows:
5018 - *
5019 - * Check the first page we try to write in a block.
5020 - * If the check passes then we don't need to check any
5021 - * more. If the check fails, we check again...
5022 - * If the block has been erased, we don't need to check.
5023 - *
5024 - * However, if the block has been prioritised for gc,
5025 - * then we think there might be something odd about
5026 - * this block and stop using it.
5027 - *
5028 - * Rationale: We should only ever see chunks that have
5029 - * not been erased if there was a partially written
5030 - * chunk due to power loss. This checking policy should
5031 - * catch that case with very few checks and thus save a
5032 - * lot of checks that are most likely not needed.
5033 - */
5034 - if (bi->gcPrioritise) {
5035 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5036 - /* try another chunk */
5037 - continue;
5038 - }
5039 -
5040 - /* let's give it a try */
5041 - attempts++;
5042 -
5043 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5044 - bi->skipErasedCheck = 0;
5045 -#endif
5046 - if (!bi->skipErasedCheck) {
5047 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5048 - if (erasedOk != YAFFS_OK) {
5049 - T(YAFFS_TRACE_ERROR,
5050 - (TSTR("**>> yaffs chunk %d was not erased"
5051 - TENDSTR), chunk));
5052 -
5053 - /* try another chunk */
5054 - continue;
5055 - }
5056 - bi->skipErasedCheck = 1;
5057 - }
5058 -
5059 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5060 - data, tags);
5061 - if (writeOk != YAFFS_OK) {
5062 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5063 - /* try another chunk */
5064 - continue;
5065 - }
5066 -
5067 - /* Copy the data into the robustification buffer */
5068 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5069 -
5070 - } while (writeOk != YAFFS_OK &&
5071 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5072 -
5073 - if (!writeOk)
5074 - chunk = -1;
5075 -
5076 - if (attempts > 1) {
5077 - T(YAFFS_TRACE_ERROR,
5078 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5079 - attempts));
5080 -
5081 - dev->nRetriedWrites += (attempts - 1);
5082 - }
5083 -
5084 - return chunk;
5085 -}
5086 -
5087 -/*
5088 - * Block retiring for handling a broken block.
5089 - */
5090 -
5091 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5092 -{
5093 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5094 -
5095 - yaffs_InvalidateCheckpoint(dev);
5096 -
5097 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5098 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5099 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5100 - "yaffs: Failed to mark bad and erase block %d"
5101 - TENDSTR), blockInNAND));
5102 - } else {
5103 - yaffs_ExtendedTags tags;
5104 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5105 -
5106 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5107 -
5108 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5109 - yaffs_InitialiseTags(&tags);
5110 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5111 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5112 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5113 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5114 - TCONT("write bad block marker to block %d")
5115 - TENDSTR), blockInNAND));
5116 -
5117 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5118 - }
5119 - }
5120 -
5121 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5122 - bi->gcPrioritise = 0;
5123 - bi->needsRetiring = 0;
5124 -
5125 - dev->nRetiredBlocks++;
5126 -}
5127 -
5128 -/*
5129 - * Functions for robustisizing TODO
5130 - *
5131 - */
5132 -
5133 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5134 - const __u8 *data,
5135 - const yaffs_ExtendedTags *tags)
5136 -{
5137 -}
5138 -
5139 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5140 - const yaffs_ExtendedTags *tags)
5141 -{
5142 -}
5143 -
5144 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5145 -{
5146 - if (!bi->gcPrioritise) {
5147 - bi->gcPrioritise = 1;
5148 - dev->hasPendingPrioritisedGCs = 1;
5149 - bi->chunkErrorStrikes++;
5150 -
5151 - if (bi->chunkErrorStrikes > 3) {
5152 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5153 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5154 -
5155 - }
5156 - }
5157 -}
5158 -
5159 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5160 - int erasedOk)
5161 -{
5162 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5163 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5164 -
5165 - yaffs_HandleChunkError(dev, bi);
5166 -
5167 - if (erasedOk) {
5168 - /* Was an actual write failure, so mark the block for retirement */
5169 - bi->needsRetiring = 1;
5170 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5171 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5172 - }
5173 -
5174 - /* Delete the chunk */
5175 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5176 -}
5177 -
5178 -
5179 -/*---------------- Name handling functions ------------*/
5180 -
5181 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5182 -{
5183 - __u16 sum = 0;
5184 - __u16 i = 1;
5185 -
5186 - const YUCHAR *bname = (const YUCHAR *) name;
5187 - if (bname) {
5188 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5189 -
5190 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5191 - sum += yaffs_toupper(*bname) * i;
5192 -#else
5193 - sum += (*bname) * i;
5194 -#endif
5195 - i++;
5196 - bname++;
5197 - }
5198 - }
5199 - return sum;
5200 -}
5201 -
5202 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
5203 -{
5204 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5205 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5206 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
5207 - yaffs_strcpy(obj->shortName, name);
5208 - else
5209 - obj->shortName[0] = _Y('\0');
5210 -#endif
5211 - obj->sum = yaffs_CalcNameSum(name);
5212 -}
5213 -
5214 -/*-------------------- TNODES -------------------
5215 -
5216 - * List of spare tnodes
5217 - * The list is hooked together using the first pointer
5218 - * in the tnode.
5219 - */
5220 -
5221 -/* yaffs_CreateTnodes creates a bunch more tnodes and
5222 - * adds them to the tnode free list.
5223 - * Don't use this function directly
5224 - */
5225 -
5226 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
5227 -{
5228 - int i;
5229 - int tnodeSize;
5230 - yaffs_Tnode *newTnodes;
5231 - __u8 *mem;
5232 - yaffs_Tnode *curr;
5233 - yaffs_Tnode *next;
5234 - yaffs_TnodeList *tnl;
5235 -
5236 - if (nTnodes < 1)
5237 - return YAFFS_OK;
5238 -
5239 - /* Calculate the tnode size in bytes for variable width tnode support.
5240 - * Must be a multiple of 32-bits */
5241 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5242 -
5243 - if (tnodeSize < sizeof(yaffs_Tnode))
5244 - tnodeSize = sizeof(yaffs_Tnode);
5245 -
5246 - /* make these things */
5247 -
5248 - newTnodes = YMALLOC(nTnodes * tnodeSize);
5249 - mem = (__u8 *)newTnodes;
5250 -
5251 - if (!newTnodes) {
5252 - T(YAFFS_TRACE_ERROR,
5253 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
5254 - return YAFFS_FAIL;
5255 - }
5256 -
5257 - /* Hook them into the free list */
5258 -#if 0
5259 - for (i = 0; i < nTnodes - 1; i++) {
5260 - newTnodes[i].internal[0] = &newTnodes[i + 1];
5261 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5262 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5263 -#endif
5264 - }
5265 -
5266 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
5267 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5268 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5269 -#endif
5270 - dev->freeTnodes = newTnodes;
5271 -#else
5272 - /* New hookup for wide tnodes */
5273 - for (i = 0; i < nTnodes - 1; i++) {
5274 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
5275 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
5276 - curr->internal[0] = next;
5277 - }
5278 -
5279 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
5280 - curr->internal[0] = dev->freeTnodes;
5281 - dev->freeTnodes = (yaffs_Tnode *)mem;
5282 -
5283 -#endif
5284 -
5285 -
5286 - dev->nFreeTnodes += nTnodes;
5287 - dev->nTnodesCreated += nTnodes;
5288 -
5289 - /* Now add this bunch of tnodes to a list for freeing up.
5290 - * NB If we can't add this to the management list it isn't fatal
5291 - * but it just means we can't free this bunch of tnodes later.
5292 - */
5293 -
5294 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
5295 - if (!tnl) {
5296 - T(YAFFS_TRACE_ERROR,
5297 - (TSTR
5298 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
5299 - return YAFFS_FAIL;
5300 - } else {
5301 - tnl->tnodes = newTnodes;
5302 - tnl->next = dev->allocatedTnodeList;
5303 - dev->allocatedTnodeList = tnl;
5304 - }
5305 -
5306 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
5307 -
5308 - return YAFFS_OK;
5309 -}
5310 -
5311 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
5312 -
5313 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
5314 -{
5315 - yaffs_Tnode *tn = NULL;
5316 -
5317 - /* If there are none left make more */
5318 - if (!dev->freeTnodes)
5319 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
5320 -
5321 - if (dev->freeTnodes) {
5322 - tn = dev->freeTnodes;
5323 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5324 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
5325 - /* Hoosterman, this thing looks like it isn't in the list */
5326 - T(YAFFS_TRACE_ALWAYS,
5327 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
5328 - }
5329 -#endif
5330 - dev->freeTnodes = dev->freeTnodes->internal[0];
5331 - dev->nFreeTnodes--;
5332 - }
5333 -
5334 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5335 -
5336 - return tn;
5337 -}
5338 -
5339 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
5340 -{
5341 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
5342 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5343 -
5344 - if (tnodeSize < sizeof(yaffs_Tnode))
5345 - tnodeSize = sizeof(yaffs_Tnode);
5346 -
5347 - if (tn)
5348 - memset(tn, 0, tnodeSize);
5349 -
5350 - return tn;
5351 -}
5352 -
5353 -/* FreeTnode frees up a tnode and puts it back on the free list */
5354 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
5355 -{
5356 - if (tn) {
5357 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5358 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
5359 - /* Hoosterman, this thing looks like it is already in the list */
5360 - T(YAFFS_TRACE_ALWAYS,
5361 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
5362 - }
5363 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5364 -#endif
5365 - tn->internal[0] = dev->freeTnodes;
5366 - dev->freeTnodes = tn;
5367 - dev->nFreeTnodes++;
5368 - }
5369 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5370 -}
5371 -
5372 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
5373 -{
5374 - /* Free the list of allocated tnodes */
5375 - yaffs_TnodeList *tmp;
5376 -
5377 - while (dev->allocatedTnodeList) {
5378 - tmp = dev->allocatedTnodeList->next;
5379 -
5380 - YFREE(dev->allocatedTnodeList->tnodes);
5381 - YFREE(dev->allocatedTnodeList);
5382 - dev->allocatedTnodeList = tmp;
5383 -
5384 - }
5385 -
5386 - dev->freeTnodes = NULL;
5387 - dev->nFreeTnodes = 0;
5388 -}
5389 -
5390 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
5391 -{
5392 - dev->allocatedTnodeList = NULL;
5393 - dev->freeTnodes = NULL;
5394 - dev->nFreeTnodes = 0;
5395 - dev->nTnodesCreated = 0;
5396 -}
5397 -
5398 -
5399 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
5400 - unsigned val)
5401 -{
5402 - __u32 *map = (__u32 *)tn;
5403 - __u32 bitInMap;
5404 - __u32 bitInWord;
5405 - __u32 wordInMap;
5406 - __u32 mask;
5407 -
5408 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5409 - val >>= dev->chunkGroupBits;
5410 -
5411 - bitInMap = pos * dev->tnodeWidth;
5412 - wordInMap = bitInMap / 32;
5413 - bitInWord = bitInMap & (32 - 1);
5414 -
5415 - mask = dev->tnodeMask << bitInWord;
5416 -
5417 - map[wordInMap] &= ~mask;
5418 - map[wordInMap] |= (mask & (val << bitInWord));
5419 -
5420 - if (dev->tnodeWidth > (32 - bitInWord)) {
5421 - bitInWord = (32 - bitInWord);
5422 - wordInMap++;;
5423 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
5424 - map[wordInMap] &= ~mask;
5425 - map[wordInMap] |= (mask & (val >> bitInWord));
5426 - }
5427 -}
5428 -
5429 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
5430 - unsigned pos)
5431 -{
5432 - __u32 *map = (__u32 *)tn;
5433 - __u32 bitInMap;
5434 - __u32 bitInWord;
5435 - __u32 wordInMap;
5436 - __u32 val;
5437 -
5438 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5439 -
5440 - bitInMap = pos * dev->tnodeWidth;
5441 - wordInMap = bitInMap / 32;
5442 - bitInWord = bitInMap & (32 - 1);
5443 -
5444 - val = map[wordInMap] >> bitInWord;
5445 -
5446 - if (dev->tnodeWidth > (32 - bitInWord)) {
5447 - bitInWord = (32 - bitInWord);
5448 - wordInMap++;;
5449 - val |= (map[wordInMap] << bitInWord);
5450 - }
5451 -
5452 - val &= dev->tnodeMask;
5453 - val <<= dev->chunkGroupBits;
5454 -
5455 - return val;
5456 -}
5457 -
5458 -/* ------------------- End of individual tnode manipulation -----------------*/
5459 -
5460 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5461 - * The look up tree is represented by the top tnode and the number of topLevel
5462 - * in the tree. 0 means only the level 0 tnode is in the tree.
5463 - */
5464 -
5465 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5466 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
5467 - yaffs_FileStructure *fStruct,
5468 - __u32 chunkId)
5469 -{
5470 - yaffs_Tnode *tn = fStruct->top;
5471 - __u32 i;
5472 - int requiredTallness;
5473 - int level = fStruct->topLevel;
5474 -
5475 - /* Check sane level and chunk Id */
5476 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5477 - return NULL;
5478 -
5479 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5480 - return NULL;
5481 -
5482 - /* First check we're tall enough (ie enough topLevel) */
5483 -
5484 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5485 - requiredTallness = 0;
5486 - while (i) {
5487 - i >>= YAFFS_TNODES_INTERNAL_BITS;
5488 - requiredTallness++;
5489 - }
5490 -
5491 - if (requiredTallness > fStruct->topLevel)
5492 - return NULL; /* Not tall enough, so we can't find it */
5493 -
5494 - /* Traverse down to level 0 */
5495 - while (level > 0 && tn) {
5496 - tn = tn->internal[(chunkId >>
5497 - (YAFFS_TNODES_LEVEL0_BITS +
5498 - (level - 1) *
5499 - YAFFS_TNODES_INTERNAL_BITS)) &
5500 - YAFFS_TNODES_INTERNAL_MASK];
5501 - level--;
5502 - }
5503 -
5504 - return tn;
5505 -}
5506 -
5507 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5508 - * This happens in two steps:
5509 - * 1. If the tree isn't tall enough, then make it taller.
5510 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5511 - *
5512 - * Used when modifying the tree.
5513 - *
5514 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5515 - * be plugged into the ttree.
5516 - */
5517 -
5518 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
5519 - yaffs_FileStructure *fStruct,
5520 - __u32 chunkId,
5521 - yaffs_Tnode *passedTn)
5522 -{
5523 - int requiredTallness;
5524 - int i;
5525 - int l;
5526 - yaffs_Tnode *tn;
5527 -
5528 - __u32 x;
5529 -
5530 -
5531 - /* Check sane level and page Id */
5532 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
5533 - return NULL;
5534 -
5535 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5536 - return NULL;
5537 -
5538 - /* First check we're tall enough (ie enough topLevel) */
5539 -
5540 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5541 - requiredTallness = 0;
5542 - while (x) {
5543 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5544 - requiredTallness++;
5545 - }
5546 -
5547 -
5548 - if (requiredTallness > fStruct->topLevel) {
5549 - /* Not tall enough, gotta make the tree taller */
5550 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
5551 -
5552 - tn = yaffs_GetTnode(dev);
5553 -
5554 - if (tn) {
5555 - tn->internal[0] = fStruct->top;
5556 - fStruct->top = tn;
5557 - } else {
5558 - T(YAFFS_TRACE_ERROR,
5559 - (TSTR("yaffs: no more tnodes" TENDSTR)));
5560 - }
5561 - }
5562 -
5563 - fStruct->topLevel = requiredTallness;
5564 - }
5565 -
5566 - /* Traverse down to level 0, adding anything we need */
5567 -
5568 - l = fStruct->topLevel;
5569 - tn = fStruct->top;
5570 -
5571 - if (l > 0) {
5572 - while (l > 0 && tn) {
5573 - x = (chunkId >>
5574 - (YAFFS_TNODES_LEVEL0_BITS +
5575 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5576 - YAFFS_TNODES_INTERNAL_MASK;
5577 -
5578 -
5579 - if ((l > 1) && !tn->internal[x]) {
5580 - /* Add missing non-level-zero tnode */
5581 - tn->internal[x] = yaffs_GetTnode(dev);
5582 -
5583 - } else if (l == 1) {
5584 - /* Looking from level 1 at level 0 */
5585 - if (passedTn) {
5586 - /* If we already have one, then release it.*/
5587 - if (tn->internal[x])
5588 - yaffs_FreeTnode(dev, tn->internal[x]);
5589 - tn->internal[x] = passedTn;
5590 -
5591 - } else if (!tn->internal[x]) {
5592 - /* Don't have one, none passed in */
5593 - tn->internal[x] = yaffs_GetTnode(dev);
5594 - }
5595 - }
5596 -
5597 - tn = tn->internal[x];
5598 - l--;
5599 - }
5600 - } else {
5601 - /* top is level 0 */
5602 - if (passedTn) {
5603 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
5604 - yaffs_FreeTnode(dev, passedTn);
5605 - }
5606 - }
5607 -
5608 - return tn;
5609 -}
5610 -
5611 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
5612 - yaffs_ExtendedTags *tags, int objectId,
5613 - int chunkInInode)
5614 -{
5615 - int j;
5616 -
5617 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
5618 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
5619 - theChunk % dev->nChunksPerBlock)) {
5620 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
5621 - tags);
5622 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
5623 - /* found it; */
5624 - return theChunk;
5625 - }
5626 - }
5627 - theChunk++;
5628 - }
5629 - return -1;
5630 -}
5631 -
5632 -
5633 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
5634 - * chunks and tnodes in the file
5635 - * Returns 1 if the tree was deleted.
5636 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5637 - */
5638 -
5639 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
5640 - int chunkOffset, int *limit)
5641 -{
5642 - int i;
5643 - int chunkInInode;
5644 - int theChunk;
5645 - yaffs_ExtendedTags tags;
5646 - int foundChunk;
5647 - yaffs_Device *dev = in->myDev;
5648 -
5649 - int allDone = 1;
5650 -
5651 - if (tn) {
5652 - if (level > 0) {
5653 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5654 - i--) {
5655 - if (tn->internal[i]) {
5656 - if (limit && (*limit) < 0) {
5657 - allDone = 0;
5658 - } else {
5659 - allDone =
5660 - yaffs_DeleteWorker(in,
5661 - tn->
5662 - internal
5663 - [i],
5664 - level -
5665 - 1,
5666 - (chunkOffset
5667 - <<
5668 - YAFFS_TNODES_INTERNAL_BITS)
5669 - + i,
5670 - limit);
5671 - }
5672 - if (allDone) {
5673 - yaffs_FreeTnode(dev,
5674 - tn->
5675 - internal[i]);
5676 - tn->internal[i] = NULL;
5677 - }
5678 - }
5679 - }
5680 - return (allDone) ? 1 : 0;
5681 - } else if (level == 0) {
5682 - int hitLimit = 0;
5683 -
5684 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5685 - i--) {
5686 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5687 - if (theChunk) {
5688 -
5689 - chunkInInode = (chunkOffset <<
5690 - YAFFS_TNODES_LEVEL0_BITS) + i;
5691 -
5692 - foundChunk =
5693 - yaffs_FindChunkInGroup(dev,
5694 - theChunk,
5695 - &tags,
5696 - in->objectId,
5697 - chunkInInode);
5698 -
5699 - if (foundChunk > 0) {
5700 - yaffs_DeleteChunk(dev,
5701 - foundChunk, 1,
5702 - __LINE__);
5703 - in->nDataChunks--;
5704 - if (limit) {
5705 - *limit = *limit - 1;
5706 - if (*limit <= 0)
5707 - hitLimit = 1;
5708 - }
5709 -
5710 - }
5711 -
5712 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5713 - }
5714 -
5715 - }
5716 - return (i < 0) ? 1 : 0;
5717 -
5718 - }
5719 -
5720 - }
5721 -
5722 - return 1;
5723 -
5724 -}
5725 -
5726 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
5727 -{
5728 - yaffs_BlockInfo *theBlock;
5729 -
5730 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5731 -
5732 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
5733 - if (theBlock) {
5734 - theBlock->softDeletions++;
5735 - dev->nFreeChunks++;
5736 - }
5737 -}
5738 -
5739 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5740 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5741 - * of the tnode.
5742 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5743 - */
5744 -
5745 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
5746 - __u32 level, int chunkOffset)
5747 -{
5748 - int i;
5749 - int theChunk;
5750 - int allDone = 1;
5751 - yaffs_Device *dev = in->myDev;
5752 -
5753 - if (tn) {
5754 - if (level > 0) {
5755 -
5756 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5757 - i--) {
5758 - if (tn->internal[i]) {
5759 - allDone =
5760 - yaffs_SoftDeleteWorker(in,
5761 - tn->
5762 - internal[i],
5763 - level - 1,
5764 - (chunkOffset
5765 - <<
5766 - YAFFS_TNODES_INTERNAL_BITS)
5767 - + i);
5768 - if (allDone) {
5769 - yaffs_FreeTnode(dev,
5770 - tn->
5771 - internal[i]);
5772 - tn->internal[i] = NULL;
5773 - } else {
5774 - /* Hoosterman... how could this happen? */
5775 - }
5776 - }
5777 - }
5778 - return (allDone) ? 1 : 0;
5779 - } else if (level == 0) {
5780 -
5781 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
5782 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5783 - if (theChunk) {
5784 - /* Note this does not find the real chunk, only the chunk group.
5785 - * We make an assumption that a chunk group is not larger than
5786 - * a block.
5787 - */
5788 - yaffs_SoftDeleteChunk(dev, theChunk);
5789 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5790 - }
5791 -
5792 - }
5793 - return 1;
5794 -
5795 - }
5796 -
5797 - }
5798 -
5799 - return 1;
5800 -
5801 -}
5802 -
5803 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
5804 -{
5805 - if (obj->deleted &&
5806 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
5807 - if (obj->nDataChunks <= 0) {
5808 - /* Empty file with no duplicate object headers, just delete it immediately */
5809 - yaffs_FreeTnode(obj->myDev,
5810 - obj->variant.fileVariant.top);
5811 - obj->variant.fileVariant.top = NULL;
5812 - T(YAFFS_TRACE_TRACING,
5813 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
5814 - obj->objectId));
5815 - yaffs_DoGenericObjectDeletion(obj);
5816 - } else {
5817 - yaffs_SoftDeleteWorker(obj,
5818 - obj->variant.fileVariant.top,
5819 - obj->variant.fileVariant.
5820 - topLevel, 0);
5821 - obj->softDeleted = 1;
5822 - }
5823 - }
5824 -}
5825 -
5826 -/* Pruning removes any part of the file structure tree that is beyond the
5827 - * bounds of the file (ie that does not point to chunks).
5828 - *
5829 - * A file should only get pruned when its size is reduced.
5830 - *
5831 - * Before pruning, the chunks must be pulled from the tree and the
5832 - * level 0 tnode entries must be zeroed out.
5833 - * Could also use this for file deletion, but that's probably better handled
5834 - * by a special case.
5835 - */
5836 -
5837 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
5838 - __u32 level, int del0)
5839 -{
5840 - int i;
5841 - int hasData;
5842 -
5843 - if (tn) {
5844 - hasData = 0;
5845 -
5846 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
5847 - if (tn->internal[i] && level > 0) {
5848 - tn->internal[i] =
5849 - yaffs_PruneWorker(dev, tn->internal[i],
5850 - level - 1,
5851 - (i == 0) ? del0 : 1);
5852 - }
5853 -
5854 - if (tn->internal[i])
5855 - hasData++;
5856 - }
5857 -
5858 - if (hasData == 0 && del0) {
5859 - /* Free and return NULL */
5860 -
5861 - yaffs_FreeTnode(dev, tn);
5862 - tn = NULL;
5863 - }
5864 -
5865 - }
5866 -
5867 - return tn;
5868 -
5869 -}
5870 -
5871 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
5872 - yaffs_FileStructure *fStruct)
5873 -{
5874 - int i;
5875 - int hasData;
5876 - int done = 0;
5877 - yaffs_Tnode *tn;
5878 -
5879 - if (fStruct->topLevel > 0) {
5880 - fStruct->top =
5881 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
5882 -
5883 - /* Now we have a tree with all the non-zero branches NULL but the height
5884 - * is the same as it was.
5885 - * Let's see if we can trim internal tnodes to shorten the tree.
5886 - * We can do this if only the 0th element in the tnode is in use
5887 - * (ie all the non-zero are NULL)
5888 - */
5889 -
5890 - while (fStruct->topLevel && !done) {
5891 - tn = fStruct->top;
5892 -
5893 - hasData = 0;
5894 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
5895 - if (tn->internal[i])
5896 - hasData++;
5897 - }
5898 -
5899 - if (!hasData) {
5900 - fStruct->top = tn->internal[0];
5901 - fStruct->topLevel--;
5902 - yaffs_FreeTnode(dev, tn);
5903 - } else {
5904 - done = 1;
5905 - }
5906 - }
5907 - }
5908 -
5909 - return YAFFS_OK;
5910 -}
5911 -
5912 -/*-------------------- End of File Structure functions.-------------------*/
5913 -
5914 -/* yaffs_CreateFreeObjects creates a bunch more objects and
5915 - * adds them to the object free list.
5916 - */
5917 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
5918 -{
5919 - int i;
5920 - yaffs_Object *newObjects;
5921 - yaffs_ObjectList *list;
5922 -
5923 - if (nObjects < 1)
5924 - return YAFFS_OK;
5925 -
5926 - /* make these things */
5927 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
5928 - list = YMALLOC(sizeof(yaffs_ObjectList));
5929 -
5930 - if (!newObjects || !list) {
5931 - if (newObjects)
5932 - YFREE(newObjects);
5933 - if (list)
5934 - YFREE(list);
5935 - T(YAFFS_TRACE_ALLOCATE,
5936 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
5937 - return YAFFS_FAIL;
5938 - }
5939 -
5940 - /* Hook them into the free list */
5941 - for (i = 0; i < nObjects - 1; i++) {
5942 - newObjects[i].siblings.next =
5943 - (struct ylist_head *)(&newObjects[i + 1]);
5944 - }
5945 -
5946 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
5947 - dev->freeObjects = newObjects;
5948 - dev->nFreeObjects += nObjects;
5949 - dev->nObjectsCreated += nObjects;
5950 -
5951 - /* Now add this bunch of Objects to a list for freeing up. */
5952 -
5953 - list->objects = newObjects;
5954 - list->next = dev->allocatedObjectList;
5955 - dev->allocatedObjectList = list;
5956 -
5957 - return YAFFS_OK;
5958 -}
5959 -
5960 -
5961 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
5962 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
5963 -{
5964 - yaffs_Object *tn = NULL;
5965 -
5966 -#ifdef VALGRIND_TEST
5967 - tn = YMALLOC(sizeof(yaffs_Object));
5968 -#else
5969 - /* If there are none left make more */
5970 - if (!dev->freeObjects)
5971 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
5972 -
5973 - if (dev->freeObjects) {
5974 - tn = dev->freeObjects;
5975 - dev->freeObjects =
5976 - (yaffs_Object *) (dev->freeObjects->siblings.next);
5977 - dev->nFreeObjects--;
5978 - }
5979 -#endif
5980 - if (tn) {
5981 - /* Now sweeten it up... */
5982 -
5983 - memset(tn, 0, sizeof(yaffs_Object));
5984 - tn->beingCreated = 1;
5985 -
5986 - tn->myDev = dev;
5987 - tn->hdrChunk = 0;
5988 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
5989 - YINIT_LIST_HEAD(&(tn->hardLinks));
5990 - YINIT_LIST_HEAD(&(tn->hashLink));
5991 - YINIT_LIST_HEAD(&tn->siblings);
5992 -
5993 -
5994 - /* Now make the directory sane */
5995 - if (dev->rootDir) {
5996 - tn->parent = dev->rootDir;
5997 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
5998 - }
5999 -
6000 - /* Add it to the lost and found directory.
6001 - * NB Can't put root or lostNFound in lostNFound so
6002 - * check if lostNFound exists first
6003 - */
6004 - if (dev->lostNFoundDir)
6005 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
6006 -
6007 - tn->beingCreated = 0;
6008 - }
6009 -
6010 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6011 -
6012 - return tn;
6013 -}
6014 -
6015 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
6016 - __u32 mode)
6017 -{
6018 -
6019 - yaffs_Object *obj =
6020 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6021 - if (obj) {
6022 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
6023 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
6024 - obj->unlinkAllowed = 0; /* ... or unlink it */
6025 - obj->deleted = 0;
6026 - obj->unlinked = 0;
6027 - obj->yst_mode = mode;
6028 - obj->myDev = dev;
6029 - obj->hdrChunk = 0; /* Not a valid chunk. */
6030 - }
6031 -
6032 - return obj;
6033 -
6034 -}
6035 -
6036 -static void yaffs_UnhashObject(yaffs_Object *tn)
6037 -{
6038 - int bucket;
6039 - yaffs_Device *dev = tn->myDev;
6040 -
6041 - /* If it is still linked into the bucket list, free from the list */
6042 - if (!ylist_empty(&tn->hashLink)) {
6043 - ylist_del_init(&tn->hashLink);
6044 - bucket = yaffs_HashFunction(tn->objectId);
6045 - dev->objectBucket[bucket].count--;
6046 - }
6047 -}
6048 -
6049 -/* FreeObject frees up a Object and puts it back on the free list */
6050 -static void yaffs_FreeObject(yaffs_Object *tn)
6051 -{
6052 - yaffs_Device *dev = tn->myDev;
6053 -
6054 -#ifdef __KERNEL__
6055 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
6056 -#endif
6057 -
6058 - if (tn->parent)
6059 - YBUG();
6060 - if (!ylist_empty(&tn->siblings))
6061 - YBUG();
6062 -
6063 -
6064 -#ifdef __KERNEL__
6065 - if (tn->myInode) {
6066 - /* We're still hooked up to a cached inode.
6067 - * Don't delete now, but mark for later deletion
6068 - */
6069 - tn->deferedFree = 1;
6070 - return;
6071 - }
6072 -#endif
6073 -
6074 - yaffs_UnhashObject(tn);
6075 -
6076 -#ifdef VALGRIND_TEST
6077 - YFREE(tn);
6078 -#else
6079 - /* Link into the free list. */
6080 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
6081 - dev->freeObjects = tn;
6082 - dev->nFreeObjects++;
6083 -#endif
6084 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6085 -}
6086 -
6087 -#ifdef __KERNEL__
6088 -
6089 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
6090 -{
6091 - if (obj->deferedFree)
6092 - yaffs_FreeObject(obj);
6093 -}
6094 -
6095 -#endif
6096 -
6097 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
6098 -{
6099 - /* Free the list of allocated Objects */
6100 -
6101 - yaffs_ObjectList *tmp;
6102 -
6103 - while (dev->allocatedObjectList) {
6104 - tmp = dev->allocatedObjectList->next;
6105 - YFREE(dev->allocatedObjectList->objects);
6106 - YFREE(dev->allocatedObjectList);
6107 -
6108 - dev->allocatedObjectList = tmp;
6109 - }
6110 -
6111 - dev->freeObjects = NULL;
6112 - dev->nFreeObjects = 0;
6113 -}
6114 -
6115 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
6116 -{
6117 - int i;
6118 -
6119 - dev->allocatedObjectList = NULL;
6120 - dev->freeObjects = NULL;
6121 - dev->nFreeObjects = 0;
6122 -
6123 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6124 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
6125 - dev->objectBucket[i].count = 0;
6126 - }
6127 -}
6128 -
6129 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
6130 -{
6131 - static int x;
6132 - int i;
6133 - int l = 999;
6134 - int lowest = 999999;
6135 -
6136 - /* First let's see if we can find one that's empty. */
6137 -
6138 - for (i = 0; i < 10 && lowest > 0; i++) {
6139 - x++;
6140 - x %= YAFFS_NOBJECT_BUCKETS;
6141 - if (dev->objectBucket[x].count < lowest) {
6142 - lowest = dev->objectBucket[x].count;
6143 - l = x;
6144 - }
6145 -
6146 - }
6147 -
6148 - /* If we didn't find an empty list, then try
6149 - * looking a bit further for a short one
6150 - */
6151 -
6152 - for (i = 0; i < 10 && lowest > 3; i++) {
6153 - x++;
6154 - x %= YAFFS_NOBJECT_BUCKETS;
6155 - if (dev->objectBucket[x].count < lowest) {
6156 - lowest = dev->objectBucket[x].count;
6157 - l = x;
6158 - }
6159 -
6160 - }
6161 -
6162 - return l;
6163 -}
6164 -
6165 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
6166 -{
6167 - int bucket = yaffs_FindNiceObjectBucket(dev);
6168 -
6169 - /* Now find an object value that has not already been taken
6170 - * by scanning the list.
6171 - */
6172 -
6173 - int found = 0;
6174 - struct ylist_head *i;
6175 -
6176 - __u32 n = (__u32) bucket;
6177 -
6178 - /* yaffs_CheckObjectHashSanity(); */
6179 -
6180 - while (!found) {
6181 - found = 1;
6182 - n += YAFFS_NOBJECT_BUCKETS;
6183 - if (1 || dev->objectBucket[bucket].count > 0) {
6184 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6185 - /* If there is already one in the list */
6186 - if (i && ylist_entry(i, yaffs_Object,
6187 - hashLink)->objectId == n) {
6188 - found = 0;
6189 - }
6190 - }
6191 - }
6192 - }
6193 -
6194 - return n;
6195 -}
6196 -
6197 -static void yaffs_HashObject(yaffs_Object *in)
6198 -{
6199 - int bucket = yaffs_HashFunction(in->objectId);
6200 - yaffs_Device *dev = in->myDev;
6201 -
6202 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
6203 - dev->objectBucket[bucket].count++;
6204 -}
6205 -
6206 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
6207 -{
6208 - int bucket = yaffs_HashFunction(number);
6209 - struct ylist_head *i;
6210 - yaffs_Object *in;
6211 -
6212 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6213 - /* Look if it is in the list */
6214 - if (i) {
6215 - in = ylist_entry(i, yaffs_Object, hashLink);
6216 - if (in->objectId == number) {
6217 -#ifdef __KERNEL__
6218 - /* Don't tell the VFS about this one if it is defered free */
6219 - if (in->deferedFree)
6220 - return NULL;
6221 -#endif
6222 -
6223 - return in;
6224 - }
6225 - }
6226 - }
6227 -
6228 - return NULL;
6229 -}
6230 -
6231 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
6232 - yaffs_ObjectType type)
6233 -{
6234 - yaffs_Object *theObject;
6235 - yaffs_Tnode *tn = NULL;
6236 -
6237 - if (number < 0)
6238 - number = yaffs_CreateNewObjectNumber(dev);
6239 -
6240 - theObject = yaffs_AllocateEmptyObject(dev);
6241 - if (!theObject)
6242 - return NULL;
6243 -
6244 - if (type == YAFFS_OBJECT_TYPE_FILE) {
6245 - tn = yaffs_GetTnode(dev);
6246 - if (!tn) {
6247 - yaffs_FreeObject(theObject);
6248 - return NULL;
6249 - }
6250 - }
6251 -
6252 - if (theObject) {
6253 - theObject->fake = 0;
6254 - theObject->renameAllowed = 1;
6255 - theObject->unlinkAllowed = 1;
6256 - theObject->objectId = number;
6257 - yaffs_HashObject(theObject);
6258 - theObject->variantType = type;
6259 -#ifdef CONFIG_YAFFS_WINCE
6260 - yfsd_WinFileTimeNow(theObject->win_atime);
6261 - theObject->win_ctime[0] = theObject->win_mtime[0] =
6262 - theObject->win_atime[0];
6263 - theObject->win_ctime[1] = theObject->win_mtime[1] =
6264 - theObject->win_atime[1];
6265 -
6266 -#else
6267 -
6268 - theObject->yst_atime = theObject->yst_mtime =
6269 - theObject->yst_ctime = Y_CURRENT_TIME;
6270 -#endif
6271 - switch (type) {
6272 - case YAFFS_OBJECT_TYPE_FILE:
6273 - theObject->variant.fileVariant.fileSize = 0;
6274 - theObject->variant.fileVariant.scannedFileSize = 0;
6275 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
6276 - theObject->variant.fileVariant.topLevel = 0;
6277 - theObject->variant.fileVariant.top = tn;
6278 - break;
6279 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6280 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
6281 - children);
6282 - break;
6283 - case YAFFS_OBJECT_TYPE_SYMLINK:
6284 - case YAFFS_OBJECT_TYPE_HARDLINK:
6285 - case YAFFS_OBJECT_TYPE_SPECIAL:
6286 - /* No action required */
6287 - break;
6288 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6289 - /* todo this should not happen */
6290 - break;
6291 - }
6292 - }
6293 -
6294 - return theObject;
6295 -}
6296 -
6297 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
6298 - int number,
6299 - yaffs_ObjectType type)
6300 -{
6301 - yaffs_Object *theObject = NULL;
6302 -
6303 - if (number > 0)
6304 - theObject = yaffs_FindObjectByNumber(dev, number);
6305 -
6306 - if (!theObject)
6307 - theObject = yaffs_CreateNewObject(dev, number, type);
6308 -
6309 - return theObject;
6310 -
6311 -}
6312 -
6313 -
6314 -static YCHAR *yaffs_CloneString(const YCHAR *str)
6315 -{
6316 - YCHAR *newStr = NULL;
6317 -
6318 - if (str && *str) {
6319 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
6320 - if (newStr)
6321 - yaffs_strcpy(newStr, str);
6322 - }
6323 -
6324 - return newStr;
6325 -
6326 -}
6327 -
6328 -/*
6329 - * Mknod (create) a new object.
6330 - * equivalentObject only has meaning for a hard link;
6331 - * aliasString only has meaning for a sumlink.
6332 - * rdev only has meaning for devices (a subset of special objects)
6333 - */
6334 -
6335 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
6336 - yaffs_Object *parent,
6337 - const YCHAR *name,
6338 - __u32 mode,
6339 - __u32 uid,
6340 - __u32 gid,
6341 - yaffs_Object *equivalentObject,
6342 - const YCHAR *aliasString, __u32 rdev)
6343 -{
6344 - yaffs_Object *in;
6345 - YCHAR *str = NULL;
6346 -
6347 - yaffs_Device *dev = parent->myDev;
6348 -
6349 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
6350 - if (yaffs_FindObjectByName(parent, name))
6351 - return NULL;
6352 -
6353 - in = yaffs_CreateNewObject(dev, -1, type);
6354 -
6355 - if (!in)
6356 - return YAFFS_FAIL;
6357 -
6358 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
6359 - str = yaffs_CloneString(aliasString);
6360 - if (!str) {
6361 - yaffs_FreeObject(in);
6362 - return NULL;
6363 - }
6364 - }
6365 -
6366 -
6367 -
6368 - if (in) {
6369 - in->hdrChunk = 0;
6370 - in->valid = 1;
6371 - in->variantType = type;
6372 -
6373 - in->yst_mode = mode;
6374 -
6375 -#ifdef CONFIG_YAFFS_WINCE
6376 - yfsd_WinFileTimeNow(in->win_atime);
6377 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
6378 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
6379 -
6380 -#else
6381 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
6382 -
6383 - in->yst_rdev = rdev;
6384 - in->yst_uid = uid;
6385 - in->yst_gid = gid;
6386 -#endif
6387 - in->nDataChunks = 0;
6388 -
6389 - yaffs_SetObjectName(in, name);
6390 - in->dirty = 1;
6391 -
6392 - yaffs_AddObjectToDirectory(parent, in);
6393 -
6394 - in->myDev = parent->myDev;
6395 -
6396 - switch (type) {
6397 - case YAFFS_OBJECT_TYPE_SYMLINK:
6398 - in->variant.symLinkVariant.alias = str;
6399 - break;
6400 - case YAFFS_OBJECT_TYPE_HARDLINK:
6401 - in->variant.hardLinkVariant.equivalentObject =
6402 - equivalentObject;
6403 - in->variant.hardLinkVariant.equivalentObjectId =
6404 - equivalentObject->objectId;
6405 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
6406 - break;
6407 - case YAFFS_OBJECT_TYPE_FILE:
6408 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6409 - case YAFFS_OBJECT_TYPE_SPECIAL:
6410 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6411 - /* do nothing */
6412 - break;
6413 - }
6414 -
6415 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
6416 - /* Could not create the object header, fail the creation */
6417 - yaffs_DeleteObject(in);
6418 - in = NULL;
6419 - }
6420 -
6421 - }
6422 -
6423 - return in;
6424 -}
6425 -
6426 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
6427 - __u32 mode, __u32 uid, __u32 gid)
6428 -{
6429 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
6430 - uid, gid, NULL, NULL, 0);
6431 -}
6432 -
6433 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
6434 - __u32 mode, __u32 uid, __u32 gid)
6435 -{
6436 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
6437 - mode, uid, gid, NULL, NULL, 0);
6438 -}
6439 -
6440 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
6441 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
6442 -{
6443 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
6444 - uid, gid, NULL, NULL, rdev);
6445 -}
6446 -
6447 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
6448 - __u32 mode, __u32 uid, __u32 gid,
6449 - const YCHAR *alias)
6450 -{
6451 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
6452 - uid, gid, NULL, alias, 0);
6453 -}
6454 -
6455 -/* yaffs_Link returns the object id of the equivalent object.*/
6456 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
6457 - yaffs_Object *equivalentObject)
6458 -{
6459 - /* Get the real object in case we were fed a hard link as an equivalent object */
6460 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
6461 -
6462 - if (yaffs_MknodObject
6463 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
6464 - equivalentObject, NULL, 0)) {
6465 - return equivalentObject;
6466 - } else {
6467 - return NULL;
6468 - }
6469 -
6470 -}
6471 -
6472 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
6473 - const YCHAR *newName, int force, int shadows)
6474 -{
6475 - int unlinkOp;
6476 - int deleteOp;
6477 -
6478 - yaffs_Object *existingTarget;
6479 -
6480 - if (newDir == NULL)
6481 - newDir = obj->parent; /* use the old directory */
6482 -
6483 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6484 - T(YAFFS_TRACE_ALWAYS,
6485 - (TSTR
6486 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
6487 - TENDSTR)));
6488 - YBUG();
6489 - }
6490 -
6491 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
6492 - if (obj->myDev->isYaffs2)
6493 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
6494 - else
6495 - unlinkOp = (newDir == obj->myDev->unlinkedDir
6496 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
6497 -
6498 - deleteOp = (newDir == obj->myDev->deletedDir);
6499 -
6500 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6501 -
6502 - /* If the object is a file going into the unlinked directory,
6503 - * then it is OK to just stuff it in since duplicate names are allowed.
6504 - * else only proceed if the new name does not exist and if we're putting
6505 - * it into a directory.
6506 - */
6507 - if ((unlinkOp ||
6508 - deleteOp ||
6509 - force ||
6510 - (shadows > 0) ||
6511 - !existingTarget) &&
6512 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
6513 - yaffs_SetObjectName(obj, newName);
6514 - obj->dirty = 1;
6515 -
6516 - yaffs_AddObjectToDirectory(newDir, obj);
6517 -
6518 - if (unlinkOp)
6519 - obj->unlinked = 1;
6520 -
6521 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
6522 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
6523 - return YAFFS_OK;
6524 - }
6525 -
6526 - return YAFFS_FAIL;
6527 -}
6528 -
6529 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
6530 - yaffs_Object *newDir, const YCHAR *newName)
6531 -{
6532 - yaffs_Object *obj = NULL;
6533 - yaffs_Object *existingTarget = NULL;
6534 - int force = 0;
6535 -
6536 -
6537 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6538 - YBUG();
6539 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6540 - YBUG();
6541 -
6542 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6543 - /* Special case for case insemsitive systems (eg. WinCE).
6544 - * While look-up is case insensitive, the name isn't.
6545 - * Therefore we might want to change x.txt to X.txt
6546 - */
6547 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
6548 - force = 1;
6549 -#endif
6550 -
6551 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
6552 - /* ENAMETOOLONG */
6553 - return YAFFS_FAIL;
6554 -
6555 - obj = yaffs_FindObjectByName(oldDir, oldName);
6556 -
6557 - if (obj && obj->renameAllowed) {
6558 -
6559 - /* Now do the handling for an existing target, if there is one */
6560 -
6561 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6562 - if (existingTarget &&
6563 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
6564 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
6565 - /* There is a target that is a non-empty directory, so we fail */
6566 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
6567 - } else if (existingTarget && existingTarget != obj) {
6568 - /* Nuke the target first, using shadowing,
6569 - * but only if it isn't the same object
6570 - */
6571 - yaffs_ChangeObjectName(obj, newDir, newName, force,
6572 - existingTarget->objectId);
6573 - yaffs_UnlinkObject(existingTarget);
6574 - }
6575 -
6576 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
6577 - }
6578 - return YAFFS_FAIL;
6579 -}
6580 -
6581 -/*------------------------- Block Management and Page Allocation ----------------*/
6582 -
6583 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
6584 -{
6585 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6586 -
6587 - dev->blockInfo = NULL;
6588 - dev->chunkBits = NULL;
6589 -
6590 - dev->allocationBlock = -1; /* force it to get a new one */
6591 -
6592 - /* If the first allocation strategy fails, thry the alternate one */
6593 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
6594 - if (!dev->blockInfo) {
6595 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
6596 - dev->blockInfoAlt = 1;
6597 - } else
6598 - dev->blockInfoAlt = 0;
6599 -
6600 - if (dev->blockInfo) {
6601 - /* Set up dynamic blockinfo stuff. */
6602 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
6603 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
6604 - if (!dev->chunkBits) {
6605 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
6606 - dev->chunkBitsAlt = 1;
6607 - } else
6608 - dev->chunkBitsAlt = 0;
6609 - }
6610 -
6611 - if (dev->blockInfo && dev->chunkBits) {
6612 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
6613 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
6614 - return YAFFS_OK;
6615 - }
6616 -
6617 - return YAFFS_FAIL;
6618 -}
6619 -
6620 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
6621 -{
6622 - if (dev->blockInfoAlt && dev->blockInfo)
6623 - YFREE_ALT(dev->blockInfo);
6624 - else if (dev->blockInfo)
6625 - YFREE(dev->blockInfo);
6626 -
6627 - dev->blockInfoAlt = 0;
6628 -
6629 - dev->blockInfo = NULL;
6630 -
6631 - if (dev->chunkBitsAlt && dev->chunkBits)
6632 - YFREE_ALT(dev->chunkBits);
6633 - else if (dev->chunkBits)
6634 - YFREE(dev->chunkBits);
6635 - dev->chunkBitsAlt = 0;
6636 - dev->chunkBits = NULL;
6637 -}
6638 -
6639 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
6640 - yaffs_BlockInfo *bi)
6641 -{
6642 - int i;
6643 - __u32 seq;
6644 - yaffs_BlockInfo *b;
6645 -
6646 - if (!dev->isYaffs2)
6647 - return 1; /* disqualification only applies to yaffs2. */
6648 -
6649 - if (!bi->hasShrinkHeader)
6650 - return 1; /* can gc */
6651 -
6652 - /* Find the oldest dirty sequence number if we don't know it and save it
6653 - * so we don't have to keep recomputing it.
6654 - */
6655 - if (!dev->oldestDirtySequence) {
6656 - seq = dev->sequenceNumber;
6657 -
6658 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
6659 - i++) {
6660 - b = yaffs_GetBlockInfo(dev, i);
6661 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
6662 - (b->pagesInUse - b->softDeletions) <
6663 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
6664 - seq = b->sequenceNumber;
6665 - }
6666 - }
6667 - dev->oldestDirtySequence = seq;
6668 - }
6669 -
6670 - /* Can't do gc of this block if there are any blocks older than this one that have
6671 - * discarded pages.
6672 - */
6673 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
6674 -}
6675 -
6676 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
6677 - * for garbage collection.
6678 - */
6679 -
6680 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
6681 - int aggressive)
6682 -{
6683 - int b = dev->currentDirtyChecker;
6684 -
6685 - int i;
6686 - int iterations;
6687 - int dirtiest = -1;
6688 - int pagesInUse = 0;
6689 - int prioritised = 0;
6690 - yaffs_BlockInfo *bi;
6691 - int pendingPrioritisedExist = 0;
6692 -
6693 - /* First let's see if we need to grab a prioritised block */
6694 - if (dev->hasPendingPrioritisedGCs) {
6695 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
6696 -
6697 - bi = yaffs_GetBlockInfo(dev, i);
6698 - /* yaffs_VerifyBlock(dev,bi,i); */
6699 -
6700 - if (bi->gcPrioritise) {
6701 - pendingPrioritisedExist = 1;
6702 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6703 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6704 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6705 - dirtiest = i;
6706 - prioritised = 1;
6707 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
6708 - }
6709 - }
6710 - }
6711 -
6712 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
6713 - dev->hasPendingPrioritisedGCs = 0;
6714 - }
6715 -
6716 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
6717 - * search harder.
6718 - * else (we're doing a leasurely gc), then we only bother to do this if the
6719 - * block has only a few pages in use.
6720 - */
6721 -
6722 - dev->nonAggressiveSkip--;
6723 -
6724 - if (!aggressive && (dev->nonAggressiveSkip > 0))
6725 - return -1;
6726 -
6727 - if (!prioritised)
6728 - pagesInUse =
6729 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
6730 -
6731 - if (aggressive)
6732 - iterations =
6733 - dev->internalEndBlock - dev->internalStartBlock + 1;
6734 - else {
6735 - iterations =
6736 - dev->internalEndBlock - dev->internalStartBlock + 1;
6737 - iterations = iterations / 16;
6738 - if (iterations > 200)
6739 - iterations = 200;
6740 - }
6741 -
6742 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
6743 - b++;
6744 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
6745 - b = dev->internalStartBlock;
6746 -
6747 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
6748 - T(YAFFS_TRACE_ERROR,
6749 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
6750 - YBUG();
6751 - }
6752 -
6753 - bi = yaffs_GetBlockInfo(dev, b);
6754 -
6755 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6756 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
6757 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6758 - dirtiest = b;
6759 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6760 - }
6761 - }
6762 -
6763 - dev->currentDirtyChecker = b;
6764 -
6765 - if (dirtiest > 0) {
6766 - T(YAFFS_TRACE_GC,
6767 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
6768 - dev->nChunksPerBlock - pagesInUse, prioritised));
6769 - }
6770 -
6771 - dev->oldestDirtySequence = 0;
6772 -
6773 - if (dirtiest > 0)
6774 - dev->nonAggressiveSkip = 4;
6775 -
6776 - return dirtiest;
6777 -}
6778 -
6779 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
6780 -{
6781 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
6782 -
6783 - int erasedOk = 0;
6784 -
6785 - /* If the block is still healthy erase it and mark as clean.
6786 - * If the block has had a data failure, then retire it.
6787 - */
6788 -
6789 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
6790 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
6791 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
6792 -
6793 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
6794 -
6795 - if (!bi->needsRetiring) {
6796 - yaffs_InvalidateCheckpoint(dev);
6797 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
6798 - if (!erasedOk) {
6799 - dev->nErasureFailures++;
6800 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6801 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
6802 - }
6803 - }
6804 -
6805 - if (erasedOk &&
6806 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
6807 - int i;
6808 - for (i = 0; i < dev->nChunksPerBlock; i++) {
6809 - if (!yaffs_CheckChunkErased
6810 - (dev, blockNo * dev->nChunksPerBlock + i)) {
6811 - T(YAFFS_TRACE_ERROR,
6812 - (TSTR
6813 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
6814 - TENDSTR), blockNo, i));
6815 - }
6816 - }
6817 - }
6818 -
6819 - if (erasedOk) {
6820 - /* Clean it up... */
6821 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
6822 - dev->nErasedBlocks++;
6823 - bi->pagesInUse = 0;
6824 - bi->softDeletions = 0;
6825 - bi->hasShrinkHeader = 0;
6826 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
6827 - bi->gcPrioritise = 0;
6828 - yaffs_ClearChunkBits(dev, blockNo);
6829 -
6830 - T(YAFFS_TRACE_ERASE,
6831 - (TSTR("Erased block %d" TENDSTR), blockNo));
6832 - } else {
6833 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
6834 -
6835 - yaffs_RetireBlock(dev, blockNo);
6836 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6837 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
6838 - }
6839 -}
6840 -
6841 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
6842 -{
6843 - int i;
6844 -
6845 - yaffs_BlockInfo *bi;
6846 -
6847 - if (dev->nErasedBlocks < 1) {
6848 - /* Hoosterman we've got a problem.
6849 - * Can't get space to gc
6850 - */
6851 - T(YAFFS_TRACE_ERROR,
6852 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
6853 -
6854 - return -1;
6855 - }
6856 -
6857 - /* Find an empty block. */
6858 -
6859 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
6860 - dev->allocationBlockFinder++;
6861 - if (dev->allocationBlockFinder < dev->internalStartBlock
6862 - || dev->allocationBlockFinder > dev->internalEndBlock) {
6863 - dev->allocationBlockFinder = dev->internalStartBlock;
6864 - }
6865 -
6866 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
6867 -
6868 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
6869 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
6870 - dev->sequenceNumber++;
6871 - bi->sequenceNumber = dev->sequenceNumber;
6872 - dev->nErasedBlocks--;
6873 - T(YAFFS_TRACE_ALLOCATE,
6874 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
6875 - dev->allocationBlockFinder, dev->sequenceNumber,
6876 - dev->nErasedBlocks));
6877 - return dev->allocationBlockFinder;
6878 - }
6879 - }
6880 -
6881 - T(YAFFS_TRACE_ALWAYS,
6882 - (TSTR
6883 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
6884 - TENDSTR), dev->nErasedBlocks));
6885 -
6886 - return -1;
6887 -}
6888 -
6889 -
6890 -
6891 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
6892 -{
6893 - if (!dev->nCheckpointBlocksRequired &&
6894 - dev->isYaffs2) {
6895 - /* Not a valid value so recalculate */
6896 - int nBytes = 0;
6897 - int nBlocks;
6898 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
6899 - int tnodeSize;
6900 -
6901 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6902 -
6903 - if (tnodeSize < sizeof(yaffs_Tnode))
6904 - tnodeSize = sizeof(yaffs_Tnode);
6905 -
6906 - nBytes += sizeof(yaffs_CheckpointValidity);
6907 - nBytes += sizeof(yaffs_CheckpointDevice);
6908 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
6909 - nBytes += devBlocks * dev->chunkBitmapStride;
6910 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
6911 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
6912 - nBytes += sizeof(yaffs_CheckpointValidity);
6913 - nBytes += sizeof(__u32); /* checksum*/
6914 -
6915 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
6916 -
6917 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
6918 -
6919 - dev->nCheckpointBlocksRequired = nBlocks;
6920 - }
6921 -
6922 - return dev->nCheckpointBlocksRequired;
6923 -}
6924 -
6925 -/*
6926 - * Check if there's space to allocate...
6927 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
6928 - */
6929 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
6930 -{
6931 - int reservedChunks;
6932 - int reservedBlocks = dev->nReservedBlocks;
6933 - int checkpointBlocks;
6934 -
6935 - if (dev->isYaffs2) {
6936 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
6937 - dev->blocksInCheckpoint;
6938 - if (checkpointBlocks < 0)
6939 - checkpointBlocks = 0;
6940 - } else {
6941 - checkpointBlocks = 0;
6942 - }
6943 -
6944 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
6945 -
6946 - return (dev->nFreeChunks > reservedChunks);
6947 -}
6948 -
6949 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
6950 - yaffs_BlockInfo **blockUsedPtr)
6951 -{
6952 - int retVal;
6953 - yaffs_BlockInfo *bi;
6954 -
6955 - if (dev->allocationBlock < 0) {
6956 - /* Get next block to allocate off */
6957 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
6958 - dev->allocationPage = 0;
6959 - }
6960 -
6961 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
6962 - /* Not enough space to allocate unless we're allowed to use the reserve. */
6963 - return -1;
6964 - }
6965 -
6966 - if (dev->nErasedBlocks < dev->nReservedBlocks
6967 - && dev->allocationPage == 0) {
6968 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
6969 - }
6970 -
6971 - /* Next page please.... */
6972 - if (dev->allocationBlock >= 0) {
6973 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
6974 -
6975 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
6976 - dev->allocationPage;
6977 - bi->pagesInUse++;
6978 - yaffs_SetChunkBit(dev, dev->allocationBlock,
6979 - dev->allocationPage);
6980 -
6981 - dev->allocationPage++;
6982 -
6983 - dev->nFreeChunks--;
6984 -
6985 - /* If the block is full set the state to full */
6986 - if (dev->allocationPage >= dev->nChunksPerBlock) {
6987 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
6988 - dev->allocationBlock = -1;
6989 - }
6990 -
6991 - if (blockUsedPtr)
6992 - *blockUsedPtr = bi;
6993 -
6994 - return retVal;
6995 - }
6996 -
6997 - T(YAFFS_TRACE_ERROR,
6998 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
6999 -
7000 - return -1;
7001 -}
7002 -
7003 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
7004 -{
7005 - int n;
7006 -
7007 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
7008 -
7009 - if (dev->allocationBlock > 0)
7010 - n += (dev->nChunksPerBlock - dev->allocationPage);
7011 -
7012 - return n;
7013 -
7014 -}
7015 -
7016 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
7017 - int wholeBlock)
7018 -{
7019 - int oldChunk;
7020 - int newChunk;
7021 - int markNAND;
7022 - int retVal = YAFFS_OK;
7023 - int cleanups = 0;
7024 - int i;
7025 - int isCheckpointBlock;
7026 - int matchingChunk;
7027 - int maxCopies;
7028 -
7029 - int chunksBefore = yaffs_GetErasedChunks(dev);
7030 - int chunksAfter;
7031 -
7032 - yaffs_ExtendedTags tags;
7033 -
7034 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
7035 -
7036 - yaffs_Object *object;
7037 -
7038 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
7039 -
7040 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
7041 -
7042 - T(YAFFS_TRACE_TRACING,
7043 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
7044 - block,
7045 - bi->pagesInUse,
7046 - bi->hasShrinkHeader,
7047 - wholeBlock));
7048 -
7049 - /*yaffs_VerifyFreeChunks(dev); */
7050 -
7051 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
7052 -
7053 - /* Take off the number of soft deleted entries because
7054 - * they're going to get really deleted during GC.
7055 - */
7056 - dev->nFreeChunks -= bi->softDeletions;
7057 -
7058 - dev->isDoingGC = 1;
7059 -
7060 - if (isCheckpointBlock ||
7061 - !yaffs_StillSomeChunkBits(dev, block)) {
7062 - T(YAFFS_TRACE_TRACING,
7063 - (TSTR
7064 - ("Collecting block %d that has no chunks in use" TENDSTR),
7065 - block));
7066 - yaffs_BlockBecameDirty(dev, block);
7067 - } else {
7068 -
7069 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
7070 -
7071 - yaffs_VerifyBlock(dev, bi, block);
7072 -
7073 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
7074 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
7075 -
7076 - for (/* init already done */;
7077 - retVal == YAFFS_OK &&
7078 - dev->gcChunk < dev->nChunksPerBlock &&
7079 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
7080 - maxCopies > 0;
7081 - dev->gcChunk++, oldChunk++) {
7082 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
7083 -
7084 - /* This page is in use and might need to be copied off */
7085 -
7086 - maxCopies--;
7087 -
7088 - markNAND = 1;
7089 -
7090 - yaffs_InitialiseTags(&tags);
7091 -
7092 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
7093 - buffer, &tags);
7094 -
7095 - object =
7096 - yaffs_FindObjectByNumber(dev,
7097 - tags.objectId);
7098 -
7099 - T(YAFFS_TRACE_GC_DETAIL,
7100 - (TSTR
7101 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
7102 - dev->gcChunk, tags.objectId, tags.chunkId,
7103 - tags.byteCount));
7104 -
7105 - if (object && !yaffs_SkipVerification(dev)) {
7106 - if (tags.chunkId == 0)
7107 - matchingChunk = object->hdrChunk;
7108 - else if (object->softDeleted)
7109 - matchingChunk = oldChunk; /* Defeat the test */
7110 - else
7111 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
7112 -
7113 - if (oldChunk != matchingChunk)
7114 - T(YAFFS_TRACE_ERROR,
7115 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
7116 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
7117 -
7118 - }
7119 -
7120 - if (!object) {
7121 - T(YAFFS_TRACE_ERROR,
7122 - (TSTR
7123 - ("page %d in gc has no object: %d %d %d "
7124 - TENDSTR), oldChunk,
7125 - tags.objectId, tags.chunkId, tags.byteCount));
7126 - }
7127 -
7128 - if (object &&
7129 - object->deleted &&
7130 - object->softDeleted &&
7131 - tags.chunkId != 0) {
7132 - /* Data chunk in a soft deleted file, throw it away
7133 - * It's a soft deleted data chunk,
7134 - * No need to copy this, just forget about it and
7135 - * fix up the object.
7136 - */
7137 -
7138 - object->nDataChunks--;
7139 -
7140 - if (object->nDataChunks <= 0) {
7141 - /* remeber to clean up the object */
7142 - dev->gcCleanupList[cleanups] =
7143 - tags.objectId;
7144 - cleanups++;
7145 - }
7146 - markNAND = 0;
7147 - } else if (0) {
7148 - /* Todo object && object->deleted && object->nDataChunks == 0 */
7149 - /* Deleted object header with no data chunks.
7150 - * Can be discarded and the file deleted.
7151 - */
7152 - object->hdrChunk = 0;
7153 - yaffs_FreeTnode(object->myDev,
7154 - object->variant.
7155 - fileVariant.top);
7156 - object->variant.fileVariant.top = NULL;
7157 - yaffs_DoGenericObjectDeletion(object);
7158 -
7159 - } else if (object) {
7160 - /* It's either a data chunk in a live file or
7161 - * an ObjectHeader, so we're interested in it.
7162 - * NB Need to keep the ObjectHeaders of deleted files
7163 - * until the whole file has been deleted off
7164 - */
7165 - tags.serialNumber++;
7166 -
7167 - dev->nGCCopies++;
7168 -
7169 - if (tags.chunkId == 0) {
7170 - /* It is an object Id,
7171 - * We need to nuke the shrinkheader flags first
7172 - * We no longer want the shrinkHeader flag since its work is done
7173 - * and if it is left in place it will mess up scanning.
7174 - */
7175 -
7176 - yaffs_ObjectHeader *oh;
7177 - oh = (yaffs_ObjectHeader *)buffer;
7178 - oh->isShrink = 0;
7179 - tags.extraIsShrinkHeader = 0;
7180 -
7181 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
7182 - }
7183 -
7184 - newChunk =
7185 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
7186 -
7187 - if (newChunk < 0) {
7188 - retVal = YAFFS_FAIL;
7189 - } else {
7190 -
7191 - /* Ok, now fix up the Tnodes etc. */
7192 -
7193 - if (tags.chunkId == 0) {
7194 - /* It's a header */
7195 - object->hdrChunk = newChunk;
7196 - object->serial = tags.serialNumber;
7197 - } else {
7198 - /* It's a data chunk */
7199 - yaffs_PutChunkIntoFile
7200 - (object,
7201 - tags.chunkId,
7202 - newChunk, 0);
7203 - }
7204 - }
7205 - }
7206 -
7207 - if (retVal == YAFFS_OK)
7208 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
7209 -
7210 - }
7211 - }
7212 -
7213 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
7214 -
7215 -
7216 - /* Do any required cleanups */
7217 - for (i = 0; i < cleanups; i++) {
7218 - /* Time to delete the file too */
7219 - object =
7220 - yaffs_FindObjectByNumber(dev,
7221 - dev->gcCleanupList[i]);
7222 - if (object) {
7223 - yaffs_FreeTnode(dev,
7224 - object->variant.fileVariant.
7225 - top);
7226 - object->variant.fileVariant.top = NULL;
7227 - T(YAFFS_TRACE_GC,
7228 - (TSTR
7229 - ("yaffs: About to finally delete object %d"
7230 - TENDSTR), object->objectId));
7231 - yaffs_DoGenericObjectDeletion(object);
7232 - object->myDev->nDeletedFiles--;
7233 - }
7234 -
7235 - }
7236 -
7237 - }
7238 -
7239 - yaffs_VerifyCollectedBlock(dev, bi, block);
7240 + if (chunkId > YAFFS_MAX_CHUNK_ID)
7241 + return NULL;
7242
7243 - chunksAfter = yaffs_GetErasedChunks(dev);
7244 - if (chunksBefore >= chunksAfter) {
7245 - T(YAFFS_TRACE_GC,
7246 - (TSTR
7247 - ("gc did not increase free chunks before %d after %d"
7248 - TENDSTR), chunksBefore, chunksAfter));
7249 - }
7250 + /* First check we're tall enough (ie enough topLevel) */
7251
7252 - /* If the gc completed then clear the current gcBlock so that we find another. */
7253 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
7254 - dev->gcBlock = -1;
7255 - dev->gcChunk = 0;
7256 + x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
7257 + requiredTallness = 0;
7258 + while (x) {
7259 + x >>= YAFFS_TNODES_INTERNAL_BITS;
7260 + requiredTallness++;
7261 }
7262
7263 - dev->isDoingGC = 0;
7264 -
7265 - return retVal;
7266 -}
7267
7268 -/* New garbage collector
7269 - * If we're very low on erased blocks then we do aggressive garbage collection
7270 - * otherwise we do "leasurely" garbage collection.
7271 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
7272 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
7273 - *
7274 - * The idea is to help clear out space in a more spread-out manner.
7275 - * Dunno if it really does anything useful.
7276 - */
7277 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
7278 -{
7279 - int block;
7280 - int aggressive;
7281 - int gcOk = YAFFS_OK;
7282 - int maxTries = 0;
7283 + if (requiredTallness > fStruct->topLevel) {
7284 + /* Not tall enough, gotta make the tree taller */
7285 + for (i = fStruct->topLevel; i < requiredTallness; i++) {
7286
7287 - int checkpointBlockAdjust;
7288 + tn = yaffs_GetTnode(dev);
7289
7290 - if (dev->isDoingGC) {
7291 - /* Bail out so we don't get recursive gc */
7292 - return YAFFS_OK;
7293 + if (tn) {
7294 + tn->internal[0] = fStruct->top;
7295 + fStruct->top = tn;
7296 + fStruct->topLevel++;
7297 + } else {
7298 + T(YAFFS_TRACE_ERROR,
7299 + (TSTR("yaffs: no more tnodes" TENDSTR)));
7300 + return NULL;
7301 + }
7302 + }
7303 }
7304
7305 - /* This loop should pass the first time.
7306 - * We'll only see looping here if the erase of the collected block fails.
7307 - */
7308 -
7309 - do {
7310 - maxTries++;
7311 -
7312 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
7313 - if (checkpointBlockAdjust < 0)
7314 - checkpointBlockAdjust = 0;
7315 + /* Traverse down to level 0, adding anything we need */
7316
7317 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
7318 - /* We need a block soon...*/
7319 - aggressive = 1;
7320 - } else {
7321 - /* We're in no hurry */
7322 - aggressive = 0;
7323 - }
7324 + l = fStruct->topLevel;
7325 + tn = fStruct->top;
7326
7327 - if (dev->gcBlock <= 0) {
7328 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
7329 - dev->gcChunk = 0;
7330 - }
7331 + if (l > 0) {
7332 + while (l > 0 && tn) {
7333 + x = (chunkId >>
7334 + (YAFFS_TNODES_LEVEL0_BITS +
7335 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
7336 + YAFFS_TNODES_INTERNAL_MASK;
7337
7338 - block = dev->gcBlock;
7339
7340 - if (block > 0) {
7341 - dev->garbageCollections++;
7342 - if (!aggressive)
7343 - dev->passiveGarbageCollections++;
7344 + if ((l > 1) && !tn->internal[x]) {
7345 + /* Add missing non-level-zero tnode */
7346 + tn->internal[x] = yaffs_GetTnode(dev);
7347 + if(!tn->internal[x])
7348 + return NULL;
7349 + } else if (l == 1) {
7350 + /* Looking from level 1 at level 0 */
7351 + if (passedTn) {
7352 + /* If we already have one, then release it.*/
7353 + if (tn->internal[x])
7354 + yaffs_FreeTnode(dev, tn->internal[x]);
7355 + tn->internal[x] = passedTn;
7356
7357 - T(YAFFS_TRACE_GC,
7358 - (TSTR
7359 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
7360 - dev->nErasedBlocks, aggressive));
7361 + } else if (!tn->internal[x]) {
7362 + /* Don't have one, none passed in */
7363 + tn->internal[x] = yaffs_GetTnode(dev);
7364 + if(!tn->internal[x])
7365 + return NULL;
7366 + }
7367 + }
7368
7369 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
7370 + tn = tn->internal[x];
7371 + l--;
7372 }
7373 -
7374 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
7375 - T(YAFFS_TRACE_GC,
7376 - (TSTR
7377 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
7378 - TENDSTR), dev->nErasedBlocks, maxTries, block));
7379 + } else {
7380 + /* top is level 0 */
7381 + if (passedTn) {
7382 + memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
7383 + yaffs_FreeTnode(dev, passedTn);
7384 }
7385 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
7386 - (block > 0) &&
7387 - (maxTries < 2));
7388 + }
7389
7390 - return aggressive ? gcOk : YAFFS_OK;
7391 + return tn;
7392 }
7393
7394 -/*------------------------- TAGS --------------------------------*/
7395 -
7396 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
7397 - int chunkInObject)
7398 +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
7399 + yaffs_ExtendedTags *tags, int objectId,
7400 + int chunkInInode)
7401 {
7402 - return (tags->chunkId == chunkInObject &&
7403 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
7404 + int j;
7405
7406 + for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
7407 + if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock,
7408 + theChunk % dev->param.nChunksPerBlock)) {
7409 +
7410 + if(dev->chunkGroupSize == 1)
7411 + return theChunk;
7412 + else {
7413 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
7414 + tags);
7415 + if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
7416 + /* found it; */
7417 + return theChunk;
7418 + }
7419 + }
7420 + }
7421 + theChunk++;
7422 + }
7423 + return -1;
7424 }
7425
7426 +#if 0
7427 +/* Experimental code not being used yet. Might speed up file deletion */
7428 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
7429 + * chunks and tnodes in the file.
7430 + * Returns 1 if the tree was deleted.
7431 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
7432 + */
7433
7434 -/*-------------------- Data file manipulation -----------------*/
7435 -
7436 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
7437 - yaffs_ExtendedTags *tags)
7438 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
7439 + int chunkOffset, int *limit)
7440 {
7441 - /*Get the Tnode, then get the level 0 offset chunk offset */
7442 - yaffs_Tnode *tn;
7443 - int theChunk = -1;
7444 - yaffs_ExtendedTags localTags;
7445 - int retVal = -1;
7446 -
7447 + int i;
7448 + int chunkInInode;
7449 + int theChunk;
7450 + yaffs_ExtendedTags tags;
7451 + int foundChunk;
7452 yaffs_Device *dev = in->myDev;
7453
7454 - if (!tags) {
7455 - /* Passed a NULL, so use our own tags space */
7456 - tags = &localTags;
7457 - }
7458 -
7459 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7460 + int allDone = 1;
7461
7462 if (tn) {
7463 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7464 + if (level > 0) {
7465 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7466 + i--) {
7467 + if (tn->internal[i]) {
7468 + if (limit && (*limit) < 0) {
7469 + allDone = 0;
7470 + } else {
7471 + allDone =
7472 + yaffs_DeleteWorker(in,
7473 + tn->
7474 + internal
7475 + [i],
7476 + level -
7477 + 1,
7478 + (chunkOffset
7479 + <<
7480 + YAFFS_TNODES_INTERNAL_BITS)
7481 + + i,
7482 + limit);
7483 + }
7484 + if (allDone) {
7485 + yaffs_FreeTnode(dev,
7486 + tn->
7487 + internal[i]);
7488 + tn->internal[i] = NULL;
7489 + }
7490 + }
7491 + }
7492 + return (allDone) ? 1 : 0;
7493 + } else if (level == 0) {
7494 + int hitLimit = 0;
7495
7496 - retVal =
7497 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7498 - chunkInInode);
7499 - }
7500 - return retVal;
7501 -}
7502 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
7503 + i--) {
7504 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7505 + if (theChunk) {
7506
7507 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
7508 - yaffs_ExtendedTags *tags)
7509 -{
7510 - /* Get the Tnode, then get the level 0 offset chunk offset */
7511 - yaffs_Tnode *tn;
7512 - int theChunk = -1;
7513 - yaffs_ExtendedTags localTags;
7514 + chunkInInode = (chunkOffset <<
7515 + YAFFS_TNODES_LEVEL0_BITS) + i;
7516 +
7517 + foundChunk =
7518 + yaffs_FindChunkInGroup(dev,
7519 + theChunk,
7520 + &tags,
7521 + in->objectId,
7522 + chunkInInode);
7523 +
7524 + if (foundChunk > 0) {
7525 + yaffs_DeleteChunk(dev,
7526 + foundChunk, 1,
7527 + __LINE__);
7528 + in->nDataChunks--;
7529 + if (limit) {
7530 + *limit = *limit - 1;
7531 + if (*limit <= 0)
7532 + hitLimit = 1;
7533 + }
7534
7535 - yaffs_Device *dev = in->myDev;
7536 - int retVal = -1;
7537 + }
7538 +
7539 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7540 + }
7541 +
7542 + }
7543 + return (i < 0) ? 1 : 0;
7544 +
7545 + }
7546
7547 - if (!tags) {
7548 - /* Passed a NULL, so use our own tags space */
7549 - tags = &localTags;
7550 }
7551
7552 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7553 + return 1;
7554
7555 - if (tn) {
7556 +}
7557
7558 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7559 +#endif
7560
7561 - retVal =
7562 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7563 - chunkInInode);
7564 +static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
7565 +{
7566 + yaffs_BlockInfo *theBlock;
7567 + unsigned blockNo;
7568
7569 - /* Delete the entry in the filestructure (if found) */
7570 - if (retVal != -1)
7571 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
7572 - }
7573 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
7574
7575 - return retVal;
7576 + blockNo = chunk / dev->param.nChunksPerBlock;
7577 + theBlock = yaffs_GetBlockInfo(dev, blockNo);
7578 + if (theBlock) {
7579 + theBlock->softDeletions++;
7580 + dev->nFreeChunks++;
7581 + yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock);
7582 + }
7583 }
7584
7585 -#ifdef YAFFS_PARANOID
7586 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
7587 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
7588 + * of the tnode.
7589 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
7590 + */
7591
7592 -static int yaffs_CheckFileSanity(yaffs_Object *in)
7593 +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
7594 + __u32 level, int chunkOffset)
7595 {
7596 - int chunk;
7597 - int nChunks;
7598 - int fSize;
7599 - int failed = 0;
7600 - int objId;
7601 - yaffs_Tnode *tn;
7602 - yaffs_Tags localTags;
7603 - yaffs_Tags *tags = &localTags;
7604 + int i;
7605 int theChunk;
7606 - int chunkDeleted;
7607 + int allDone = 1;
7608 + yaffs_Device *dev = in->myDev;
7609
7610 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
7611 - return YAFFS_FAIL;
7612 + if (tn) {
7613 + if (level > 0) {
7614
7615 - objId = in->objectId;
7616 - fSize = in->variant.fileVariant.fileSize;
7617 - nChunks =
7618 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
7619 -
7620 - for (chunk = 1; chunk <= nChunks; chunk++) {
7621 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
7622 - chunk);
7623 -
7624 - if (tn) {
7625 -
7626 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
7627 -
7628 - if (yaffs_CheckChunkBits
7629 - (dev, theChunk / dev->nChunksPerBlock,
7630 - theChunk % dev->nChunksPerBlock)) {
7631 -
7632 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
7633 - tags,
7634 - &chunkDeleted);
7635 - if (yaffs_TagsMatch
7636 - (tags, in->objectId, chunk, chunkDeleted)) {
7637 - /* found it; */
7638 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7639 + i--) {
7640 + if (tn->internal[i]) {
7641 + allDone =
7642 + yaffs_SoftDeleteWorker(in,
7643 + tn->
7644 + internal[i],
7645 + level - 1,
7646 + (chunkOffset
7647 + <<
7648 + YAFFS_TNODES_INTERNAL_BITS)
7649 + + i);
7650 + if (allDone) {
7651 + yaffs_FreeTnode(dev,
7652 + tn->
7653 + internal[i]);
7654 + tn->internal[i] = NULL;
7655 + } else {
7656 + /* Hoosterman... how could this happen? */
7657 + }
7658 + }
7659 + }
7660 + return (allDone) ? 1 : 0;
7661 + } else if (level == 0) {
7662
7663 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
7664 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7665 + if (theChunk) {
7666 + /* Note this does not find the real chunk, only the chunk group.
7667 + * We make an assumption that a chunk group is not larger than
7668 + * a block.
7669 + */
7670 + yaffs_SoftDeleteChunk(dev, theChunk);
7671 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7672 }
7673 - } else {
7674
7675 - failed = 1;
7676 }
7677 + return 1;
7678
7679 - } else {
7680 - /* T(("No level 0 found for %d\n", chunk)); */
7681 }
7682 +
7683 }
7684
7685 - return failed ? YAFFS_FAIL : YAFFS_OK;
7686 + return 1;
7687 +
7688 }
7689
7690 -#endif
7691 +static void yaffs_SoftDeleteFile(yaffs_Object *obj)
7692 +{
7693 + if (obj->deleted &&
7694 + obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
7695 + if (obj->nDataChunks <= 0) {
7696 + /* Empty file with no duplicate object headers, just delete it immediately */
7697 + yaffs_FreeTnode(obj->myDev,
7698 + obj->variant.fileVariant.top);
7699 + obj->variant.fileVariant.top = NULL;
7700 + T(YAFFS_TRACE_TRACING,
7701 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
7702 + obj->objectId));
7703 + yaffs_DoGenericObjectDeletion(obj);
7704 + } else {
7705 + yaffs_SoftDeleteWorker(obj,
7706 + obj->variant.fileVariant.top,
7707 + obj->variant.fileVariant.
7708 + topLevel, 0);
7709 + obj->softDeleted = 1;
7710 + }
7711 + }
7712 +}
7713
7714 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
7715 - int chunkInNAND, int inScan)
7716 +/* Pruning removes any part of the file structure tree that is beyond the
7717 + * bounds of the file (ie that does not point to chunks).
7718 + *
7719 + * A file should only get pruned when its size is reduced.
7720 + *
7721 + * Before pruning, the chunks must be pulled from the tree and the
7722 + * level 0 tnode entries must be zeroed out.
7723 + * Could also use this for file deletion, but that's probably better handled
7724 + * by a special case.
7725 + *
7726 + * This function is recursive. For levels > 0 the function is called again on
7727 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
7728 + * If there is no data in a subtree then it is pruned.
7729 + */
7730 +
7731 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7732 + __u32 level, int del0)
7733 {
7734 - /* NB inScan is zero unless scanning.
7735 - * For forward scanning, inScan is > 0;
7736 - * for backward scanning inScan is < 0
7737 - */
7738 + int i;
7739 + int hasData;
7740
7741 - yaffs_Tnode *tn;
7742 - yaffs_Device *dev = in->myDev;
7743 - int existingChunk;
7744 - yaffs_ExtendedTags existingTags;
7745 - yaffs_ExtendedTags newTags;
7746 - unsigned existingSerial, newSerial;
7747 + if (tn) {
7748 + hasData = 0;
7749
7750 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
7751 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
7752 - * If it is not during Scanning then something went wrong!
7753 - */
7754 - if (!inScan) {
7755 - T(YAFFS_TRACE_ERROR,
7756 - (TSTR
7757 - ("yaffs tragedy:attempt to put data chunk into a non-file"
7758 - TENDSTR)));
7759 - YBUG();
7760 - }
7761 + if(level > 0){
7762 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7763 + if (tn->internal[i]) {
7764 + tn->internal[i] =
7765 + yaffs_PruneWorker(dev, tn->internal[i],
7766 + level - 1,
7767 + (i == 0) ? del0 : 1);
7768 + }
7769
7770 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
7771 - return YAFFS_OK;
7772 - }
7773 + if (tn->internal[i])
7774 + hasData++;
7775 + }
7776 + } else {
7777 + int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32);
7778 + __u32 *map = (__u32 *)tn;
7779
7780 - tn = yaffs_AddOrFindLevel0Tnode(dev,
7781 - &in->variant.fileVariant,
7782 - chunkInInode,
7783 - NULL);
7784 - if (!tn)
7785 - return YAFFS_FAIL;
7786 + for(i = 0; !hasData && i < tnodeSize_u32; i++){
7787 + if(map[i])
7788 + hasData++;
7789 + }
7790 + }
7791
7792 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7793 + if (hasData == 0 && del0) {
7794 + /* Free and return NULL */
7795
7796 - if (inScan != 0) {
7797 - /* If we're scanning then we need to test for duplicates
7798 - * NB This does not need to be efficient since it should only ever
7799 - * happen when the power fails during a write, then only one
7800 - * chunk should ever be affected.
7801 - *
7802 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
7803 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
7804 - */
7805 + yaffs_FreeTnode(dev, tn);
7806 + tn = NULL;
7807 + }
7808
7809 - if (existingChunk > 0) {
7810 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
7811 - * thus we have to do a FindChunkInFile to get the real chunk id.
7812 - *
7813 - * We have a duplicate now we need to decide which one to use:
7814 - *
7815 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
7816 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
7817 - * YAFFS1: Get both sets of tags and compare serial numbers.
7818 - */
7819 + }
7820
7821 - if (inScan > 0) {
7822 - /* Only do this for forward scanning */
7823 - yaffs_ReadChunkWithTagsFromNAND(dev,
7824 - chunkInNAND,
7825 - NULL, &newTags);
7826 + return tn;
7827
7828 - /* Do a proper find */
7829 - existingChunk =
7830 - yaffs_FindChunkInFile(in, chunkInInode,
7831 - &existingTags);
7832 - }
7833 +}
7834
7835 - if (existingChunk <= 0) {
7836 - /*Hoosterman - how did this happen? */
7837 +static int yaffs_PruneFileStructure(yaffs_Device *dev,
7838 + yaffs_FileStructure *fStruct)
7839 +{
7840 + int i;
7841 + int hasData;
7842 + int done = 0;
7843 + yaffs_Tnode *tn;
7844
7845 - T(YAFFS_TRACE_ERROR,
7846 - (TSTR
7847 - ("yaffs tragedy: existing chunk < 0 in scan"
7848 - TENDSTR)));
7849 + if (fStruct->topLevel > 0) {
7850 + fStruct->top =
7851 + yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7852
7853 - }
7854 + /* Now we have a tree with all the non-zero branches NULL but the height
7855 + * is the same as it was.
7856 + * Let's see if we can trim internal tnodes to shorten the tree.
7857 + * We can do this if only the 0th element in the tnode is in use
7858 + * (ie all the non-zero are NULL)
7859 + */
7860
7861 - /* NB The deleted flags should be false, otherwise the chunks will
7862 - * not be loaded during a scan
7863 - */
7864 + while (fStruct->topLevel && !done) {
7865 + tn = fStruct->top;
7866
7867 - if (inScan > 0) {
7868 - newSerial = newTags.serialNumber;
7869 - existingSerial = existingTags.serialNumber;
7870 + hasData = 0;
7871 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7872 + if (tn->internal[i])
7873 + hasData++;
7874 }
7875 -
7876 - if ((inScan > 0) &&
7877 - (in->myDev->isYaffs2 ||
7878 - existingChunk <= 0 ||
7879 - ((existingSerial + 1) & 3) == newSerial)) {
7880 - /* Forward scanning.
7881 - * Use new
7882 - * Delete the old one and drop through to update the tnode
7883 - */
7884 - yaffs_DeleteChunk(dev, existingChunk, 1,
7885 - __LINE__);
7886 - } else {
7887 - /* Backward scanning or we want to use the existing one
7888 - * Use existing.
7889 - * Delete the new one and return early so that the tnode isn't changed
7890 - */
7891 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
7892 - __LINE__);
7893 - return YAFFS_OK;
7894 +
7895 + if (!hasData) {
7896 + fStruct->top = tn->internal[0];
7897 + fStruct->topLevel--;
7898 + yaffs_FreeTnode(dev, tn);
7899 + } else {
7900 + done = 1;
7901 }
7902 }
7903 -
7904 }
7905
7906 - if (existingChunk == 0)
7907 - in->nDataChunks++;
7908 -
7909 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
7910 -
7911 return YAFFS_OK;
7912 }
7913
7914 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
7915 - __u8 *buffer)
7916 -{
7917 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
7918 -
7919 - if (chunkInNAND >= 0)
7920 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
7921 - buffer, NULL);
7922 - else {
7923 - T(YAFFS_TRACE_NANDACCESS,
7924 - (TSTR("Chunk %d not found zero instead" TENDSTR),
7925 - chunkInNAND));
7926 - /* get sane (zero) data if you read a hole */
7927 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
7928 - return 0;
7929 - }
7930 +/*-------------------- End of File Structure functions.-------------------*/
7931
7932 -}
7933
7934 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
7935 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7936 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7937 {
7938 - int block;
7939 - int page;
7940 - yaffs_ExtendedTags tags;
7941 - yaffs_BlockInfo *bi;
7942 + yaffs_Object *obj = yaffs_AllocateRawObject(dev);
7943
7944 - if (chunkId <= 0)
7945 - return;
7946 + if (obj) {
7947 + dev->nObjects++;
7948
7949 - dev->nDeletions++;
7950 - block = chunkId / dev->nChunksPerBlock;
7951 - page = chunkId % dev->nChunksPerBlock;
7952 + /* Now sweeten it up... */
7953
7954 + memset(obj, 0, sizeof(yaffs_Object));
7955 + obj->beingCreated = 1;
7956
7957 - if (!yaffs_CheckChunkBit(dev, block, page))
7958 - T(YAFFS_TRACE_VERIFY,
7959 - (TSTR("Deleting invalid chunk %d"TENDSTR),
7960 - chunkId));
7961 + obj->myDev = dev;
7962 + obj->hdrChunk = 0;
7963 + obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7964 + YINIT_LIST_HEAD(&(obj->hardLinks));
7965 + YINIT_LIST_HEAD(&(obj->hashLink));
7966 + YINIT_LIST_HEAD(&obj->siblings);
7967
7968 - bi = yaffs_GetBlockInfo(dev, block);
7969
7970 - T(YAFFS_TRACE_DELETION,
7971 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
7972 + /* Now make the directory sane */
7973 + if (dev->rootDir) {
7974 + obj->parent = dev->rootDir;
7975 + ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children);
7976 + }
7977
7978 - if (markNAND &&
7979 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
7980 + /* Add it to the lost and found directory.
7981 + * NB Can't put root or lostNFound in lostNFound so
7982 + * check if lostNFound exists first
7983 + */
7984 + if (dev->lostNFoundDir)
7985 + yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj);
7986
7987 - yaffs_InitialiseTags(&tags);
7988 + obj->beingCreated = 0;
7989 + }
7990
7991 - tags.chunkDeleted = 1;
7992 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7993
7994 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
7995 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
7996 - } else {
7997 - dev->nUnmarkedDeletions++;
7998 - }
7999 + return obj;
8000 +}
8001
8002 - /* Pull out of the management area.
8003 - * If the whole block became dirty, this will kick off an erasure.
8004 - */
8005 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8006 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8007 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8008 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8009 - dev->nFreeChunks++;
8010 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
8011 + __u32 mode)
8012 +{
8013
8014 - yaffs_ClearChunkBit(dev, block, page);
8015 + yaffs_Object *obj =
8016 + yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
8017 + if (obj) {
8018 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
8019 + obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
8020 + obj->unlinkAllowed = 0; /* ... or unlink it */
8021 + obj->deleted = 0;
8022 + obj->unlinked = 0;
8023 + obj->yst_mode = mode;
8024 + obj->myDev = dev;
8025 + obj->hdrChunk = 0; /* Not a valid chunk. */
8026 + }
8027
8028 - bi->pagesInUse--;
8029 + return obj;
8030
8031 - if (bi->pagesInUse == 0 &&
8032 - !bi->hasShrinkHeader &&
8033 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8034 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8035 - yaffs_BlockBecameDirty(dev, block);
8036 - }
8037 +}
8038
8039 - }
8040 +static void yaffs_UnhashObject(yaffs_Object *obj)
8041 +{
8042 + int bucket;
8043 + yaffs_Device *dev = obj->myDev;
8044
8045 + /* If it is still linked into the bucket list, free from the list */
8046 + if (!ylist_empty(&obj->hashLink)) {
8047 + ylist_del_init(&obj->hashLink);
8048 + bucket = yaffs_HashFunction(obj->objectId);
8049 + dev->objectBucket[bucket].count--;
8050 + }
8051 }
8052
8053 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8054 - const __u8 *buffer, int nBytes,
8055 - int useReserve)
8056 +/* FreeObject frees up a Object and puts it back on the free list */
8057 +static void yaffs_FreeObject(yaffs_Object *obj)
8058 {
8059 - /* Find old chunk Need to do this to get serial number
8060 - * Write new one and patch into tree.
8061 - * Invalidate old tags.
8062 - */
8063 + yaffs_Device *dev = obj->myDev;
8064
8065 - int prevChunkId;
8066 - yaffs_ExtendedTags prevTags;
8067 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode));
8068
8069 - int newChunkId;
8070 - yaffs_ExtendedTags newTags;
8071 + if (!obj)
8072 + YBUG();
8073 + if (obj->parent)
8074 + YBUG();
8075 + if (!ylist_empty(&obj->siblings))
8076 + YBUG();
8077
8078 - yaffs_Device *dev = in->myDev;
8079
8080 - yaffs_CheckGarbageCollection(dev);
8081 + if (obj->myInode) {
8082 + /* We're still hooked up to a cached inode.
8083 + * Don't delete now, but mark for later deletion
8084 + */
8085 + obj->deferedFree = 1;
8086 + return;
8087 + }
8088 +
8089 + yaffs_UnhashObject(obj);
8090
8091 - /* Get the previous chunk at this location in the file if it exists */
8092 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8093 + yaffs_FreeRawObject(dev,obj);
8094 + dev->nObjects--;
8095 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
8096 +}
8097
8098 - /* Set up new tags */
8099 - yaffs_InitialiseTags(&newTags);
8100
8101 - newTags.chunkId = chunkInInode;
8102 - newTags.objectId = in->objectId;
8103 - newTags.serialNumber =
8104 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8105 - newTags.byteCount = nBytes;
8106 +void yaffs_HandleDeferedFree(yaffs_Object *obj)
8107 +{
8108 + if (obj->deferedFree)
8109 + yaffs_FreeObject(obj);
8110 +}
8111
8112 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8113 - T(YAFFS_TRACE_ERROR,
8114 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8115 - YBUG();
8116 +static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev)
8117 +{
8118 + int i;
8119 +
8120 + dev->nObjects = 0;
8121 + dev->nTnodes = 0;
8122 +
8123 + yaffs_InitialiseRawTnodesAndObjects(dev);
8124 +
8125 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
8126 + YINIT_LIST_HEAD(&dev->objectBucket[i].list);
8127 + dev->objectBucket[i].count = 0;
8128 }
8129 +}
8130
8131 - newChunkId =
8132 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8133 - useReserve);
8134 +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
8135 +{
8136 + int i;
8137 + int l = 999;
8138 + int lowest = 999999;
8139
8140 - if (newChunkId >= 0) {
8141 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8142
8143 - if (prevChunkId >= 0)
8144 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8145 + /* Search for the shortest list or one that
8146 + * isn't too long.
8147 + */
8148 +
8149 + for (i = 0; i < 10 && lowest > 4; i++) {
8150 + dev->bucketFinder++;
8151 + dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS;
8152 + if (dev->objectBucket[dev->bucketFinder].count < lowest) {
8153 + lowest = dev->objectBucket[dev->bucketFinder].count;
8154 + l = dev->bucketFinder;
8155 + }
8156
8157 - yaffs_CheckFileSanity(in);
8158 }
8159 - return newChunkId;
8160
8161 + return l;
8162 }
8163
8164 -/* UpdateObjectHeader updates the header on NAND for an object.
8165 - * If name is not NULL, then that new name is used.
8166 - */
8167 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8168 - int isShrink, int shadows)
8169 +static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
8170 {
8171 + int bucket = yaffs_FindNiceObjectBucket(dev);
8172
8173 - yaffs_BlockInfo *bi;
8174 + /* Now find an object value that has not already been taken
8175 + * by scanning the list.
8176 + */
8177
8178 - yaffs_Device *dev = in->myDev;
8179 + int found = 0;
8180 + struct ylist_head *i;
8181
8182 - int prevChunkId;
8183 - int retVal = 0;
8184 - int result = 0;
8185 + __u32 n = (__u32) bucket;
8186
8187 - int newChunkId;
8188 - yaffs_ExtendedTags newTags;
8189 - yaffs_ExtendedTags oldTags;
8190 + /* yaffs_CheckObjectHashSanity(); */
8191
8192 - __u8 *buffer = NULL;
8193 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8194 + while (!found) {
8195 + found = 1;
8196 + n += YAFFS_NOBJECT_BUCKETS;
8197 + if (1 || dev->objectBucket[bucket].count > 0) {
8198 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8199 + /* If there is already one in the list */
8200 + if (i && ylist_entry(i, yaffs_Object,
8201 + hashLink)->objectId == n) {
8202 + found = 0;
8203 + }
8204 + }
8205 + }
8206 + }
8207
8208 - yaffs_ObjectHeader *oh = NULL;
8209 + return n;
8210 +}
8211
8212 - yaffs_strcpy(oldName, _Y("silly old name"));
8213 +static void yaffs_HashObject(yaffs_Object *in)
8214 +{
8215 + int bucket = yaffs_HashFunction(in->objectId);
8216 + yaffs_Device *dev = in->myDev;
8217
8218 + ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
8219 + dev->objectBucket[bucket].count++;
8220 +}
8221
8222 - if (!in->fake ||
8223 - in == dev->rootDir || /* The rootDir should also be saved */
8224 - force) {
8225 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
8226 +{
8227 + int bucket = yaffs_HashFunction(number);
8228 + struct ylist_head *i;
8229 + yaffs_Object *in;
8230
8231 - yaffs_CheckGarbageCollection(dev);
8232 - yaffs_CheckObjectDetailsLoaded(in);
8233 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8234 + /* Look if it is in the list */
8235 + if (i) {
8236 + in = ylist_entry(i, yaffs_Object, hashLink);
8237 + if (in->objectId == number) {
8238
8239 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8240 - oh = (yaffs_ObjectHeader *) buffer;
8241 + /* Don't tell the VFS about this one if it is defered free */
8242 + if (in->deferedFree)
8243 + return NULL;
8244
8245 - prevChunkId = in->hdrChunk;
8246 + return in;
8247 + }
8248 + }
8249 + }
8250
8251 - if (prevChunkId > 0) {
8252 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8253 - buffer, &oldTags);
8254 + return NULL;
8255 +}
8256
8257 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8258 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
8259 + yaffs_ObjectType type)
8260 +{
8261 + yaffs_Object *theObject=NULL;
8262 + yaffs_Tnode *tn = NULL;
8263 +
8264 + if (number < 0)
8265 + number = yaffs_CreateNewObjectNumber(dev);
8266
8267 - memcpy(oldName, oh->name, sizeof(oh->name));
8268 - }
8269 + if (type == YAFFS_OBJECT_TYPE_FILE) {
8270 + tn = yaffs_GetTnode(dev);
8271 + if (!tn)
8272 + return NULL;
8273 + }
8274
8275 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8276 + theObject = yaffs_AllocateEmptyObject(dev);
8277 + if (!theObject){
8278 + if(tn)
8279 + yaffs_FreeTnode(dev,tn);
8280 + return NULL;
8281 + }
8282
8283 - oh->type = in->variantType;
8284 - oh->yst_mode = in->yst_mode;
8285 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8286
8287 + if (theObject) {
8288 + theObject->fake = 0;
8289 + theObject->renameAllowed = 1;
8290 + theObject->unlinkAllowed = 1;
8291 + theObject->objectId = number;
8292 + yaffs_HashObject(theObject);
8293 + theObject->variantType = type;
8294 #ifdef CONFIG_YAFFS_WINCE
8295 - oh->win_atime[0] = in->win_atime[0];
8296 - oh->win_ctime[0] = in->win_ctime[0];
8297 - oh->win_mtime[0] = in->win_mtime[0];
8298 - oh->win_atime[1] = in->win_atime[1];
8299 - oh->win_ctime[1] = in->win_ctime[1];
8300 - oh->win_mtime[1] = in->win_mtime[1];
8301 -#else
8302 - oh->yst_uid = in->yst_uid;
8303 - oh->yst_gid = in->yst_gid;
8304 - oh->yst_atime = in->yst_atime;
8305 - oh->yst_mtime = in->yst_mtime;
8306 - oh->yst_ctime = in->yst_ctime;
8307 - oh->yst_rdev = in->yst_rdev;
8308 -#endif
8309 - if (in->parent)
8310 - oh->parentObjectId = in->parent->objectId;
8311 - else
8312 - oh->parentObjectId = 0;
8313 -
8314 - if (name && *name) {
8315 - memset(oh->name, 0, sizeof(oh->name));
8316 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
8317 - } else if (prevChunkId >= 0)
8318 - memcpy(oh->name, oldName, sizeof(oh->name));
8319 - else
8320 - memset(oh->name, 0, sizeof(oh->name));
8321 + yfsd_WinFileTimeNow(theObject->win_atime);
8322 + theObject->win_ctime[0] = theObject->win_mtime[0] =
8323 + theObject->win_atime[0];
8324 + theObject->win_ctime[1] = theObject->win_mtime[1] =
8325 + theObject->win_atime[1];
8326
8327 - oh->isShrink = isShrink;
8328 +#else
8329
8330 - switch (in->variantType) {
8331 - case YAFFS_OBJECT_TYPE_UNKNOWN:
8332 - /* Should not happen */
8333 - break;
8334 + theObject->yst_atime = theObject->yst_mtime =
8335 + theObject->yst_ctime = Y_CURRENT_TIME;
8336 +#endif
8337 + switch (type) {
8338 case YAFFS_OBJECT_TYPE_FILE:
8339 - oh->fileSize =
8340 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
8341 - || oh->parentObjectId ==
8342 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
8343 - fileVariant.fileSize;
8344 - break;
8345 - case YAFFS_OBJECT_TYPE_HARDLINK:
8346 - oh->equivalentObjectId =
8347 - in->variant.hardLinkVariant.equivalentObjectId;
8348 - break;
8349 - case YAFFS_OBJECT_TYPE_SPECIAL:
8350 - /* Do nothing */
8351 + theObject->variant.fileVariant.fileSize = 0;
8352 + theObject->variant.fileVariant.scannedFileSize = 0;
8353 + theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
8354 + theObject->variant.fileVariant.topLevel = 0;
8355 + theObject->variant.fileVariant.top = tn;
8356 break;
8357 case YAFFS_OBJECT_TYPE_DIRECTORY:
8358 - /* Do nothing */
8359 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8360 + children);
8361 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8362 + dirty);
8363 break;
8364 case YAFFS_OBJECT_TYPE_SYMLINK:
8365 - yaffs_strncpy(oh->alias,
8366 - in->variant.symLinkVariant.alias,
8367 - YAFFS_MAX_ALIAS_LENGTH);
8368 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
8369 + case YAFFS_OBJECT_TYPE_HARDLINK:
8370 + case YAFFS_OBJECT_TYPE_SPECIAL:
8371 + /* No action required */
8372 + break;
8373 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8374 + /* todo this should not happen */
8375 break;
8376 }
8377 + }
8378
8379 - /* Tags */
8380 - yaffs_InitialiseTags(&newTags);
8381 - in->serial++;
8382 - newTags.chunkId = 0;
8383 - newTags.objectId = in->objectId;
8384 - newTags.serialNumber = in->serial;
8385 -
8386 - /* Add extra info for file header */
8387 -
8388 - newTags.extraHeaderInfoAvailable = 1;
8389 - newTags.extraParentObjectId = oh->parentObjectId;
8390 - newTags.extraFileLength = oh->fileSize;
8391 - newTags.extraIsShrinkHeader = oh->isShrink;
8392 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
8393 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
8394 - newTags.extraObjectType = in->variantType;
8395 -
8396 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
8397 + return theObject;
8398 +}
8399
8400 - /* Create new chunk in NAND */
8401 - newChunkId =
8402 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8403 - (prevChunkId >= 0) ? 1 : 0);
8404 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
8405 + int number,
8406 + yaffs_ObjectType type)
8407 +{
8408 + yaffs_Object *theObject = NULL;
8409
8410 - if (newChunkId >= 0) {
8411 + if (number > 0)
8412 + theObject = yaffs_FindObjectByNumber(dev, number);
8413
8414 - in->hdrChunk = newChunkId;
8415 + if (!theObject)
8416 + theObject = yaffs_CreateNewObject(dev, number, type);
8417
8418 - if (prevChunkId >= 0) {
8419 - yaffs_DeleteChunk(dev, prevChunkId, 1,
8420 - __LINE__);
8421 - }
8422 + return theObject;
8423
8424 - if (!yaffs_ObjectHasCachedWriteData(in))
8425 - in->dirty = 0;
8426 +}
8427
8428 - /* If this was a shrink, then mark the block that the chunk lives on */
8429 - if (isShrink) {
8430 - bi = yaffs_GetBlockInfo(in->myDev,
8431 - newChunkId / in->myDev->nChunksPerBlock);
8432 - bi->hasShrinkHeader = 1;
8433 - }
8434
8435 - }
8436 +YCHAR *yaffs_CloneString(const YCHAR *str)
8437 +{
8438 + YCHAR *newStr = NULL;
8439 + int len;
8440
8441 - retVal = newChunkId;
8442 + if (!str)
8443 + str = _Y("");
8444
8445 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
8446 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
8447 + if (newStr){
8448 + yaffs_strncpy(newStr, str,len);
8449 + newStr[len] = 0;
8450 }
8451 + return newStr;
8452
8453 - if (buffer)
8454 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8455 -
8456 - return retVal;
8457 }
8458
8459 -/*------------------------ Short Operations Cache ----------------------------------------
8460 - * In many situations where there is no high level buffering (eg WinCE) a lot of
8461 - * reads might be short sequential reads, and a lot of writes may be short
8462 - * sequential writes. eg. scanning/writing a jpeg file.
8463 - * In these cases, a short read/write cache can provide a huge perfomance benefit
8464 - * with dumb-as-a-rock code.
8465 - * In Linux, the page cache provides read buffering aand the short op cache provides write
8466 - * buffering.
8467 - *
8468 - * There are a limited number (~10) of cache chunks per device so that we don't
8469 - * need a very intelligent search.
8470 +/*
8471 + * Mknod (create) a new object.
8472 + * equivalentObject only has meaning for a hard link;
8473 + * aliasString only has meaning for a symlink.
8474 + * rdev only has meaning for devices (a subset of special objects)
8475 */
8476
8477 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
8478 +static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
8479 + yaffs_Object *parent,
8480 + const YCHAR *name,
8481 + __u32 mode,
8482 + __u32 uid,
8483 + __u32 gid,
8484 + yaffs_Object *equivalentObject,
8485 + const YCHAR *aliasString, __u32 rdev)
8486 {
8487 - yaffs_Device *dev = obj->myDev;
8488 - int i;
8489 - yaffs_ChunkCache *cache;
8490 - int nCaches = obj->myDev->nShortOpCaches;
8491 + yaffs_Object *in;
8492 + YCHAR *str = NULL;
8493
8494 - for (i = 0; i < nCaches; i++) {
8495 - cache = &dev->srCache[i];
8496 - if (cache->object == obj &&
8497 - cache->dirty)
8498 - return 1;
8499 + yaffs_Device *dev = parent->myDev;
8500 +
8501 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8502 + if (yaffs_FindObjectByName(parent, name))
8503 + return NULL;
8504 +
8505 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8506 + str = yaffs_CloneString(aliasString);
8507 + if (!str)
8508 + return NULL;
8509 }
8510
8511 - return 0;
8512 -}
8513 + in = yaffs_CreateNewObject(dev, -1, type);
8514
8515 + if (!in){
8516 + if(str)
8517 + YFREE(str);
8518 + return NULL;
8519 + }
8520
8521 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
8522 -{
8523 - yaffs_Device *dev = obj->myDev;
8524 - int lowest = -99; /* Stop compiler whining. */
8525 - int i;
8526 - yaffs_ChunkCache *cache;
8527 - int chunkWritten = 0;
8528 - int nCaches = obj->myDev->nShortOpCaches;
8529
8530 - if (nCaches > 0) {
8531 - do {
8532 - cache = NULL;
8533
8534 - /* Find the dirty cache for this object with the lowest chunk id. */
8535 - for (i = 0; i < nCaches; i++) {
8536 - if (dev->srCache[i].object == obj &&
8537 - dev->srCache[i].dirty) {
8538 - if (!cache
8539 - || dev->srCache[i].chunkId <
8540 - lowest) {
8541 - cache = &dev->srCache[i];
8542 - lowest = cache->chunkId;
8543 - }
8544 - }
8545 - }
8546
8547 - if (cache && !cache->locked) {
8548 - /* Write it out and free it up */
8549
8550 - chunkWritten =
8551 - yaffs_WriteChunkDataToObject(cache->object,
8552 - cache->chunkId,
8553 - cache->data,
8554 - cache->nBytes,
8555 - 1);
8556 - cache->dirty = 0;
8557 - cache->object = NULL;
8558 - }
8559 + if (in) {
8560 + in->hdrChunk = 0;
8561 + in->valid = 1;
8562 + in->variantType = type;
8563
8564 - } while (cache && chunkWritten > 0);
8565 + in->yst_mode = mode;
8566
8567 - if (cache) {
8568 - /* Hoosterman, disk full while writing cache out. */
8569 - T(YAFFS_TRACE_ERROR,
8570 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
8571 +#ifdef CONFIG_YAFFS_WINCE
8572 + yfsd_WinFileTimeNow(in->win_atime);
8573 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8574 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
8575 +
8576 +#else
8577 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
8578 +
8579 + in->yst_rdev = rdev;
8580 + in->yst_uid = uid;
8581 + in->yst_gid = gid;
8582 +#endif
8583 + in->nDataChunks = 0;
8584 +
8585 + yaffs_SetObjectName(in, name);
8586 + in->dirty = 1;
8587 +
8588 + yaffs_AddObjectToDirectory(parent, in);
8589 +
8590 + in->myDev = parent->myDev;
8591 +
8592 + switch (type) {
8593 + case YAFFS_OBJECT_TYPE_SYMLINK:
8594 + in->variant.symLinkVariant.alias = str;
8595 + break;
8596 + case YAFFS_OBJECT_TYPE_HARDLINK:
8597 + in->variant.hardLinkVariant.equivalentObject =
8598 + equivalentObject;
8599 + in->variant.hardLinkVariant.equivalentObjectId =
8600 + equivalentObject->objectId;
8601 + ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
8602 + break;
8603 + case YAFFS_OBJECT_TYPE_FILE:
8604 + case YAFFS_OBJECT_TYPE_DIRECTORY:
8605 + case YAFFS_OBJECT_TYPE_SPECIAL:
8606 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8607 + /* do nothing */
8608 + break;
8609 + }
8610
8611 + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) {
8612 + /* Could not create the object header, fail the creation */
8613 + yaffs_DeleteObject(in);
8614 + in = NULL;
8615 }
8616 +
8617 + yaffs_UpdateParent(parent);
8618 }
8619
8620 + return in;
8621 }
8622
8623 -/*yaffs_FlushEntireDeviceCache(dev)
8624 - *
8625 - *
8626 - */
8627 -
8628 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
8629 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
8630 + __u32 mode, __u32 uid, __u32 gid)
8631 {
8632 - yaffs_Object *obj;
8633 - int nCaches = dev->nShortOpCaches;
8634 - int i;
8635 -
8636 - /* Find a dirty object in the cache and flush it...
8637 - * until there are no further dirty objects.
8638 - */
8639 - do {
8640 - obj = NULL;
8641 - for (i = 0; i < nCaches && !obj; i++) {
8642 - if (dev->srCache[i].object &&
8643 - dev->srCache[i].dirty)
8644 - obj = dev->srCache[i].object;
8645 -
8646 - }
8647 - if (obj)
8648 - yaffs_FlushFilesChunkCache(obj);
8649 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
8650 + uid, gid, NULL, NULL, 0);
8651 +}
8652
8653 - } while (obj);
8654 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
8655 + __u32 mode, __u32 uid, __u32 gid)
8656 +{
8657 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
8658 + mode, uid, gid, NULL, NULL, 0);
8659 +}
8660
8661 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
8662 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
8663 +{
8664 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
8665 + uid, gid, NULL, NULL, rdev);
8666 }
8667
8668 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
8669 + __u32 mode, __u32 uid, __u32 gid,
8670 + const YCHAR *alias)
8671 +{
8672 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
8673 + uid, gid, NULL, alias, 0);
8674 +}
8675
8676 -/* Grab us a cache chunk for use.
8677 - * First look for an empty one.
8678 - * Then look for the least recently used non-dirty one.
8679 - * Then look for the least recently used dirty one...., flush and look again.
8680 - */
8681 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
8682 +/* yaffs_Link returns the object id of the equivalent object.*/
8683 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
8684 + yaffs_Object *equivalentObject)
8685 {
8686 - int i;
8687 + /* Get the real object in case we were fed a hard link as an equivalent object */
8688 + equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
8689
8690 - if (dev->nShortOpCaches > 0) {
8691 - for (i = 0; i < dev->nShortOpCaches; i++) {
8692 - if (!dev->srCache[i].object)
8693 - return &dev->srCache[i];
8694 - }
8695 + if (yaffs_MknodObject
8696 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
8697 + equivalentObject, NULL, 0)) {
8698 + return equivalentObject;
8699 + } else {
8700 + return NULL;
8701 }
8702
8703 - return NULL;
8704 }
8705
8706 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
8707 +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
8708 + const YCHAR *newName, int force, int shadows)
8709 {
8710 - yaffs_ChunkCache *cache;
8711 - yaffs_Object *theObj;
8712 - int usage;
8713 - int i;
8714 - int pushout;
8715 -
8716 - if (dev->nShortOpCaches > 0) {
8717 - /* Try find a non-dirty one... */
8718 + int unlinkOp;
8719 + int deleteOp;
8720
8721 - cache = yaffs_GrabChunkCacheWorker(dev);
8722 + yaffs_Object *existingTarget;
8723
8724 - if (!cache) {
8725 - /* They were all dirty, find the last recently used object and flush
8726 - * its cache, then find again.
8727 - * NB what's here is not very accurate, we actually flush the object
8728 - * the last recently used page.
8729 - */
8730 + if (newDir == NULL)
8731 + newDir = obj->parent; /* use the old directory */
8732
8733 - /* With locking we can't assume we can use entry zero */
8734 + if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
8735 + T(YAFFS_TRACE_ALWAYS,
8736 + (TSTR
8737 + ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
8738 + TENDSTR)));
8739 + YBUG();
8740 + }
8741
8742 - theObj = NULL;
8743 - usage = -1;
8744 - cache = NULL;
8745 - pushout = -1;
8746 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
8747 + if (obj->myDev->param.isYaffs2)
8748 + unlinkOp = (newDir == obj->myDev->unlinkedDir);
8749 + else
8750 + unlinkOp = (newDir == obj->myDev->unlinkedDir
8751 + && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
8752
8753 - for (i = 0; i < dev->nShortOpCaches; i++) {
8754 - if (dev->srCache[i].object &&
8755 - !dev->srCache[i].locked &&
8756 - (dev->srCache[i].lastUse < usage || !cache)) {
8757 - usage = dev->srCache[i].lastUse;
8758 - theObj = dev->srCache[i].object;
8759 - cache = &dev->srCache[i];
8760 - pushout = i;
8761 - }
8762 - }
8763 + deleteOp = (newDir == obj->myDev->deletedDir);
8764
8765 - if (!cache || cache->dirty) {
8766 - /* Flush and try again */
8767 - yaffs_FlushFilesChunkCache(theObj);
8768 - cache = yaffs_GrabChunkCacheWorker(dev);
8769 - }
8770 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8771
8772 - }
8773 - return cache;
8774 - } else
8775 - return NULL;
8776 + /* If the object is a file going into the unlinked directory,
8777 + * then it is OK to just stuff it in since duplicate names are allowed.
8778 + * else only proceed if the new name does not exist and if we're putting
8779 + * it into a directory.
8780 + */
8781 + if ((unlinkOp ||
8782 + deleteOp ||
8783 + force ||
8784 + (shadows > 0) ||
8785 + !existingTarget) &&
8786 + newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
8787 + yaffs_SetObjectName(obj, newName);
8788 + obj->dirty = 1;
8789
8790 -}
8791 + yaffs_AddObjectToDirectory(newDir, obj);
8792
8793 -/* Find a cached chunk */
8794 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
8795 - int chunkId)
8796 -{
8797 - yaffs_Device *dev = obj->myDev;
8798 - int i;
8799 - if (dev->nShortOpCaches > 0) {
8800 - for (i = 0; i < dev->nShortOpCaches; i++) {
8801 - if (dev->srCache[i].object == obj &&
8802 - dev->srCache[i].chunkId == chunkId) {
8803 - dev->cacheHits++;
8804 + if (unlinkOp)
8805 + obj->unlinked = 1;
8806
8807 - return &dev->srCache[i];
8808 - }
8809 - }
8810 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
8811 + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0)
8812 + return YAFFS_OK;
8813 }
8814 - return NULL;
8815 +
8816 + return YAFFS_FAIL;
8817 }
8818
8819 -/* Mark the chunk for the least recently used algorithym */
8820 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
8821 - int isAWrite)
8822 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
8823 + yaffs_Object *newDir, const YCHAR *newName)
8824 {
8825 + yaffs_Object *obj = NULL;
8826 + yaffs_Object *existingTarget = NULL;
8827 + int force = 0;
8828 + int result;
8829 + yaffs_Device *dev;
8830
8831 - if (dev->nShortOpCaches > 0) {
8832 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
8833 - /* Reset the cache usages */
8834 - int i;
8835 - for (i = 1; i < dev->nShortOpCaches; i++)
8836 - dev->srCache[i].lastUse = 0;
8837
8838 - dev->srLastUse = 0;
8839 - }
8840 + if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8841 + YBUG();
8842 + if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8843 + YBUG();
8844
8845 - dev->srLastUse++;
8846 + dev = oldDir->myDev;
8847
8848 - cache->lastUse = dev->srLastUse;
8849 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
8850 + /* Special case for case insemsitive systems (eg. WinCE).
8851 + * While look-up is case insensitive, the name isn't.
8852 + * Therefore we might want to change x.txt to X.txt
8853 + */
8854 + if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
8855 + force = 1;
8856 +#endif
8857
8858 - if (isAWrite)
8859 - cache->dirty = 1;
8860 - }
8861 -}
8862 + if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
8863 + /* ENAMETOOLONG */
8864 + return YAFFS_FAIL;
8865
8866 -/* Invalidate a single cache page.
8867 - * Do this when a whole page gets written,
8868 - * ie the short cache for this page is no longer valid.
8869 - */
8870 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
8871 -{
8872 - if (object->myDev->nShortOpCaches > 0) {
8873 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
8874 + obj = yaffs_FindObjectByName(oldDir, oldName);
8875
8876 - if (cache)
8877 - cache->object = NULL;
8878 - }
8879 -}
8880 + if (obj && obj->renameAllowed) {
8881
8882 -/* Invalidate all the cache pages associated with this object
8883 - * Do this whenever ther file is deleted or resized.
8884 - */
8885 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
8886 -{
8887 - int i;
8888 - yaffs_Device *dev = in->myDev;
8889 + /* Now do the handling for an existing target, if there is one */
8890
8891 - if (dev->nShortOpCaches > 0) {
8892 - /* Invalidate it. */
8893 - for (i = 0; i < dev->nShortOpCaches; i++) {
8894 - if (dev->srCache[i].object == in)
8895 - dev->srCache[i].object = NULL;
8896 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8897 + if (existingTarget &&
8898 + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
8899 + !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
8900 + /* There is a target that is a non-empty directory, so we fail */
8901 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
8902 + } else if (existingTarget && existingTarget != obj) {
8903 + /* Nuke the target first, using shadowing,
8904 + * but only if it isn't the same object.
8905 + *
8906 + * Note we must disable gc otherwise it can mess up the shadowing.
8907 + *
8908 + */
8909 + dev->gcDisable=1;
8910 + yaffs_ChangeObjectName(obj, newDir, newName, force,
8911 + existingTarget->objectId);
8912 + existingTarget->isShadowed = 1;
8913 + yaffs_UnlinkObject(existingTarget);
8914 + dev->gcDisable=0;
8915 }
8916 +
8917 + result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
8918 +
8919 + yaffs_UpdateParent(oldDir);
8920 + if(newDir != oldDir)
8921 + yaffs_UpdateParent(newDir);
8922 +
8923 + return result;
8924 }
8925 + return YAFFS_FAIL;
8926 }
8927
8928 -/*--------------------- Checkpointing --------------------*/
8929 -
8930 +/*------------------------- Block Management and Page Allocation ----------------*/
8931
8932 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
8933 +static int yaffs_InitialiseBlocks(yaffs_Device *dev)
8934 {
8935 - yaffs_CheckpointValidity cp;
8936 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
8937
8938 - memset(&cp, 0, sizeof(cp));
8939 + dev->blockInfo = NULL;
8940 + dev->chunkBits = NULL;
8941
8942 - cp.structType = sizeof(cp);
8943 - cp.magic = YAFFS_MAGIC;
8944 - cp.version = YAFFS_CHECKPOINT_VERSION;
8945 - cp.head = (head) ? 1 : 0;
8946 + dev->allocationBlock = -1; /* force it to get a new one */
8947
8948 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
8949 - 1 : 0;
8950 -}
8951 + /* If the first allocation strategy fails, thry the alternate one */
8952 + dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
8953 + if (!dev->blockInfo) {
8954 + dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
8955 + dev->blockInfoAlt = 1;
8956 + } else
8957 + dev->blockInfoAlt = 0;
8958
8959 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
8960 -{
8961 - yaffs_CheckpointValidity cp;
8962 - int ok;
8963 + if (dev->blockInfo) {
8964 + /* Set up dynamic blockinfo stuff. */
8965 + dev->chunkBitmapStride = (dev->param.nChunksPerBlock + 7) / 8; /* round up bytes */
8966 + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
8967 + if (!dev->chunkBits) {
8968 + dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
8969 + dev->chunkBitsAlt = 1;
8970 + } else
8971 + dev->chunkBitsAlt = 0;
8972 + }
8973
8974 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
8975 + if (dev->blockInfo && dev->chunkBits) {
8976 + memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
8977 + memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
8978 + return YAFFS_OK;
8979 + }
8980
8981 - if (ok)
8982 - ok = (cp.structType == sizeof(cp)) &&
8983 - (cp.magic == YAFFS_MAGIC) &&
8984 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
8985 - (cp.head == ((head) ? 1 : 0));
8986 - return ok ? 1 : 0;
8987 + return YAFFS_FAIL;
8988 }
8989
8990 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
8991 - yaffs_Device *dev)
8992 +static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
8993 {
8994 - cp->nErasedBlocks = dev->nErasedBlocks;
8995 - cp->allocationBlock = dev->allocationBlock;
8996 - cp->allocationPage = dev->allocationPage;
8997 - cp->nFreeChunks = dev->nFreeChunks;
8998 + if (dev->blockInfoAlt && dev->blockInfo)
8999 + YFREE_ALT(dev->blockInfo);
9000 + else if (dev->blockInfo)
9001 + YFREE(dev->blockInfo);
9002 +
9003 + dev->blockInfoAlt = 0;
9004
9005 - cp->nDeletedFiles = dev->nDeletedFiles;
9006 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9007 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9008 - cp->sequenceNumber = dev->sequenceNumber;
9009 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9010 + dev->blockInfo = NULL;
9011
9012 + if (dev->chunkBitsAlt && dev->chunkBits)
9013 + YFREE_ALT(dev->chunkBits);
9014 + else if (dev->chunkBits)
9015 + YFREE(dev->chunkBits);
9016 + dev->chunkBitsAlt = 0;
9017 + dev->chunkBits = NULL;
9018 }
9019
9020 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9021 - yaffs_CheckpointDevice *cp)
9022 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
9023 {
9024 - dev->nErasedBlocks = cp->nErasedBlocks;
9025 - dev->allocationBlock = cp->allocationBlock;
9026 - dev->allocationPage = cp->allocationPage;
9027 - dev->nFreeChunks = cp->nFreeChunks;
9028 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
9029
9030 - dev->nDeletedFiles = cp->nDeletedFiles;
9031 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9032 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9033 - dev->sequenceNumber = cp->sequenceNumber;
9034 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9035 -}
9036 + int erasedOk = 0;
9037
9038 + /* If the block is still healthy erase it and mark as clean.
9039 + * If the block has had a data failure, then retire it.
9040 + */
9041
9042 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9043 -{
9044 - yaffs_CheckpointDevice cp;
9045 - __u32 nBytes;
9046 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9047 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9048 + (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
9049 + blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
9050
9051 - int ok;
9052 + yaffs2_ClearOldestDirtySequence(dev,bi);
9053
9054 - /* Write device runtime values*/
9055 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9056 - cp.structType = sizeof(cp);
9057 + bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
9058
9059 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9060 + /* If this is the block being garbage collected then stop gc'ing this block */
9061 + if(blockNo == dev->gcBlock)
9062 + dev->gcBlock = 0;
9063 +
9064 + /* If this block is currently the best candidate for gc then drop as a candidate */
9065 + if(blockNo == dev->gcDirtiest){
9066 + dev->gcDirtiest = 0;
9067 + dev->gcPagesInUse = 0;
9068 + }
9069
9070 - /* Write block info */
9071 - if (ok) {
9072 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9073 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9074 + if (!bi->needsRetiring) {
9075 + yaffs2_InvalidateCheckpoint(dev);
9076 + erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
9077 + if (!erasedOk) {
9078 + dev->nErasureFailures++;
9079 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9080 + (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
9081 + }
9082 }
9083
9084 - /* Write chunk bits */
9085 - if (ok) {
9086 - nBytes = nBlocks * dev->chunkBitmapStride;
9087 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9088 + if (erasedOk &&
9089 + ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
9090 + int i;
9091 + for (i = 0; i < dev->param.nChunksPerBlock; i++) {
9092 + if (!yaffs_CheckChunkErased
9093 + (dev, blockNo * dev->param.nChunksPerBlock + i)) {
9094 + T(YAFFS_TRACE_ERROR,
9095 + (TSTR
9096 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9097 + TENDSTR), blockNo, i));
9098 + }
9099 + }
9100 }
9101 - return ok ? 1 : 0;
9102
9103 + if (erasedOk) {
9104 + /* Clean it up... */
9105 + bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
9106 + bi->sequenceNumber = 0;
9107 + dev->nErasedBlocks++;
9108 + bi->pagesInUse = 0;
9109 + bi->softDeletions = 0;
9110 + bi->hasShrinkHeader = 0;
9111 + bi->skipErasedCheck = 1; /* This is clean, so no need to check */
9112 + bi->gcPrioritise = 0;
9113 + yaffs_ClearChunkBits(dev, blockNo);
9114 +
9115 + T(YAFFS_TRACE_ERASE,
9116 + (TSTR("Erased block %d" TENDSTR), blockNo));
9117 + } else {
9118 + dev->nFreeChunks -= dev->param.nChunksPerBlock; /* We lost a block of free space */
9119 +
9120 + yaffs_RetireBlock(dev, blockNo);
9121 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9122 + (TSTR("**>> Block %d retired" TENDSTR), blockNo));
9123 + }
9124 }
9125
9126 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9127 +static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
9128 {
9129 - yaffs_CheckpointDevice cp;
9130 - __u32 nBytes;
9131 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9132 -
9133 - int ok;
9134 + int i;
9135
9136 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9137 - if (!ok)
9138 - return 0;
9139 + yaffs_BlockInfo *bi;
9140
9141 - if (cp.structType != sizeof(cp))
9142 - return 0;
9143 + if (dev->nErasedBlocks < 1) {
9144 + /* Hoosterman we've got a problem.
9145 + * Can't get space to gc
9146 + */
9147 + T(YAFFS_TRACE_ERROR,
9148 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9149
9150 + return -1;
9151 + }
9152
9153 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9154 + /* Find an empty block. */
9155
9156 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9157 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
9158 + dev->allocationBlockFinder++;
9159 + if (dev->allocationBlockFinder < dev->internalStartBlock
9160 + || dev->allocationBlockFinder > dev->internalEndBlock) {
9161 + dev->allocationBlockFinder = dev->internalStartBlock;
9162 + }
9163
9164 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9165 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
9166
9167 - if (!ok)
9168 - return 0;
9169 - nBytes = nBlocks * dev->chunkBitmapStride;
9170 + if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
9171 + bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
9172 + dev->sequenceNumber++;
9173 + bi->sequenceNumber = dev->sequenceNumber;
9174 + dev->nErasedBlocks--;
9175 + T(YAFFS_TRACE_ALLOCATE,
9176 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9177 + dev->allocationBlockFinder, dev->sequenceNumber,
9178 + dev->nErasedBlocks));
9179 + return dev->allocationBlockFinder;
9180 + }
9181 + }
9182
9183 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9184 + T(YAFFS_TRACE_ALWAYS,
9185 + (TSTR
9186 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9187 + TENDSTR), dev->nErasedBlocks));
9188
9189 - return ok ? 1 : 0;
9190 + return -1;
9191 }
9192
9193 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9194 - yaffs_Object *obj)
9195 +
9196 +/*
9197 + * Check if there's space to allocate...
9198 + * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
9199 + */
9200 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks)
9201 {
9202 + int reservedChunks;
9203 + int reservedBlocks = dev->param.nReservedBlocks;
9204 + int checkpointBlocks;
9205
9206 - cp->objectId = obj->objectId;
9207 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9208 - cp->hdrChunk = obj->hdrChunk;
9209 - cp->variantType = obj->variantType;
9210 - cp->deleted = obj->deleted;
9211 - cp->softDeleted = obj->softDeleted;
9212 - cp->unlinked = obj->unlinked;
9213 - cp->fake = obj->fake;
9214 - cp->renameAllowed = obj->renameAllowed;
9215 - cp->unlinkAllowed = obj->unlinkAllowed;
9216 - cp->serial = obj->serial;
9217 - cp->nDataChunks = obj->nDataChunks;
9218 + checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev);
9219
9220 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9221 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9222 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9223 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9224 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
9225 +
9226 + return (dev->nFreeChunks > (reservedChunks + nChunks));
9227 }
9228
9229 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9230 +static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
9231 + yaffs_BlockInfo **blockUsedPtr)
9232 {
9233 + int retVal;
9234 + yaffs_BlockInfo *bi;
9235
9236 - yaffs_Object *parent;
9237 + if (dev->allocationBlock < 0) {
9238 + /* Get next block to allocate off */
9239 + dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
9240 + dev->allocationPage = 0;
9241 + }
9242
9243 - if (obj->variantType != cp->variantType) {
9244 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9245 - TCONT("chunk %d does not match existing object type %d")
9246 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9247 - obj->variantType));
9248 - return 0;
9249 + if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) {
9250 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9251 + return -1;
9252 }
9253
9254 - obj->objectId = cp->objectId;
9255 + if (dev->nErasedBlocks < dev->param.nReservedBlocks
9256 + && dev->allocationPage == 0) {
9257 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9258 + }
9259
9260 - if (cp->parentId)
9261 - parent = yaffs_FindOrCreateObjectByNumber(
9262 - obj->myDev,
9263 - cp->parentId,
9264 - YAFFS_OBJECT_TYPE_DIRECTORY);
9265 - else
9266 - parent = NULL;
9267 + /* Next page please.... */
9268 + if (dev->allocationBlock >= 0) {
9269 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9270
9271 - if (parent) {
9272 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9273 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9274 - TCONT(" chunk %d Parent type, %d, not directory")
9275 - TENDSTR),
9276 - cp->objectId, cp->parentId, cp->variantType,
9277 - cp->hdrChunk, parent->variantType));
9278 - return 0;
9279 - }
9280 - yaffs_AddObjectToDirectory(parent, obj);
9281 - }
9282 + retVal = (dev->allocationBlock * dev->param.nChunksPerBlock) +
9283 + dev->allocationPage;
9284 + bi->pagesInUse++;
9285 + yaffs_SetChunkBit(dev, dev->allocationBlock,
9286 + dev->allocationPage);
9287
9288 - obj->hdrChunk = cp->hdrChunk;
9289 - obj->variantType = cp->variantType;
9290 - obj->deleted = cp->deleted;
9291 - obj->softDeleted = cp->softDeleted;
9292 - obj->unlinked = cp->unlinked;
9293 - obj->fake = cp->fake;
9294 - obj->renameAllowed = cp->renameAllowed;
9295 - obj->unlinkAllowed = cp->unlinkAllowed;
9296 - obj->serial = cp->serial;
9297 - obj->nDataChunks = cp->nDataChunks;
9298 + dev->allocationPage++;
9299
9300 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9301 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9302 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9303 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9304 + dev->nFreeChunks--;
9305
9306 - if (obj->hdrChunk > 0)
9307 - obj->lazyLoaded = 1;
9308 - return 1;
9309 -}
9310 + /* If the block is full set the state to full */
9311 + if (dev->allocationPage >= dev->param.nChunksPerBlock) {
9312 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9313 + dev->allocationBlock = -1;
9314 + }
9315
9316 + if (blockUsedPtr)
9317 + *blockUsedPtr = bi;
9318
9319 + return retVal;
9320 + }
9321
9322 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9323 - __u32 level, int chunkOffset)
9324 -{
9325 - int i;
9326 - yaffs_Device *dev = in->myDev;
9327 - int ok = 1;
9328 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9329 + T(YAFFS_TRACE_ERROR,
9330 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9331
9332 - if (tnodeSize < sizeof(yaffs_Tnode))
9333 - tnodeSize = sizeof(yaffs_Tnode);
9334 + return -1;
9335 +}
9336
9337 +static int yaffs_GetErasedChunks(yaffs_Device *dev)
9338 +{
9339 + int n;
9340
9341 - if (tn) {
9342 - if (level > 0) {
9343 + n = dev->nErasedBlocks * dev->param.nChunksPerBlock;
9344
9345 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9346 - if (tn->internal[i]) {
9347 - ok = yaffs_CheckpointTnodeWorker(in,
9348 - tn->internal[i],
9349 - level - 1,
9350 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9351 - }
9352 - }
9353 - } else if (level == 0) {
9354 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9355 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9356 - if (ok)
9357 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9358 - }
9359 - }
9360 + if (dev->allocationBlock > 0)
9361 + n += (dev->param.nChunksPerBlock - dev->allocationPage);
9362
9363 - return ok;
9364 + return n;
9365
9366 }
9367
9368 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9369 +/*
9370 + * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
9371 + * if we don't want to write to it.
9372 + */
9373 +void yaffs_SkipRestOfBlock(yaffs_Device *dev)
9374 {
9375 - __u32 endMarker = ~0;
9376 - int ok = 1;
9377 -
9378 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9379 - ok = yaffs_CheckpointTnodeWorker(obj,
9380 - obj->variant.fileVariant.top,
9381 - obj->variant.fileVariant.topLevel,
9382 - 0);
9383 - if (ok)
9384 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
9385 - sizeof(endMarker));
9386 + if(dev->allocationBlock > 0){
9387 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9388 + if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
9389 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9390 + dev->allocationBlock = -1;
9391 + }
9392 }
9393 -
9394 - return ok ? 1 : 0;
9395 }
9396
9397 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
9398 -{
9399 - __u32 baseChunk;
9400 - int ok = 1;
9401 - yaffs_Device *dev = obj->myDev;
9402 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
9403 - yaffs_Tnode *tn;
9404 - int nread = 0;
9405 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9406
9407 - if (tnodeSize < sizeof(yaffs_Tnode))
9408 - tnodeSize = sizeof(yaffs_Tnode);
9409 +static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
9410 + int wholeBlock)
9411 +{
9412 + int oldChunk;
9413 + int newChunk;
9414 + int markNAND;
9415 + int retVal = YAFFS_OK;
9416 + int i;
9417 + int isCheckpointBlock;
9418 + int matchingChunk;
9419 + int maxCopies;
9420
9421 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9422 + int chunksBefore = yaffs_GetErasedChunks(dev);
9423 + int chunksAfter;
9424
9425 - while (ok && (~baseChunk)) {
9426 - nread++;
9427 - /* Read level 0 tnode */
9428 + yaffs_ExtendedTags tags;
9429
9430 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
9431
9432 - tn = yaffs_GetTnodeRaw(dev);
9433 - if (tn)
9434 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
9435 - else
9436 - ok = 0;
9437 + yaffs_Object *object;
9438
9439 - if (tn && ok)
9440 - ok = yaffs_AddOrFindLevel0Tnode(dev,
9441 - fileStructPtr,
9442 - baseChunk,
9443 - tn) ? 1 : 0;
9444 + isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
9445
9446 - if (ok)
9447 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9448
9449 - }
9450 + T(YAFFS_TRACE_TRACING,
9451 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
9452 + block,
9453 + bi->pagesInUse,
9454 + bi->hasShrinkHeader,
9455 + wholeBlock));
9456
9457 - T(YAFFS_TRACE_CHECKPOINT, (
9458 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
9459 - nread, baseChunk, ok));
9460 + /*yaffs_VerifyFreeChunks(dev); */
9461
9462 - return ok ? 1 : 0;
9463 -}
9464 + if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
9465 + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
9466 +
9467 + bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
9468
9469 + dev->gcDisable = 1;
9470
9471 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
9472 -{
9473 - yaffs_Object *obj;
9474 - yaffs_CheckpointObject cp;
9475 - int i;
9476 - int ok = 1;
9477 - struct ylist_head *lh;
9478 + if (isCheckpointBlock ||
9479 + !yaffs_StillSomeChunkBits(dev, block)) {
9480 + T(YAFFS_TRACE_TRACING,
9481 + (TSTR
9482 + ("Collecting block %d that has no chunks in use" TENDSTR),
9483 + block));
9484 + yaffs_BlockBecameDirty(dev, block);
9485 + } else {
9486
9487 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
9488
9489 - /* Iterate through the objects in each hash entry,
9490 - * dumping them to the checkpointing stream.
9491 - */
9492 + yaffs_VerifyBlock(dev, bi, block);
9493
9494 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
9495 - ylist_for_each(lh, &dev->objectBucket[i].list) {
9496 - if (lh) {
9497 - obj = ylist_entry(lh, yaffs_Object, hashLink);
9498 - if (!obj->deferedFree) {
9499 - yaffs_ObjectToCheckpointObject(&cp, obj);
9500 - cp.structType = sizeof(cp);
9501 -
9502 - T(YAFFS_TRACE_CHECKPOINT, (
9503 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
9504 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
9505 + maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5;
9506 + oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk;
9507
9508 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9509 + for (/* init already done */;
9510 + retVal == YAFFS_OK &&
9511 + dev->gcChunk < dev->param.nChunksPerBlock &&
9512 + (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
9513 + maxCopies > 0;
9514 + dev->gcChunk++, oldChunk++) {
9515 + if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
9516
9517 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9518 - ok = yaffs_WriteCheckpointTnodes(obj);
9519 - }
9520 - }
9521 - }
9522 - }
9523 + /* This page is in use and might need to be copied off */
9524
9525 - /* Dump end of list */
9526 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
9527 - cp.structType = sizeof(cp);
9528 + maxCopies--;
9529
9530 - if (ok)
9531 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9532 + markNAND = 1;
9533
9534 - return ok ? 1 : 0;
9535 -}
9536 + yaffs_InitialiseTags(&tags);
9537
9538 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
9539 -{
9540 - yaffs_Object *obj;
9541 - yaffs_CheckpointObject cp;
9542 - int ok = 1;
9543 - int done = 0;
9544 - yaffs_Object *hardList = NULL;
9545 + yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
9546 + buffer, &tags);
9547
9548 - while (ok && !done) {
9549 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9550 - if (cp.structType != sizeof(cp)) {
9551 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
9552 - cp.structType, sizeof(cp), ok));
9553 - ok = 0;
9554 - }
9555 -
9556 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
9557 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
9558 -
9559 - if (ok && cp.objectId == ~0)
9560 - done = 1;
9561 - else if (ok) {
9562 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
9563 - if (obj) {
9564 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
9565 - if (!ok)
9566 - break;
9567 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9568 - ok = yaffs_ReadCheckpointTnodes(obj);
9569 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
9570 - obj->hardLinks.next =
9571 - (struct ylist_head *) hardList;
9572 - hardList = obj;
9573 - }
9574 - } else
9575 - ok = 0;
9576 - }
9577 - }
9578 + object =
9579 + yaffs_FindObjectByNumber(dev,
9580 + tags.objectId);
9581
9582 - if (ok)
9583 - yaffs_HardlinkFixup(dev, hardList);
9584 + T(YAFFS_TRACE_GC_DETAIL,
9585 + (TSTR
9586 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
9587 + dev->gcChunk, tags.objectId, tags.chunkId,
9588 + tags.byteCount));
9589
9590 - return ok ? 1 : 0;
9591 -}
9592 + if (object && !yaffs_SkipVerification(dev)) {
9593 + if (tags.chunkId == 0)
9594 + matchingChunk = object->hdrChunk;
9595 + else if (object->softDeleted)
9596 + matchingChunk = oldChunk; /* Defeat the test */
9597 + else
9598 + matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
9599
9600 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
9601 -{
9602 - __u32 checkpointSum;
9603 - int ok;
9604 + if (oldChunk != matchingChunk)
9605 + T(YAFFS_TRACE_ERROR,
9606 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
9607 + oldChunk, matchingChunk, tags.objectId, tags.chunkId));
9608
9609 - yaffs_GetCheckpointSum(dev, &checkpointSum);
9610 + }
9611
9612 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
9613 + if (!object) {
9614 + T(YAFFS_TRACE_ERROR,
9615 + (TSTR
9616 + ("page %d in gc has no object: %d %d %d "
9617 + TENDSTR), oldChunk,
9618 + tags.objectId, tags.chunkId, tags.byteCount));
9619 + }
9620
9621 - if (!ok)
9622 - return 0;
9623 + if (object &&
9624 + object->deleted &&
9625 + object->softDeleted &&
9626 + tags.chunkId != 0) {
9627 + /* Data chunk in a soft deleted file, throw it away
9628 + * It's a soft deleted data chunk,
9629 + * No need to copy this, just forget about it and
9630 + * fix up the object.
9631 + */
9632 +
9633 + /* Free chunks already includes softdeleted chunks.
9634 + * How ever this chunk is going to soon be really deleted
9635 + * which will increment free chunks.
9636 + * We have to decrement free chunks so this works out properly.
9637 + */
9638 + dev->nFreeChunks--;
9639 + bi->softDeletions--;
9640
9641 - return 1;
9642 -}
9643 + object->nDataChunks--;
9644
9645 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
9646 -{
9647 - __u32 checkpointSum0;
9648 - __u32 checkpointSum1;
9649 - int ok;
9650 + if (object->nDataChunks <= 0) {
9651 + /* remeber to clean up the object */
9652 + dev->gcCleanupList[dev->nCleanups] =
9653 + tags.objectId;
9654 + dev->nCleanups++;
9655 + }
9656 + markNAND = 0;
9657 + } else if (0) {
9658 + /* Todo object && object->deleted && object->nDataChunks == 0 */
9659 + /* Deleted object header with no data chunks.
9660 + * Can be discarded and the file deleted.
9661 + */
9662 + object->hdrChunk = 0;
9663 + yaffs_FreeTnode(object->myDev,
9664 + object->variant.
9665 + fileVariant.top);
9666 + object->variant.fileVariant.top = NULL;
9667 + yaffs_DoGenericObjectDeletion(object);
9668
9669 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
9670 + } else if (object) {
9671 + /* It's either a data chunk in a live file or
9672 + * an ObjectHeader, so we're interested in it.
9673 + * NB Need to keep the ObjectHeaders of deleted files
9674 + * until the whole file has been deleted off
9675 + */
9676 + tags.serialNumber++;
9677
9678 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
9679 + dev->nGCCopies++;
9680
9681 - if (!ok)
9682 - return 0;
9683 + if (tags.chunkId == 0) {
9684 + /* It is an object Id,
9685 + * We need to nuke the shrinkheader flags first
9686 + * Also need to clean up shadowing.
9687 + * We no longer want the shrinkHeader flag since its work is done
9688 + * and if it is left in place it will mess up scanning.
9689 + */
9690
9691 - if (checkpointSum0 != checkpointSum1)
9692 - return 0;
9693 + yaffs_ObjectHeader *oh;
9694 + oh = (yaffs_ObjectHeader *)buffer;
9695
9696 - return 1;
9697 -}
9698 + oh->isShrink = 0;
9699 + tags.extraIsShrinkHeader = 0;
9700
9701 + oh->shadowsObject = 0;
9702 + oh->inbandShadowsObject = 0;
9703 + tags.extraShadows = 0;
9704 +
9705 + /* Update file size */
9706 + if(object->variantType == YAFFS_OBJECT_TYPE_FILE){
9707 + oh->fileSize = object->variant.fileVariant.fileSize;
9708 + tags.extraFileLength = oh->fileSize;
9709 + }
9710
9711 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
9712 -{
9713 - int ok = 1;
9714 + yaffs_VerifyObjectHeader(object, oh, &tags, 1);
9715 + newChunk =
9716 + yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1);
9717 + } else
9718 + newChunk =
9719 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
9720
9721 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
9722 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
9723 - ok = 0;
9724 - }
9725 + if (newChunk < 0) {
9726 + retVal = YAFFS_FAIL;
9727 + } else {
9728
9729 - if (ok)
9730 - ok = yaffs_CheckpointOpen(dev, 1);
9731 + /* Ok, now fix up the Tnodes etc. */
9732
9733 - if (ok) {
9734 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9735 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
9736 - }
9737 - if (ok) {
9738 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
9739 - ok = yaffs_WriteCheckpointDevice(dev);
9740 - }
9741 - if (ok) {
9742 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
9743 - ok = yaffs_WriteCheckpointObjects(dev);
9744 - }
9745 - if (ok) {
9746 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9747 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
9748 - }
9749 + if (tags.chunkId == 0) {
9750 + /* It's a header */
9751 + object->hdrChunk = newChunk;
9752 + object->serial = tags.serialNumber;
9753 + } else {
9754 + /* It's a data chunk */
9755 + int ok;
9756 + ok = yaffs_PutChunkIntoFile
9757 + (object,
9758 + tags.chunkId,
9759 + newChunk, 0);
9760 + }
9761 + }
9762 + }
9763
9764 - if (ok)
9765 - ok = yaffs_WriteCheckpointSum(dev);
9766 + if (retVal == YAFFS_OK)
9767 + yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
9768
9769 - if (!yaffs_CheckpointClose(dev))
9770 - ok = 0;
9771 + }
9772 + }
9773
9774 - if (ok)
9775 - dev->isCheckpointed = 1;
9776 - else
9777 - dev->isCheckpointed = 0;
9778 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9779
9780 - return dev->isCheckpointed;
9781 -}
9782
9783 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
9784 -{
9785 - int ok = 1;
9786
9787 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
9788 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
9789 - ok = 0;
9790 }
9791
9792 - if (ok)
9793 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
9794 -
9795 - if (ok) {
9796 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9797 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
9798 - }
9799 - if (ok) {
9800 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
9801 - ok = yaffs_ReadCheckpointDevice(dev);
9802 - }
9803 - if (ok) {
9804 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
9805 - ok = yaffs_ReadCheckpointObjects(dev);
9806 - }
9807 - if (ok) {
9808 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9809 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
9810 - }
9811 + yaffs_VerifyCollectedBlock(dev, bi, block);
9812
9813 - if (ok) {
9814 - ok = yaffs_ReadCheckpointSum(dev);
9815 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
9816 - }
9817
9818 - if (!yaffs_CheckpointClose(dev))
9819 - ok = 0;
9820
9821 - if (ok)
9822 - dev->isCheckpointed = 1;
9823 - else
9824 - dev->isCheckpointed = 0;
9825 + if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
9826 + /*
9827 + * The gc did not complete. Set block state back to FULL
9828 + * because checkpointing does not restore gc.
9829 + */
9830 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9831 + } else {
9832 + /* The gc completed. */
9833 + /* Do any required cleanups */
9834 + for (i = 0; i < dev->nCleanups; i++) {
9835 + /* Time to delete the file too */
9836 + object =
9837 + yaffs_FindObjectByNumber(dev,
9838 + dev->gcCleanupList[i]);
9839 + if (object) {
9840 + yaffs_FreeTnode(dev,
9841 + object->variant.fileVariant.
9842 + top);
9843 + object->variant.fileVariant.top = NULL;
9844 + T(YAFFS_TRACE_GC,
9845 + (TSTR
9846 + ("yaffs: About to finally delete object %d"
9847 + TENDSTR), object->objectId));
9848 + yaffs_DoGenericObjectDeletion(object);
9849 + object->myDev->nDeletedFiles--;
9850 + }
9851
9852 - return ok ? 1 : 0;
9853 + }
9854
9855 -}
9856
9857 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
9858 -{
9859 - if (dev->isCheckpointed ||
9860 - dev->blocksInCheckpoint > 0) {
9861 - dev->isCheckpointed = 0;
9862 - yaffs_CheckpointInvalidateStream(dev);
9863 - if (dev->superBlock && dev->markSuperBlockDirty)
9864 - dev->markSuperBlockDirty(dev->superBlock);
9865 + chunksAfter = yaffs_GetErasedChunks(dev);
9866 + if (chunksBefore >= chunksAfter) {
9867 + T(YAFFS_TRACE_GC,
9868 + (TSTR
9869 + ("gc did not increase free chunks before %d after %d"
9870 + TENDSTR), chunksBefore, chunksAfter));
9871 + }
9872 + dev->gcBlock = 0;
9873 + dev->gcChunk = 0;
9874 + dev->nCleanups = 0;
9875 }
9876 -}
9877
9878 + dev->gcDisable = 0;
9879
9880 -int yaffs_CheckpointSave(yaffs_Device *dev)
9881 -{
9882 -
9883 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9884 + return retVal;
9885 +}
9886
9887 - yaffs_VerifyObjects(dev);
9888 - yaffs_VerifyBlocks(dev);
9889 - yaffs_VerifyFreeChunks(dev);
9890 +/*
9891 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
9892 + * for garbage collection.
9893 + */
9894
9895 - if (!dev->isCheckpointed) {
9896 - yaffs_InvalidateCheckpoint(dev);
9897 - yaffs_WriteCheckpointData(dev);
9898 - }
9899 +static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
9900 + int aggressive,
9901 + int background)
9902 +{
9903 + int i;
9904 + int iterations;
9905 + unsigned selected = 0;
9906 + int prioritised = 0;
9907 + int prioritisedExists = 0;
9908 + yaffs_BlockInfo *bi;
9909 + int threshold;
9910
9911 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9912 + /* First let's see if we need to grab a prioritised block */
9913 + if (dev->hasPendingPrioritisedGCs && !aggressive) {
9914 + dev->gcDirtiest = 0;
9915 + bi = dev->blockInfo;
9916 + for (i = dev->internalStartBlock;
9917 + i <= dev->internalEndBlock && !selected;
9918 + i++) {
9919
9920 - return dev->isCheckpointed;
9921 -}
9922 + if (bi->gcPrioritise) {
9923 + prioritisedExists = 1;
9924 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
9925 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
9926 + selected = i;
9927 + prioritised = 1;
9928 + }
9929 + }
9930 + bi++;
9931 + }
9932
9933 -int yaffs_CheckpointRestore(yaffs_Device *dev)
9934 -{
9935 - int retval;
9936 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9937 + /*
9938 + * If there is a prioritised block and none was selected then
9939 + * this happened because there is at least one old dirty block gumming
9940 + * up the works. Let's gc the oldest dirty block.
9941 + */
9942
9943 - retval = yaffs_ReadCheckpointData(dev);
9944 + if(prioritisedExists &&
9945 + !selected &&
9946 + dev->oldestDirtyBlock > 0)
9947 + selected = dev->oldestDirtyBlock;
9948
9949 - if (dev->isCheckpointed) {
9950 - yaffs_VerifyObjects(dev);
9951 - yaffs_VerifyBlocks(dev);
9952 - yaffs_VerifyFreeChunks(dev);
9953 + if (!prioritisedExists) /* None found, so we can clear this */
9954 + dev->hasPendingPrioritisedGCs = 0;
9955 }
9956
9957 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9958 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
9959 + * search harder.
9960 + * else (we're doing a leasurely gc), then we only bother to do this if the
9961 + * block has only a few pages in use.
9962 + */
9963
9964 - return retval;
9965 -}
9966 + if (!selected){
9967 + int pagesUsed;
9968 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
9969 + if (aggressive){
9970 + threshold = dev->param.nChunksPerBlock;
9971 + iterations = nBlocks;
9972 + } else {
9973 + int maxThreshold;
9974
9975 -/*--------------------- File read/write ------------------------
9976 - * Read and write have very similar structures.
9977 - * In general the read/write has three parts to it
9978 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
9979 - * Some complete chunks
9980 - * An incomplete chunk to end off with
9981 - *
9982 - * Curve-balls: the first chunk might also be the last chunk.
9983 - */
9984 + if(background)
9985 + maxThreshold = dev->param.nChunksPerBlock/2;
9986 + else
9987 + maxThreshold = dev->param.nChunksPerBlock/8;
9988
9989 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
9990 - int nBytes)
9991 -{
9992 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
9993 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
9994
9995 - int chunk;
9996 - __u32 start;
9997 - int nToCopy;
9998 - int n = nBytes;
9999 - int nDone = 0;
10000 - yaffs_ChunkCache *cache;
10001 + threshold = background ?
10002 + (dev->gcNotDone + 2) * 2 : 0;
10003 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10004 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10005 + if(threshold > maxThreshold)
10006 + threshold = maxThreshold;
10007
10008 - yaffs_Device *dev;
10009 + iterations = nBlocks / 16 + 1;
10010 + if (iterations > 100)
10011 + iterations = 100;
10012 + }
10013
10014 - dev = in->myDev;
10015 + for (i = 0;
10016 + i < iterations &&
10017 + (dev->gcDirtiest < 1 ||
10018 + dev->gcPagesInUse > YAFFS_GC_GOOD_ENOUGH);
10019 + i++) {
10020 + dev->gcBlockFinder++;
10021 + if (dev->gcBlockFinder < dev->internalStartBlock ||
10022 + dev->gcBlockFinder > dev->internalEndBlock)
10023 + dev->gcBlockFinder = dev->internalStartBlock;
10024
10025 - while (n > 0) {
10026 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10027 - /* start = offset % dev->nDataBytesPerChunk; */
10028 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10029 - chunk++;
10030 + bi = yaffs_GetBlockInfo(dev, dev->gcBlockFinder);
10031
10032 - /* OK now check for the curveball where the start and end are in
10033 - * the same chunk.
10034 - */
10035 - if ((start + n) < dev->nDataBytesPerChunk)
10036 - nToCopy = n;
10037 - else
10038 - nToCopy = dev->nDataBytesPerChunk - start;
10039 + pagesUsed = bi->pagesInUse - bi->softDeletions;
10040
10041 - cache = yaffs_FindChunkCache(in, chunk);
10042 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
10043 + pagesUsed < dev->param.nChunksPerBlock &&
10044 + (dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) &&
10045 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
10046 + dev->gcDirtiest = dev->gcBlockFinder;
10047 + dev->gcPagesInUse = pagesUsed;
10048 + }
10049 + }
10050
10051 - /* If the chunk is already in the cache or it is less than a whole chunk
10052 - * or we're using inband tags then use the cache (if there is caching)
10053 - * else bypass the cache.
10054 - */
10055 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10056 - if (dev->nShortOpCaches > 0) {
10057 + if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold)
10058 + selected = dev->gcDirtiest;
10059 + }
10060 +
10061 + /*
10062 + * If nothing has been selected for a while, try selecting the oldest dirty
10063 + * because that's gumming up the works.
10064 + */
10065
10066 - /* If we can't find the data in the cache, then load it up. */
10067 + if(!selected && dev->param.isYaffs2 &&
10068 + dev->gcNotDone >= ( background ? 10 : 20)){
10069 + yaffs2_FindOldestDirtySequence(dev);
10070 + if(dev->oldestDirtyBlock > 0) {
10071 + selected = dev->oldestDirtyBlock;
10072 + dev->gcDirtiest = selected;
10073 + dev->oldestDirtyGCs++;
10074 + bi = yaffs_GetBlockInfo(dev, selected);
10075 + dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions;
10076 + } else
10077 + dev->gcNotDone = 0;
10078 + }
10079
10080 - if (!cache) {
10081 - cache = yaffs_GrabChunkCache(in->myDev);
10082 - cache->object = in;
10083 - cache->chunkId = chunk;
10084 - cache->dirty = 0;
10085 - cache->locked = 0;
10086 - yaffs_ReadChunkDataFromObject(in, chunk,
10087 - cache->
10088 - data);
10089 - cache->nBytes = 0;
10090 - }
10091 + if(selected){
10092 + T(YAFFS_TRACE_GC,
10093 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10094 + selected,
10095 + dev->param.nChunksPerBlock - dev->gcPagesInUse,
10096 + prioritised));
10097 +
10098 + dev->nGCBlocks++;
10099 + if(background)
10100 + dev->backgroundGCs++;
10101 +
10102 + dev->gcDirtiest = 0;
10103 + dev->gcPagesInUse = 0;
10104 + dev->gcNotDone = 0;
10105 + if(dev->refreshSkip > 0)
10106 + dev->refreshSkip--;
10107 + } else{
10108 + dev->gcNotDone++;
10109 + T(YAFFS_TRACE_GC,
10110 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10111 + dev->gcBlockFinder, dev->gcNotDone,
10112 + threshold,
10113 + dev->gcDirtiest, dev->gcPagesInUse,
10114 + dev->oldestDirtyBlock,
10115 + background ? " bg" : ""));
10116 + }
10117
10118 - yaffs_UseChunkCache(dev, cache, 0);
10119 + return selected;
10120 +}
10121
10122 - cache->locked = 1;
10123 +/* New garbage collector
10124 + * If we're very low on erased blocks then we do aggressive garbage collection
10125 + * otherwise we do "leasurely" garbage collection.
10126 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10127 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10128 + *
10129 + * The idea is to help clear out space in a more spread-out manner.
10130 + * Dunno if it really does anything useful.
10131 + */
10132 +static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
10133 +{
10134 + int aggressive = 0;
10135 + int gcOk = YAFFS_OK;
10136 + int maxTries = 0;
10137 + int minErased;
10138 + int erasedChunks;
10139 + int checkpointBlockAdjust;
10140
10141 + if(dev->param.gcControl &&
10142 + (dev->param.gcControl(dev) & 1) == 0)
10143 + return YAFFS_OK;
10144
10145 - memcpy(buffer, &cache->data[start], nToCopy);
10146 + if (dev->gcDisable) {
10147 + /* Bail out so we don't get recursive gc */
10148 + return YAFFS_OK;
10149 + }
10150
10151 - cache->locked = 0;
10152 - } else {
10153 - /* Read into the local buffer then copy..*/
10154 + /* This loop should pass the first time.
10155 + * We'll only see looping here if the collection does not increase space.
10156 + */
10157
10158 - __u8 *localBuffer =
10159 - yaffs_GetTempBuffer(dev, __LINE__);
10160 - yaffs_ReadChunkDataFromObject(in, chunk,
10161 - localBuffer);
10162 + do {
10163 + maxTries++;
10164
10165 - memcpy(buffer, &localBuffer[start], nToCopy);
10166 + checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev);
10167
10168 + minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1;
10169 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10170
10171 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10172 - __LINE__);
10173 + /* If we need a block soon then do aggressive gc.*/
10174 + if (dev->nErasedBlocks < minErased)
10175 + aggressive = 1;
10176 + else {
10177 + if(!background && erasedChunks > (dev->nFreeChunks / 4))
10178 + break;
10179 +
10180 + if(dev->gcSkip > 20)
10181 + dev->gcSkip = 20;
10182 + if(erasedChunks < dev->nFreeChunks/2 ||
10183 + dev->gcSkip < 1 ||
10184 + background)
10185 + aggressive = 0;
10186 + else {
10187 + dev->gcSkip--;
10188 + break;
10189 }
10190 + }
10191
10192 - } else {
10193 + dev->gcSkip = 5;
10194
10195 - /* A full chunk. Read directly into the supplied buffer. */
10196 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10197 + /* If we don't already have a block being gc'd then see if we should start another */
10198
10199 + if (dev->gcBlock < 1 && !aggressive) {
10200 + dev->gcBlock = yaffs2_FindRefreshBlock(dev);
10201 + dev->gcChunk = 0;
10202 + dev->nCleanups=0;
10203 + }
10204 + if (dev->gcBlock < 1) {
10205 + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
10206 + dev->gcChunk = 0;
10207 + dev->nCleanups=0;
10208 }
10209
10210 - n -= nToCopy;
10211 - offset += nToCopy;
10212 - buffer += nToCopy;
10213 - nDone += nToCopy;
10214 + if (dev->gcBlock > 0) {
10215 + dev->allGCs++;
10216 + if (!aggressive)
10217 + dev->passiveGCs++;
10218
10219 - }
10220 + T(YAFFS_TRACE_GC,
10221 + (TSTR
10222 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10223 + dev->nErasedBlocks, aggressive));
10224
10225 - return nDone;
10226 + gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive);
10227 + }
10228 +
10229 + if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) {
10230 + T(YAFFS_TRACE_GC,
10231 + (TSTR
10232 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10233 + TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock));
10234 + }
10235 + } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) &&
10236 + (dev->gcBlock > 0) &&
10237 + (maxTries < 2));
10238 +
10239 + return aggressive ? gcOk : YAFFS_OK;
10240 }
10241
10242 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10243 - int nBytes, int writeThrough)
10244 +/*
10245 + * yaffs_BackgroundGarbageCollect()
10246 + * Garbage collects. Intended to be called from a background thread.
10247 + * Returns non-zero if at least half the free chunks are erased.
10248 + */
10249 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency)
10250 {
10251 + int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10252
10253 - int chunk;
10254 - __u32 start;
10255 - int nToCopy;
10256 - int n = nBytes;
10257 - int nDone = 0;
10258 - int nToWriteBack;
10259 - int startOfWrite = offset;
10260 - int chunkWritten = 0;
10261 - __u32 nBytesRead;
10262 - __u32 chunkStart;
10263 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10264
10265 - yaffs_Device *dev;
10266 + yaffs_CheckGarbageCollection(dev, 1);
10267 + return erasedChunks > dev->nFreeChunks/2;
10268 +}
10269
10270 - dev = in->myDev;
10271 +/*------------------------- TAGS --------------------------------*/
10272
10273 - while (n > 0 && chunkWritten >= 0) {
10274 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10275 - /* start = offset % dev->nDataBytesPerChunk; */
10276 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10277 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
10278 + int chunkInObject)
10279 +{
10280 + return (tags->chunkId == chunkInObject &&
10281 + tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
10282
10283 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10284 - start >= dev->nDataBytesPerChunk) {
10285 - T(YAFFS_TRACE_ERROR, (
10286 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10287 - TENDSTR),
10288 - (int)offset, chunk, start));
10289 - }
10290 - chunk++;
10291 +}
10292
10293 - /* OK now check for the curveball where the start and end are in
10294 - * the same chunk.
10295 - */
10296
10297 - if ((start + n) < dev->nDataBytesPerChunk) {
10298 - nToCopy = n;
10299 +/*-------------------- Data file manipulation -----------------*/
10300
10301 - /* Now folks, to calculate how many bytes to write back....
10302 - * If we're overwriting and not writing to then end of file then
10303 - * we need to write back as much as was there before.
10304 - */
10305 +static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
10306 + yaffs_ExtendedTags *tags)
10307 +{
10308 + /*Get the Tnode, then get the level 0 offset chunk offset */
10309 + yaffs_Tnode *tn;
10310 + int theChunk = -1;
10311 + yaffs_ExtendedTags localTags;
10312 + int retVal = -1;
10313
10314 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10315 + yaffs_Device *dev = in->myDev;
10316
10317 - if (chunkStart > in->variant.fileVariant.fileSize)
10318 - nBytesRead = 0; /* Past end of file */
10319 - else
10320 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10321 + if (!tags) {
10322 + /* Passed a NULL, so use our own tags space */
10323 + tags = &localTags;
10324 + }
10325
10326 - if (nBytesRead > dev->nDataBytesPerChunk)
10327 - nBytesRead = dev->nDataBytesPerChunk;
10328 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10329
10330 - nToWriteBack =
10331 - (nBytesRead >
10332 - (start + n)) ? nBytesRead : (start + n);
10333 + if (tn) {
10334 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10335
10336 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10337 - YBUG();
10338 + retVal =
10339 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10340 + chunkInInode);
10341 + }
10342 + return retVal;
10343 +}
10344
10345 - } else {
10346 - nToCopy = dev->nDataBytesPerChunk - start;
10347 - nToWriteBack = dev->nDataBytesPerChunk;
10348 - }
10349 +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
10350 + yaffs_ExtendedTags *tags)
10351 +{
10352 + /* Get the Tnode, then get the level 0 offset chunk offset */
10353 + yaffs_Tnode *tn;
10354 + int theChunk = -1;
10355 + yaffs_ExtendedTags localTags;
10356
10357 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10358 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10359 - * or we're using inband tags, so we want to use the cache buffers.
10360 - */
10361 - if (dev->nShortOpCaches > 0) {
10362 - yaffs_ChunkCache *cache;
10363 - /* If we can't find the data in the cache, then load the cache */
10364 - cache = yaffs_FindChunkCache(in, chunk);
10365 + yaffs_Device *dev = in->myDev;
10366 + int retVal = -1;
10367
10368 - if (!cache
10369 - && yaffs_CheckSpaceForAllocation(in->
10370 - myDev)) {
10371 - cache = yaffs_GrabChunkCache(in->myDev);
10372 - cache->object = in;
10373 - cache->chunkId = chunk;
10374 - cache->dirty = 0;
10375 - cache->locked = 0;
10376 - yaffs_ReadChunkDataFromObject(in, chunk,
10377 - cache->
10378 - data);
10379 - } else if (cache &&
10380 - !cache->dirty &&
10381 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10382 - /* Drop the cache if it was a read cache item and
10383 - * no space check has been made for it.
10384 - */
10385 - cache = NULL;
10386 - }
10387 + if (!tags) {
10388 + /* Passed a NULL, so use our own tags space */
10389 + tags = &localTags;
10390 + }
10391
10392 - if (cache) {
10393 - yaffs_UseChunkCache(dev, cache, 1);
10394 - cache->locked = 1;
10395 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10396
10397 + if (tn) {
10398
10399 - memcpy(&cache->data[start], buffer,
10400 - nToCopy);
10401 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10402
10403 + retVal =
10404 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10405 + chunkInInode);
10406
10407 - cache->locked = 0;
10408 - cache->nBytes = nToWriteBack;
10409 + /* Delete the entry in the filestructure (if found) */
10410 + if (retVal != -1)
10411 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
10412 + }
10413
10414 - if (writeThrough) {
10415 - chunkWritten =
10416 - yaffs_WriteChunkDataToObject
10417 - (cache->object,
10418 - cache->chunkId,
10419 - cache->data, cache->nBytes,
10420 - 1);
10421 - cache->dirty = 0;
10422 - }
10423 + return retVal;
10424 +}
10425
10426 - } else {
10427 - chunkWritten = -1; /* fail the write */
10428 - }
10429 - } else {
10430 - /* An incomplete start or end chunk (or maybe both start and end chunk)
10431 - * Read into the local buffer then copy, then copy over and write back.
10432 - */
10433
10434 - __u8 *localBuffer =
10435 - yaffs_GetTempBuffer(dev, __LINE__);
10436 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
10437 + int chunkInNAND, int inScan)
10438 +{
10439 + /* NB inScan is zero unless scanning.
10440 + * For forward scanning, inScan is > 0;
10441 + * for backward scanning inScan is < 0
10442 + *
10443 + * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
10444 + */
10445 +
10446 + yaffs_Tnode *tn;
10447 + yaffs_Device *dev = in->myDev;
10448 + int existingChunk;
10449 + yaffs_ExtendedTags existingTags;
10450 + yaffs_ExtendedTags newTags;
10451 + unsigned existingSerial, newSerial;
10452 +
10453 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
10454 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
10455 + * If it is not during Scanning then something went wrong!
10456 + */
10457 + if (!inScan) {
10458 + T(YAFFS_TRACE_ERROR,
10459 + (TSTR
10460 + ("yaffs tragedy:attempt to put data chunk into a non-file"
10461 + TENDSTR)));
10462 + YBUG();
10463 + }
10464
10465 - yaffs_ReadChunkDataFromObject(in, chunk,
10466 - localBuffer);
10467 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
10468 + return YAFFS_OK;
10469 + }
10470
10471 + tn = yaffs_AddOrFindLevel0Tnode(dev,
10472 + &in->variant.fileVariant,
10473 + chunkInInode,
10474 + NULL);
10475 + if (!tn)
10476 + return YAFFS_FAIL;
10477 +
10478 + if(!chunkInNAND)
10479 + /* Dummy insert, bail now */
10480 + return YAFFS_OK;
10481
10482 + existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10483
10484 - memcpy(&localBuffer[start], buffer, nToCopy);
10485 + if (inScan != 0) {
10486 + /* If we're scanning then we need to test for duplicates
10487 + * NB This does not need to be efficient since it should only ever
10488 + * happen when the power fails during a write, then only one
10489 + * chunk should ever be affected.
10490 + *
10491 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
10492 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
10493 + */
10494
10495 - chunkWritten =
10496 - yaffs_WriteChunkDataToObject(in, chunk,
10497 - localBuffer,
10498 - nToWriteBack,
10499 - 0);
10500 + if (existingChunk > 0) {
10501 + /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1
10502 + * thus we have to do a FindChunkInFile to get the real chunk id.
10503 + *
10504 + * We have a duplicate now we need to decide which one to use:
10505 + *
10506 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
10507 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
10508 + * YAFFS1: Get both sets of tags and compare serial numbers.
10509 + */
10510
10511 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10512 - __LINE__);
10513 + if (inScan > 0) {
10514 + /* Only do this for forward scanning */
10515 + yaffs_ReadChunkWithTagsFromNAND(dev,
10516 + chunkInNAND,
10517 + NULL, &newTags);
10518
10519 + /* Do a proper find */
10520 + existingChunk =
10521 + yaffs_FindChunkInFile(in, chunkInInode,
10522 + &existingTags);
10523 }
10524
10525 - } else {
10526 - /* A full chunk. Write directly from the supplied buffer. */
10527 + if (existingChunk <= 0) {
10528 + /*Hoosterman - how did this happen? */
10529
10530 + T(YAFFS_TRACE_ERROR,
10531 + (TSTR
10532 + ("yaffs tragedy: existing chunk < 0 in scan"
10533 + TENDSTR)));
10534
10535 + }
10536
10537 - chunkWritten =
10538 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
10539 - dev->nDataBytesPerChunk,
10540 - 0);
10541 + /* NB The deleted flags should be false, otherwise the chunks will
10542 + * not be loaded during a scan
10543 + */
10544
10545 - /* Since we've overwritten the cached data, we better invalidate it. */
10546 - yaffs_InvalidateChunkCache(in, chunk);
10547 - }
10548 + if (inScan > 0) {
10549 + newSerial = newTags.serialNumber;
10550 + existingSerial = existingTags.serialNumber;
10551 + }
10552
10553 - if (chunkWritten >= 0) {
10554 - n -= nToCopy;
10555 - offset += nToCopy;
10556 - buffer += nToCopy;
10557 - nDone += nToCopy;
10558 + if ((inScan > 0) &&
10559 + (existingChunk <= 0 ||
10560 + ((existingSerial + 1) & 3) == newSerial)) {
10561 + /* Forward scanning.
10562 + * Use new
10563 + * Delete the old one and drop through to update the tnode
10564 + */
10565 + yaffs_DeleteChunk(dev, existingChunk, 1,
10566 + __LINE__);
10567 + } else {
10568 + /* Backward scanning or we want to use the existing one
10569 + * Use existing.
10570 + * Delete the new one and return early so that the tnode isn't changed
10571 + */
10572 + yaffs_DeleteChunk(dev, chunkInNAND, 1,
10573 + __LINE__);
10574 + return YAFFS_OK;
10575 + }
10576 }
10577
10578 }
10579
10580 - /* Update file object */
10581 -
10582 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
10583 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
10584 + if (existingChunk == 0)
10585 + in->nDataChunks++;
10586
10587 - in->dirty = 1;
10588 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
10589
10590 - return nDone;
10591 + return YAFFS_OK;
10592 }
10593
10594 +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
10595 + __u8 *buffer)
10596 +{
10597 + int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
10598
10599 -/* ---------------------- File resizing stuff ------------------ */
10600 + if (chunkInNAND >= 0)
10601 + return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
10602 + buffer, NULL);
10603 + else {
10604 + T(YAFFS_TRACE_NANDACCESS,
10605 + (TSTR("Chunk %d not found zero instead" TENDSTR),
10606 + chunkInNAND));
10607 + /* get sane (zero) data if you read a hole */
10608 + memset(buffer, 0, in->myDev->nDataBytesPerChunk);
10609 + return 0;
10610 + }
10611
10612 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
10613 -{
10614 +}
10615
10616 - yaffs_Device *dev = in->myDev;
10617 - int oldFileSize = in->variant.fileVariant.fileSize;
10618 +void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
10619 +{
10620 + int block;
10621 + int page;
10622 + yaffs_ExtendedTags tags;
10623 + yaffs_BlockInfo *bi;
10624
10625 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
10626 + if (chunkId <= 0)
10627 + return;
10628
10629 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
10630 - dev->nDataBytesPerChunk;
10631 - int i;
10632 - int chunkId;
10633 + dev->nDeletions++;
10634 + block = chunkId / dev->param.nChunksPerBlock;
10635 + page = chunkId % dev->param.nChunksPerBlock;
10636
10637 - /* Delete backwards so that we don't end up with holes if
10638 - * power is lost part-way through the operation.
10639 - */
10640 - for (i = lastDel; i >= startDel; i--) {
10641 - /* NB this could be optimised somewhat,
10642 - * eg. could retrieve the tags and write them without
10643 - * using yaffs_DeleteChunk
10644 - */
10645
10646 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
10647 - if (chunkId > 0) {
10648 - if (chunkId <
10649 - (dev->internalStartBlock * dev->nChunksPerBlock)
10650 - || chunkId >=
10651 - ((dev->internalEndBlock +
10652 - 1) * dev->nChunksPerBlock)) {
10653 - T(YAFFS_TRACE_ALWAYS,
10654 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
10655 - chunkId, i));
10656 - } else {
10657 - in->nDataChunks--;
10658 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
10659 - }
10660 - }
10661 - }
10662 + if (!yaffs_CheckChunkBit(dev, block, page))
10663 + T(YAFFS_TRACE_VERIFY,
10664 + (TSTR("Deleting invalid chunk %d"TENDSTR),
10665 + chunkId));
10666
10667 -}
10668 + bi = yaffs_GetBlockInfo(dev, block);
10669 +
10670 + yaffs2_UpdateOldestDirtySequence(dev, block, bi);
10671
10672 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
10673 -{
10674 + T(YAFFS_TRACE_DELETION,
10675 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
10676
10677 - int oldFileSize = in->variant.fileVariant.fileSize;
10678 - __u32 newSizeOfPartialChunk;
10679 - int newFullChunks;
10680 + if (!dev->param.isYaffs2 && markNAND &&
10681 + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
10682
10683 - yaffs_Device *dev = in->myDev;
10684 + yaffs_InitialiseTags(&tags);
10685
10686 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
10687 + tags.chunkDeleted = 1;
10688
10689 - yaffs_FlushFilesChunkCache(in);
10690 - yaffs_InvalidateWholeChunkCache(in);
10691 + yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
10692 + yaffs_HandleUpdateChunk(dev, chunkId, &tags);
10693 + } else {
10694 + dev->nUnmarkedDeletions++;
10695 + }
10696
10697 - yaffs_CheckGarbageCollection(dev);
10698 + /* Pull out of the management area.
10699 + * If the whole block became dirty, this will kick off an erasure.
10700 + */
10701 + if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
10702 + bi->blockState == YAFFS_BLOCK_STATE_FULL ||
10703 + bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
10704 + bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
10705 + dev->nFreeChunks++;
10706
10707 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
10708 - return YAFFS_FAIL;
10709 + yaffs_ClearChunkBit(dev, block, page);
10710
10711 - if (newSize == oldFileSize)
10712 - return YAFFS_OK;
10713 + bi->pagesInUse--;
10714
10715 - if (newSize < oldFileSize) {
10716 + if (bi->pagesInUse == 0 &&
10717 + !bi->hasShrinkHeader &&
10718 + bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
10719 + bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
10720 + yaffs_BlockBecameDirty(dev, block);
10721 + }
10722
10723 - yaffs_PruneResizedChunks(in, newSize);
10724 + }
10725
10726 - if (newSizeOfPartialChunk != 0) {
10727 - int lastChunk = 1 + newFullChunks;
10728 +}
10729
10730 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
10731 +static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
10732 + const __u8 *buffer, int nBytes,
10733 + int useReserve)
10734 +{
10735 + /* Find old chunk Need to do this to get serial number
10736 + * Write new one and patch into tree.
10737 + * Invalidate old tags.
10738 + */
10739
10740 - /* Got to read and rewrite the last chunk with its new size and zero pad */
10741 - yaffs_ReadChunkDataFromObject(in, lastChunk,
10742 - localBuffer);
10743 + int prevChunkId;
10744 + yaffs_ExtendedTags prevTags;
10745
10746 - memset(localBuffer + newSizeOfPartialChunk, 0,
10747 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
10748 + int newChunkId;
10749 + yaffs_ExtendedTags newTags;
10750
10751 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
10752 - newSizeOfPartialChunk, 1);
10753 + yaffs_Device *dev = in->myDev;
10754
10755 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
10756 - }
10757 + yaffs_CheckGarbageCollection(dev,0);
10758
10759 - in->variant.fileVariant.fileSize = newSize;
10760 + /* Get the previous chunk at this location in the file if it exists.
10761 + * If it does not exist then put a zero into the tree. This creates
10762 + * the tnode now, rather than later when it is harder to clean up.
10763 + */
10764 + prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
10765 + if(prevChunkId < 1 &&
10766 + !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0))
10767 + return 0;
10768
10769 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
10770 - } else {
10771 - /* newsSize > oldFileSize */
10772 - in->variant.fileVariant.fileSize = newSize;
10773 - }
10774 + /* Set up new tags */
10775 + yaffs_InitialiseTags(&newTags);
10776
10777 + newTags.chunkId = chunkInInode;
10778 + newTags.objectId = in->objectId;
10779 + newTags.serialNumber =
10780 + (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
10781 + newTags.byteCount = nBytes;
10782
10783 - /* Write a new object header.
10784 - * show we've shrunk the file, if need be
10785 - * Do this only if the file is not in the deleted directories.
10786 - */
10787 - if (in->parent &&
10788 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
10789 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
10790 - yaffs_UpdateObjectHeader(in, NULL, 0,
10791 - (newSize < oldFileSize) ? 1 : 0, 0);
10792 + if (nBytes < 1 || nBytes > dev->param.totalBytesPerChunk) {
10793 + T(YAFFS_TRACE_ERROR,
10794 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
10795 + YBUG();
10796 + }
10797 +
10798 +
10799 + newChunkId =
10800 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
10801 + useReserve);
10802
10803 - return YAFFS_OK;
10804 -}
10805 + if (newChunkId > 0) {
10806 + yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
10807
10808 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
10809 -{
10810 - obj = yaffs_GetEquivalentObject(obj);
10811 + if (prevChunkId > 0)
10812 + yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
10813
10814 - switch (obj->variantType) {
10815 - case YAFFS_OBJECT_TYPE_FILE:
10816 - return obj->variant.fileVariant.fileSize;
10817 - case YAFFS_OBJECT_TYPE_SYMLINK:
10818 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
10819 - default:
10820 - return 0;
10821 + yaffs_VerifyFileSanity(in);
10822 }
10823 + return newChunkId;
10824 +
10825 }
10826
10827 +/* UpdateObjectHeader updates the header on NAND for an object.
10828 + * If name is not NULL, then that new name is used.
10829 + */
10830 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
10831 + int isShrink, int shadows, yaffs_XAttrMod *xmod)
10832 +{
10833
10834 + yaffs_BlockInfo *bi;
10835
10836 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
10837 -{
10838 - int retVal;
10839 - if (in->dirty) {
10840 - yaffs_FlushFilesChunkCache(in);
10841 - if (updateTime) {
10842 -#ifdef CONFIG_YAFFS_WINCE
10843 - yfsd_WinFileTimeNow(in->win_mtime);
10844 -#else
10845 + yaffs_Device *dev = in->myDev;
10846
10847 - in->yst_mtime = Y_CURRENT_TIME;
10848 + int prevChunkId;
10849 + int retVal = 0;
10850 + int result = 0;
10851
10852 -#endif
10853 - }
10854 + int newChunkId;
10855 + yaffs_ExtendedTags newTags;
10856 + yaffs_ExtendedTags oldTags;
10857 + const YCHAR *alias = NULL;
10858
10859 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
10860 - 0) ? YAFFS_OK : YAFFS_FAIL;
10861 - } else {
10862 - retVal = YAFFS_OK;
10863 - }
10864 + __u8 *buffer = NULL;
10865 + YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
10866
10867 - return retVal;
10868 + yaffs_ObjectHeader *oh = NULL;
10869
10870 -}
10871 + yaffs_strcpy(oldName, _Y("silly old name"));
10872
10873 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
10874 -{
10875
10876 - /* First off, invalidate the file's data in the cache, without flushing. */
10877 - yaffs_InvalidateWholeChunkCache(in);
10878 + if (!in->fake ||
10879 + in == dev->rootDir || /* The rootDir should also be saved */
10880 + force || xmod) {
10881
10882 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
10883 - /* Move to the unlinked directory so we have a record that it was deleted. */
10884 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
10885 + yaffs_CheckGarbageCollection(dev,0);
10886 + yaffs_CheckObjectDetailsLoaded(in);
10887
10888 - }
10889 + buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
10890 + oh = (yaffs_ObjectHeader *) buffer;
10891
10892 - yaffs_RemoveObjectFromDirectory(in);
10893 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
10894 - in->hdrChunk = 0;
10895 + prevChunkId = in->hdrChunk;
10896
10897 - yaffs_FreeObject(in);
10898 - return YAFFS_OK;
10899 + if (prevChunkId > 0) {
10900 + result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
10901 + buffer, &oldTags);
10902
10903 -}
10904 + yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
10905
10906 -/* yaffs_DeleteFile deletes the whole file data
10907 - * and the inode associated with the file.
10908 - * It does not delete the links associated with the file.
10909 - */
10910 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
10911 -{
10912 + memcpy(oldName, oh->name, sizeof(oh->name));
10913 + memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader));
10914 + } else
10915 + memset(buffer, 0xFF, dev->nDataBytesPerChunk);
10916
10917 - int retVal;
10918 - int immediateDeletion = 0;
10919 + oh->type = in->variantType;
10920 + oh->yst_mode = in->yst_mode;
10921 + oh->shadowsObject = oh->inbandShadowsObject = shadows;
10922
10923 -#ifdef __KERNEL__
10924 - if (!in->myInode)
10925 - immediateDeletion = 1;
10926 +#ifdef CONFIG_YAFFS_WINCE
10927 + oh->win_atime[0] = in->win_atime[0];
10928 + oh->win_ctime[0] = in->win_ctime[0];
10929 + oh->win_mtime[0] = in->win_mtime[0];
10930 + oh->win_atime[1] = in->win_atime[1];
10931 + oh->win_ctime[1] = in->win_ctime[1];
10932 + oh->win_mtime[1] = in->win_mtime[1];
10933 #else
10934 - if (in->inUse <= 0)
10935 - immediateDeletion = 1;
10936 + oh->yst_uid = in->yst_uid;
10937 + oh->yst_gid = in->yst_gid;
10938 + oh->yst_atime = in->yst_atime;
10939 + oh->yst_mtime = in->yst_mtime;
10940 + oh->yst_ctime = in->yst_ctime;
10941 + oh->yst_rdev = in->yst_rdev;
10942 #endif
10943 + if (in->parent)
10944 + oh->parentObjectId = in->parent->objectId;
10945 + else
10946 + oh->parentObjectId = 0;
10947
10948 - if (immediateDeletion) {
10949 - retVal =
10950 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
10951 - _Y("deleted"), 0, 0);
10952 - T(YAFFS_TRACE_TRACING,
10953 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
10954 - in->objectId));
10955 - in->deleted = 1;
10956 - in->myDev->nDeletedFiles++;
10957 - if (1 || in->myDev->isYaffs2)
10958 - yaffs_ResizeFile(in, 0);
10959 - yaffs_SoftDeleteFile(in);
10960 - } else {
10961 - retVal =
10962 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
10963 - _Y("unlinked"), 0, 0);
10964 - }
10965 + if (name && *name) {
10966 + memset(oh->name, 0, sizeof(oh->name));
10967 + yaffs_LoadObjectHeaderFromName(dev,oh->name,name);
10968 + } else if (prevChunkId > 0)
10969 + memcpy(oh->name, oldName, sizeof(oh->name));
10970 + else
10971 + memset(oh->name, 0, sizeof(oh->name));
10972
10973 + oh->isShrink = isShrink;
10974
10975 - return retVal;
10976 -}
10977 + switch (in->variantType) {
10978 + case YAFFS_OBJECT_TYPE_UNKNOWN:
10979 + /* Should not happen */
10980 + break;
10981 + case YAFFS_OBJECT_TYPE_FILE:
10982 + oh->fileSize =
10983 + (oh->parentObjectId == YAFFS_OBJECTID_DELETED
10984 + || oh->parentObjectId ==
10985 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
10986 + fileVariant.fileSize;
10987 + break;
10988 + case YAFFS_OBJECT_TYPE_HARDLINK:
10989 + oh->equivalentObjectId =
10990 + in->variant.hardLinkVariant.equivalentObjectId;
10991 + break;
10992 + case YAFFS_OBJECT_TYPE_SPECIAL:
10993 + /* Do nothing */
10994 + break;
10995 + case YAFFS_OBJECT_TYPE_DIRECTORY:
10996 + /* Do nothing */
10997 + break;
10998 + case YAFFS_OBJECT_TYPE_SYMLINK:
10999 + alias = in->variant.symLinkVariant.alias;
11000 + if(!alias)
11001 + alias = _Y("no alias");
11002 + yaffs_strncpy(oh->alias,
11003 + alias,
11004 + YAFFS_MAX_ALIAS_LENGTH);
11005 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11006 + break;
11007 + }
11008
11009 -int yaffs_DeleteFile(yaffs_Object *in)
11010 -{
11011 - int retVal = YAFFS_OK;
11012 - int deleted = in->deleted;
11013 + /* process any xattrib modifications */
11014 + if(xmod)
11015 + yaffs_ApplyXMod(in, (char *)buffer, xmod);
11016
11017 - yaffs_ResizeFile(in, 0);
11018
11019 - if (in->nDataChunks > 0) {
11020 - /* Use soft deletion if there is data in the file.
11021 - * That won't be the case if it has been resized to zero.
11022 - */
11023 - if (!in->unlinked)
11024 - retVal = yaffs_UnlinkFileIfNeeded(in);
11025 + /* Tags */
11026 + yaffs_InitialiseTags(&newTags);
11027 + in->serial++;
11028 + newTags.chunkId = 0;
11029 + newTags.objectId = in->objectId;
11030 + newTags.serialNumber = in->serial;
11031
11032 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11033 - in->deleted = 1;
11034 - deleted = 1;
11035 - in->myDev->nDeletedFiles++;
11036 - yaffs_SoftDeleteFile(in);
11037 - }
11038 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11039 - } else {
11040 - /* The file has no data chunks so we toss it immediately */
11041 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11042 - in->variant.fileVariant.top = NULL;
11043 - yaffs_DoGenericObjectDeletion(in);
11044 + /* Add extra info for file header */
11045
11046 - return YAFFS_OK;
11047 - }
11048 -}
11049 + newTags.extraHeaderInfoAvailable = 1;
11050 + newTags.extraParentObjectId = oh->parentObjectId;
11051 + newTags.extraFileLength = oh->fileSize;
11052 + newTags.extraIsShrinkHeader = oh->isShrink;
11053 + newTags.extraEquivalentObjectId = oh->equivalentObjectId;
11054 + newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
11055 + newTags.extraObjectType = in->variantType;
11056
11057 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11058 -{
11059 - /* First check that the directory is empty. */
11060 - if (ylist_empty(&in->variant.directoryVariant.children))
11061 - return yaffs_DoGenericObjectDeletion(in);
11062 + yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
11063
11064 - return YAFFS_FAIL;
11065 + /* Create new chunk in NAND */
11066 + newChunkId =
11067 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
11068 + (prevChunkId > 0) ? 1 : 0);
11069
11070 -}
11071 + if (newChunkId >= 0) {
11072
11073 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11074 -{
11075 - YFREE(in->variant.symLinkVariant.alias);
11076 + in->hdrChunk = newChunkId;
11077
11078 - return yaffs_DoGenericObjectDeletion(in);
11079 -}
11080 + if (prevChunkId > 0) {
11081 + yaffs_DeleteChunk(dev, prevChunkId, 1,
11082 + __LINE__);
11083 + }
11084
11085 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11086 -{
11087 - /* remove this hardlink from the list assocaited with the equivalent
11088 - * object
11089 - */
11090 - ylist_del_init(&in->hardLinks);
11091 - return yaffs_DoGenericObjectDeletion(in);
11092 -}
11093 + if (!yaffs_ObjectHasCachedWriteData(in))
11094 + in->dirty = 0;
11095 +
11096 + /* If this was a shrink, then mark the block that the chunk lives on */
11097 + if (isShrink) {
11098 + bi = yaffs_GetBlockInfo(in->myDev,
11099 + newChunkId / in->myDev->param.nChunksPerBlock);
11100 + bi->hasShrinkHeader = 1;
11101 + }
11102 +
11103 + }
11104 +
11105 + retVal = newChunkId;
11106
11107 -int yaffs_DeleteObject(yaffs_Object *obj)
11108 -{
11109 -int retVal = -1;
11110 - switch (obj->variantType) {
11111 - case YAFFS_OBJECT_TYPE_FILE:
11112 - retVal = yaffs_DeleteFile(obj);
11113 - break;
11114 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11115 - return yaffs_DeleteDirectory(obj);
11116 - break;
11117 - case YAFFS_OBJECT_TYPE_SYMLINK:
11118 - retVal = yaffs_DeleteSymLink(obj);
11119 - break;
11120 - case YAFFS_OBJECT_TYPE_HARDLINK:
11121 - retVal = yaffs_DeleteHardLink(obj);
11122 - break;
11123 - case YAFFS_OBJECT_TYPE_SPECIAL:
11124 - retVal = yaffs_DoGenericObjectDeletion(obj);
11125 - break;
11126 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11127 - retVal = 0;
11128 - break; /* should not happen. */
11129 }
11130
11131 + if (buffer)
11132 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
11133 +
11134 return retVal;
11135 }
11136
11137 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11138 +/*------------------------ Short Operations Cache ----------------------------------------
11139 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11140 + * reads might be short sequential reads, and a lot of writes may be short
11141 + * sequential writes. eg. scanning/writing a jpeg file.
11142 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11143 + * with dumb-as-a-rock code.
11144 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11145 + * buffering.
11146 + *
11147 + * There are a limited number (~10) of cache chunks per device so that we don't
11148 + * need a very intelligent search.
11149 + */
11150 +
11151 +static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
11152 {
11153 + yaffs_Device *dev = obj->myDev;
11154 + int i;
11155 + yaffs_ChunkCache *cache;
11156 + int nCaches = obj->myDev->param.nShortOpCaches;
11157
11158 - int immediateDeletion = 0;
11159 + for (i = 0; i < nCaches; i++) {
11160 + cache = &dev->srCache[i];
11161 + if (cache->object == obj &&
11162 + cache->dirty)
11163 + return 1;
11164 + }
11165
11166 -#ifdef __KERNEL__
11167 - if (!obj->myInode)
11168 - immediateDeletion = 1;
11169 -#else
11170 - if (obj->inUse <= 0)
11171 - immediateDeletion = 1;
11172 -#endif
11173 + return 0;
11174 +}
11175
11176 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11177 - return yaffs_DeleteHardLink(obj);
11178 - } else if (!ylist_empty(&obj->hardLinks)) {
11179 - /* Curve ball: We're unlinking an object that has a hardlink.
11180 - *
11181 - * This problem arises because we are not strictly following
11182 - * The Linux link/inode model.
11183 - *
11184 - * We can't really delete the object.
11185 - * Instead, we do the following:
11186 - * - Select a hardlink.
11187 - * - Unhook it from the hard links
11188 - * - Unhook it from its parent directory (so that the rename can work)
11189 - * - Rename the object to the hardlink's name.
11190 - * - Delete the hardlink
11191 - */
11192
11193 - yaffs_Object *hl;
11194 - int retVal;
11195 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11196 +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
11197 +{
11198 + yaffs_Device *dev = obj->myDev;
11199 + int lowest = -99; /* Stop compiler whining. */
11200 + int i;
11201 + yaffs_ChunkCache *cache;
11202 + int chunkWritten = 0;
11203 + int nCaches = obj->myDev->param.nShortOpCaches;
11204
11205 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11206 + if (nCaches > 0) {
11207 + do {
11208 + cache = NULL;
11209
11210 - ylist_del_init(&hl->hardLinks);
11211 - ylist_del_init(&hl->siblings);
11212 + /* Find the dirty cache for this object with the lowest chunk id. */
11213 + for (i = 0; i < nCaches; i++) {
11214 + if (dev->srCache[i].object == obj &&
11215 + dev->srCache[i].dirty) {
11216 + if (!cache
11217 + || dev->srCache[i].chunkId <
11218 + lowest) {
11219 + cache = &dev->srCache[i];
11220 + lowest = cache->chunkId;
11221 + }
11222 + }
11223 + }
11224
11225 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11226 + if (cache && !cache->locked) {
11227 + /* Write it out and free it up */
11228
11229 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11230 + chunkWritten =
11231 + yaffs_WriteChunkDataToObject(cache->object,
11232 + cache->chunkId,
11233 + cache->data,
11234 + cache->nBytes,
11235 + 1);
11236 + cache->dirty = 0;
11237 + cache->object = NULL;
11238 + }
11239
11240 - if (retVal == YAFFS_OK)
11241 - retVal = yaffs_DoGenericObjectDeletion(hl);
11242 + } while (cache && chunkWritten > 0);
11243
11244 - return retVal;
11245 + if (cache) {
11246 + /* Hoosterman, disk full while writing cache out. */
11247 + T(YAFFS_TRACE_ERROR,
11248 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11249
11250 - } else if (immediateDeletion) {
11251 - switch (obj->variantType) {
11252 - case YAFFS_OBJECT_TYPE_FILE:
11253 - return yaffs_DeleteFile(obj);
11254 - break;
11255 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11256 - return yaffs_DeleteDirectory(obj);
11257 - break;
11258 - case YAFFS_OBJECT_TYPE_SYMLINK:
11259 - return yaffs_DeleteSymLink(obj);
11260 - break;
11261 - case YAFFS_OBJECT_TYPE_SPECIAL:
11262 - return yaffs_DoGenericObjectDeletion(obj);
11263 - break;
11264 - case YAFFS_OBJECT_TYPE_HARDLINK:
11265 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11266 - default:
11267 - return YAFFS_FAIL;
11268 }
11269 - } else
11270 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11271 - _Y("unlinked"), 0, 0);
11272 + }
11273 +
11274 }
11275
11276 +/*yaffs_FlushEntireDeviceCache(dev)
11277 + *
11278 + *
11279 + */
11280
11281 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11282 +void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
11283 {
11284 + yaffs_Object *obj;
11285 + int nCaches = dev->param.nShortOpCaches;
11286 + int i;
11287
11288 - if (obj && obj->unlinkAllowed)
11289 - return yaffs_UnlinkWorker(obj);
11290 + /* Find a dirty object in the cache and flush it...
11291 + * until there are no further dirty objects.
11292 + */
11293 + do {
11294 + obj = NULL;
11295 + for (i = 0; i < nCaches && !obj; i++) {
11296 + if (dev->srCache[i].object &&
11297 + dev->srCache[i].dirty)
11298 + obj = dev->srCache[i].object;
11299
11300 - return YAFFS_FAIL;
11301 + }
11302 + if (obj)
11303 + yaffs_FlushFilesChunkCache(obj);
11304 +
11305 + } while (obj);
11306
11307 }
11308 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11309 +
11310 +
11311 +/* Grab us a cache chunk for use.
11312 + * First look for an empty one.
11313 + * Then look for the least recently used non-dirty one.
11314 + * Then look for the least recently used dirty one...., flush and look again.
11315 + */
11316 +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
11317 {
11318 - yaffs_Object *obj;
11319 + int i;
11320
11321 - obj = yaffs_FindObjectByName(dir, name);
11322 - return yaffs_UnlinkObject(obj);
11323 -}
11324 + if (dev->param.nShortOpCaches > 0) {
11325 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11326 + if (!dev->srCache[i].object)
11327 + return &dev->srCache[i];
11328 + }
11329 + }
11330
11331 -/*----------------------- Initialisation Scanning ---------------------- */
11332 + return NULL;
11333 +}
11334
11335 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11336 - int backwardScanning)
11337 +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
11338 {
11339 - yaffs_Object *obj;
11340 + yaffs_ChunkCache *cache;
11341 + yaffs_Object *theObj;
11342 + int usage;
11343 + int i;
11344 + int pushout;
11345
11346 - if (!backwardScanning) {
11347 - /* Handle YAFFS1 forward scanning case
11348 - * For YAFFS1 we always do the deletion
11349 - */
11350 + if (dev->param.nShortOpCaches > 0) {
11351 + /* Try find a non-dirty one... */
11352
11353 - } else {
11354 - /* Handle YAFFS2 case (backward scanning)
11355 - * If the shadowed object exists then ignore.
11356 - */
11357 - if (yaffs_FindObjectByNumber(dev, objId))
11358 - return;
11359 - }
11360 + cache = yaffs_GrabChunkCacheWorker(dev);
11361
11362 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11363 - * We put it in unlinked dir to be cleaned up after the scanning
11364 - */
11365 - obj =
11366 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11367 - YAFFS_OBJECT_TYPE_FILE);
11368 - if (!obj)
11369 - return;
11370 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11371 - obj->variant.fileVariant.shrinkSize = 0;
11372 - obj->valid = 1; /* So that we don't read any other info for this file */
11373 + if (!cache) {
11374 + /* They were all dirty, find the last recently used object and flush
11375 + * its cache, then find again.
11376 + * NB what's here is not very accurate, we actually flush the object
11377 + * the last recently used page.
11378 + */
11379
11380 -}
11381 + /* With locking we can't assume we can use entry zero */
11382
11383 -typedef struct {
11384 - int seq;
11385 - int block;
11386 -} yaffs_BlockIndex;
11387 + theObj = NULL;
11388 + usage = -1;
11389 + cache = NULL;
11390 + pushout = -1;
11391
11392 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11393 + if (dev->srCache[i].object &&
11394 + !dev->srCache[i].locked &&
11395 + (dev->srCache[i].lastUse < usage || !cache)) {
11396 + usage = dev->srCache[i].lastUse;
11397 + theObj = dev->srCache[i].object;
11398 + cache = &dev->srCache[i];
11399 + pushout = i;
11400 + }
11401 + }
11402
11403 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
11404 -{
11405 - yaffs_Object *hl;
11406 - yaffs_Object *in;
11407 + if (!cache || cache->dirty) {
11408 + /* Flush and try again */
11409 + yaffs_FlushFilesChunkCache(theObj);
11410 + cache = yaffs_GrabChunkCacheWorker(dev);
11411 + }
11412
11413 - while (hardList) {
11414 - hl = hardList;
11415 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
11416 + }
11417 + return cache;
11418 + } else
11419 + return NULL;
11420
11421 - in = yaffs_FindObjectByNumber(dev,
11422 - hl->variant.hardLinkVariant.
11423 - equivalentObjectId);
11424 +}
11425
11426 - if (in) {
11427 - /* Add the hardlink pointers */
11428 - hl->variant.hardLinkVariant.equivalentObject = in;
11429 - ylist_add(&hl->hardLinks, &in->hardLinks);
11430 - } else {
11431 - /* Todo Need to report/handle this better.
11432 - * Got a problem... hardlink to a non-existant object
11433 - */
11434 - hl->variant.hardLinkVariant.equivalentObject = NULL;
11435 - YINIT_LIST_HEAD(&hl->hardLinks);
11436 +/* Find a cached chunk */
11437 +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
11438 + int chunkId)
11439 +{
11440 + yaffs_Device *dev = obj->myDev;
11441 + int i;
11442 + if (dev->param.nShortOpCaches > 0) {
11443 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11444 + if (dev->srCache[i].object == obj &&
11445 + dev->srCache[i].chunkId == chunkId) {
11446 + dev->cacheHits++;
11447
11448 + return &dev->srCache[i];
11449 + }
11450 }
11451 }
11452 + return NULL;
11453 }
11454
11455 +/* Mark the chunk for the least recently used algorithym */
11456 +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
11457 + int isAWrite)
11458 +{
11459 +
11460 + if (dev->param.nShortOpCaches > 0) {
11461 + if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
11462 + /* Reset the cache usages */
11463 + int i;
11464 + for (i = 1; i < dev->param.nShortOpCaches; i++)
11465 + dev->srCache[i].lastUse = 0;
11466
11467 + dev->srLastUse = 0;
11468 + }
11469
11470 + dev->srLastUse++;
11471
11472 + cache->lastUse = dev->srLastUse;
11473
11474 -static int ybicmp(const void *a, const void *b)
11475 -{
11476 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
11477 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
11478 - register int ablock = ((yaffs_BlockIndex *)a)->block;
11479 - register int bblock = ((yaffs_BlockIndex *)b)->block;
11480 - if (aseq == bseq)
11481 - return ablock - bblock;
11482 - else
11483 - return aseq - bseq;
11484 + if (isAWrite)
11485 + cache->dirty = 1;
11486 + }
11487 }
11488
11489 +/* Invalidate a single cache page.
11490 + * Do this when a whole page gets written,
11491 + * ie the short cache for this page is no longer valid.
11492 + */
11493 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
11494 +{
11495 + if (object->myDev->param.nShortOpCaches > 0) {
11496 + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
11497
11498 -struct yaffs_ShadowFixerStruct {
11499 - int objectId;
11500 - int shadowedId;
11501 - struct yaffs_ShadowFixerStruct *next;
11502 -};
11503 -
11504 + if (cache)
11505 + cache->object = NULL;
11506 + }
11507 +}
11508
11509 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
11510 +/* Invalidate all the cache pages associated with this object
11511 + * Do this whenever ther file is deleted or resized.
11512 + */
11513 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
11514 {
11515 - /*
11516 - * Sort out state of unlinked and deleted objects after scanning.
11517 - */
11518 - struct ylist_head *i;
11519 - struct ylist_head *n;
11520 - yaffs_Object *l;
11521 + int i;
11522 + yaffs_Device *dev = in->myDev;
11523
11524 - /* Soft delete all the unlinked files */
11525 - ylist_for_each_safe(i, n,
11526 - &dev->unlinkedDir->variant.directoryVariant.children) {
11527 - if (i) {
11528 - l = ylist_entry(i, yaffs_Object, siblings);
11529 - yaffs_DeleteObject(l);
11530 + if (dev->param.nShortOpCaches > 0) {
11531 + /* Invalidate it. */
11532 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11533 + if (dev->srCache[i].object == in)
11534 + dev->srCache[i].object = NULL;
11535 }
11536 }
11537 +}
11538
11539 - ylist_for_each_safe(i, n,
11540 - &dev->deletedDir->variant.directoryVariant.children) {
11541 - if (i) {
11542 - l = ylist_entry(i, yaffs_Object, siblings);
11543 - yaffs_DeleteObject(l);
11544 - }
11545 - }
11546
11547 -}
11548 +/*--------------------- File read/write ------------------------
11549 + * Read and write have very similar structures.
11550 + * In general the read/write has three parts to it
11551 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
11552 + * Some complete chunks
11553 + * An incomplete chunk to end off with
11554 + *
11555 + * Curve-balls: the first chunk might also be the last chunk.
11556 + */
11557
11558 -static int yaffs_Scan(yaffs_Device *dev)
11559 +int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
11560 + int nBytes)
11561 {
11562 - yaffs_ExtendedTags tags;
11563 - int blk;
11564 - int blockIterator;
11565 - int startIterator;
11566 - int endIterator;
11567 - int result;
11568
11569 int chunk;
11570 - int c;
11571 - int deleted;
11572 - yaffs_BlockState state;
11573 - yaffs_Object *hardList = NULL;
11574 - yaffs_BlockInfo *bi;
11575 - __u32 sequenceNumber;
11576 - yaffs_ObjectHeader *oh;
11577 - yaffs_Object *in;
11578 - yaffs_Object *parent;
11579 -
11580 - int alloc_failed = 0;
11581 + __u32 start;
11582 + int nToCopy;
11583 + int n = nBytes;
11584 + int nDone = 0;
11585 + yaffs_ChunkCache *cache;
11586
11587 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
11588 + yaffs_Device *dev;
11589
11590 + dev = in->myDev;
11591
11592 - __u8 *chunkData;
11593 + while (n > 0) {
11594 + /* chunk = offset / dev->nDataBytesPerChunk + 1; */
11595 + /* start = offset % dev->nDataBytesPerChunk; */
11596 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11597 + chunk++;
11598
11599 + /* OK now check for the curveball where the start and end are in
11600 + * the same chunk.
11601 + */
11602 + if ((start + n) < dev->nDataBytesPerChunk)
11603 + nToCopy = n;
11604 + else
11605 + nToCopy = dev->nDataBytesPerChunk - start;
11606
11607 + cache = yaffs_FindChunkCache(in, chunk);
11608
11609 - T(YAFFS_TRACE_SCAN,
11610 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
11611 - dev->internalStartBlock, dev->internalEndBlock));
11612 -
11613 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
11614 -
11615 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
11616 -
11617 - /* Scan all the blocks to determine their state */
11618 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
11619 - bi = yaffs_GetBlockInfo(dev, blk);
11620 - yaffs_ClearChunkBits(dev, blk);
11621 - bi->pagesInUse = 0;
11622 - bi->softDeletions = 0;
11623 + /* If the chunk is already in the cache or it is less than a whole chunk
11624 + * or we're using inband tags then use the cache (if there is caching)
11625 + * else bypass the cache.
11626 + */
11627 + if (cache || nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11628 + if (dev->param.nShortOpCaches > 0) {
11629
11630 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
11631 + /* If we can't find the data in the cache, then load it up. */
11632
11633 - bi->blockState = state;
11634 - bi->sequenceNumber = sequenceNumber;
11635 + if (!cache) {
11636 + cache = yaffs_GrabChunkCache(in->myDev);
11637 + cache->object = in;
11638 + cache->chunkId = chunk;
11639 + cache->dirty = 0;
11640 + cache->locked = 0;
11641 + yaffs_ReadChunkDataFromObject(in, chunk,
11642 + cache->
11643 + data);
11644 + cache->nBytes = 0;
11645 + }
11646
11647 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
11648 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
11649 + yaffs_UseChunkCache(dev, cache, 0);
11650
11651 - T(YAFFS_TRACE_SCAN_DEBUG,
11652 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
11653 - state, sequenceNumber));
11654 + cache->locked = 1;
11655
11656 - if (state == YAFFS_BLOCK_STATE_DEAD) {
11657 - T(YAFFS_TRACE_BAD_BLOCKS,
11658 - (TSTR("block %d is bad" TENDSTR), blk));
11659 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
11660 - T(YAFFS_TRACE_SCAN_DEBUG,
11661 - (TSTR("Block empty " TENDSTR)));
11662 - dev->nErasedBlocks++;
11663 - dev->nFreeChunks += dev->nChunksPerBlock;
11664 - }
11665 - }
11666
11667 - startIterator = dev->internalStartBlock;
11668 - endIterator = dev->internalEndBlock;
11669 + memcpy(buffer, &cache->data[start], nToCopy);
11670
11671 - /* For each block.... */
11672 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
11673 - blockIterator++) {
11674 + cache->locked = 0;
11675 + } else {
11676 + /* Read into the local buffer then copy..*/
11677
11678 - YYIELD();
11679 + __u8 *localBuffer =
11680 + yaffs_GetTempBuffer(dev, __LINE__);
11681 + yaffs_ReadChunkDataFromObject(in, chunk,
11682 + localBuffer);
11683
11684 - YYIELD();
11685 + memcpy(buffer, &localBuffer[start], nToCopy);
11686
11687 - blk = blockIterator;
11688
11689 - bi = yaffs_GetBlockInfo(dev, blk);
11690 - state = bi->blockState;
11691 + yaffs_ReleaseTempBuffer(dev, localBuffer,
11692 + __LINE__);
11693 + }
11694
11695 - deleted = 0;
11696 + } else {
11697
11698 - /* For each chunk in each block that needs scanning....*/
11699 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
11700 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
11701 - /* Read the tags and decide what to do */
11702 - chunk = blk * dev->nChunksPerBlock + c;
11703 + /* A full chunk. Read directly into the supplied buffer. */
11704 + yaffs_ReadChunkDataFromObject(in, chunk, buffer);
11705
11706 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
11707 - &tags);
11708 + }
11709
11710 - /* Let's have a good look at this chunk... */
11711 + n -= nToCopy;
11712 + offset += nToCopy;
11713 + buffer += nToCopy;
11714 + nDone += nToCopy;
11715
11716 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
11717 - /* YAFFS1 only...
11718 - * A deleted chunk
11719 - */
11720 - deleted++;
11721 - dev->nFreeChunks++;
11722 - /*T((" %d %d deleted\n",blk,c)); */
11723 - } else if (!tags.chunkUsed) {
11724 - /* An unassigned chunk in the block
11725 - * This means that either the block is empty or
11726 - * this is the one being allocated from
11727 - */
11728 + }
11729
11730 - if (c == 0) {
11731 - /* We're looking at the first chunk in the block so the block is unused */
11732 - state = YAFFS_BLOCK_STATE_EMPTY;
11733 - dev->nErasedBlocks++;
11734 - } else {
11735 - /* this is the block being allocated from */
11736 - T(YAFFS_TRACE_SCAN,
11737 - (TSTR
11738 - (" Allocating from %d %d" TENDSTR),
11739 - blk, c));
11740 - state = YAFFS_BLOCK_STATE_ALLOCATING;
11741 - dev->allocationBlock = blk;
11742 - dev->allocationPage = c;
11743 - dev->allocationBlockFinder = blk;
11744 - /* Set it to here to encourage the allocator to go forth from here. */
11745 + return nDone;
11746 +}
11747
11748 - }
11749 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
11750 + int nBytes, int writeThrough)
11751 +{
11752
11753 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
11754 - } else if (tags.chunkId > 0) {
11755 - /* chunkId > 0 so it is a data chunk... */
11756 - unsigned int endpos;
11757 -
11758 - yaffs_SetChunkBit(dev, blk, c);
11759 - bi->pagesInUse++;
11760 -
11761 - in = yaffs_FindOrCreateObjectByNumber(dev,
11762 - tags.
11763 - objectId,
11764 - YAFFS_OBJECT_TYPE_FILE);
11765 - /* PutChunkIntoFile checks for a clash (two data chunks with
11766 - * the same chunkId).
11767 - */
11768 + int chunk;
11769 + __u32 start;
11770 + int nToCopy;
11771 + int n = nBytes;
11772 + int nDone = 0;
11773 + int nToWriteBack;
11774 + int startOfWrite = offset;
11775 + int chunkWritten = 0;
11776 + __u32 nBytesRead;
11777 + __u32 chunkStart;
11778
11779 - if (!in)
11780 - alloc_failed = 1;
11781 + yaffs_Device *dev;
11782
11783 - if (in) {
11784 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
11785 - alloc_failed = 1;
11786 - }
11787 + dev = in->myDev;
11788
11789 - endpos =
11790 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
11791 - tags.byteCount;
11792 - if (in &&
11793 - in->variantType == YAFFS_OBJECT_TYPE_FILE
11794 - && in->variant.fileVariant.scannedFileSize <
11795 - endpos) {
11796 - in->variant.fileVariant.
11797 - scannedFileSize = endpos;
11798 - if (!dev->useHeaderFileSize) {
11799 - in->variant.fileVariant.
11800 - fileSize =
11801 - in->variant.fileVariant.
11802 - scannedFileSize;
11803 - }
11804 + while (n > 0 && chunkWritten >= 0) {
11805 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11806
11807 - }
11808 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
11809 - } else {
11810 - /* chunkId == 0, so it is an ObjectHeader.
11811 - * Thus, we read in the object header and make the object
11812 - */
11813 - yaffs_SetChunkBit(dev, blk, c);
11814 - bi->pagesInUse++;
11815 + if (chunk * dev->nDataBytesPerChunk + start != offset ||
11816 + start >= dev->nDataBytesPerChunk) {
11817 + T(YAFFS_TRACE_ERROR, (
11818 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
11819 + TENDSTR),
11820 + (int)offset, chunk, start));
11821 + }
11822 + chunk++; /* File pos to chunk in file offset */
11823
11824 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
11825 - chunkData,
11826 - NULL);
11827 -
11828 - oh = (yaffs_ObjectHeader *) chunkData;
11829 -
11830 - in = yaffs_FindObjectByNumber(dev,
11831 - tags.objectId);
11832 - if (in && in->variantType != oh->type) {
11833 - /* This should not happen, but somehow
11834 - * Wev'e ended up with an objectId that has been reused but not yet
11835 - * deleted, and worse still it has changed type. Delete the old object.
11836 - */
11837 + /* OK now check for the curveball where the start and end are in
11838 + * the same chunk.
11839 + */
11840
11841 - yaffs_DeleteObject(in);
11842 + if ((start + n) < dev->nDataBytesPerChunk) {
11843 + nToCopy = n;
11844
11845 - in = 0;
11846 - }
11847 + /* Now folks, to calculate how many bytes to write back....
11848 + * If we're overwriting and not writing to then end of file then
11849 + * we need to write back as much as was there before.
11850 + */
11851
11852 - in = yaffs_FindOrCreateObjectByNumber(dev,
11853 - tags.
11854 - objectId,
11855 - oh->type);
11856 -
11857 - if (!in)
11858 - alloc_failed = 1;
11859 -
11860 - if (in && oh->shadowsObject > 0) {
11861 -
11862 - struct yaffs_ShadowFixerStruct *fixer;
11863 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
11864 - if (fixer) {
11865 - fixer->next = shadowFixerList;
11866 - shadowFixerList = fixer;
11867 - fixer->objectId = tags.objectId;
11868 - fixer->shadowedId = oh->shadowsObject;
11869 - }
11870 + chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
11871
11872 - }
11873 + if (chunkStart > in->variant.fileVariant.fileSize)
11874 + nBytesRead = 0; /* Past end of file */
11875 + else
11876 + nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
11877
11878 - if (in && in->valid) {
11879 - /* We have already filled this one. We have a duplicate and need to resolve it. */
11880 + if (nBytesRead > dev->nDataBytesPerChunk)
11881 + nBytesRead = dev->nDataBytesPerChunk;
11882
11883 - unsigned existingSerial = in->serial;
11884 - unsigned newSerial = tags.serialNumber;
11885 + nToWriteBack =
11886 + (nBytesRead >
11887 + (start + n)) ? nBytesRead : (start + n);
11888
11889 - if (((existingSerial + 1) & 3) == newSerial) {
11890 - /* Use new one - destroy the exisiting one */
11891 - yaffs_DeleteChunk(dev,
11892 - in->hdrChunk,
11893 - 1, __LINE__);
11894 - in->valid = 0;
11895 - } else {
11896 - /* Use existing - destroy this one. */
11897 - yaffs_DeleteChunk(dev, chunk, 1,
11898 - __LINE__);
11899 - }
11900 - }
11901 + if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
11902 + YBUG();
11903
11904 - if (in && !in->valid &&
11905 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
11906 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
11907 - /* We only load some info, don't fiddle with directory structure */
11908 - in->valid = 1;
11909 - in->variantType = oh->type;
11910 + } else {
11911 + nToCopy = dev->nDataBytesPerChunk - start;
11912 + nToWriteBack = dev->nDataBytesPerChunk;
11913 + }
11914
11915 - in->yst_mode = oh->yst_mode;
11916 -#ifdef CONFIG_YAFFS_WINCE
11917 - in->win_atime[0] = oh->win_atime[0];
11918 - in->win_ctime[0] = oh->win_ctime[0];
11919 - in->win_mtime[0] = oh->win_mtime[0];
11920 - in->win_atime[1] = oh->win_atime[1];
11921 - in->win_ctime[1] = oh->win_ctime[1];
11922 - in->win_mtime[1] = oh->win_mtime[1];
11923 -#else
11924 - in->yst_uid = oh->yst_uid;
11925 - in->yst_gid = oh->yst_gid;
11926 - in->yst_atime = oh->yst_atime;
11927 - in->yst_mtime = oh->yst_mtime;
11928 - in->yst_ctime = oh->yst_ctime;
11929 - in->yst_rdev = oh->yst_rdev;
11930 -#endif
11931 - in->hdrChunk = chunk;
11932 - in->serial = tags.serialNumber;
11933 + if (nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11934 + /* An incomplete start or end chunk (or maybe both start and end chunk),
11935 + * or we're using inband tags, so we want to use the cache buffers.
11936 + */
11937 + if (dev->param.nShortOpCaches > 0) {
11938 + yaffs_ChunkCache *cache;
11939 + /* If we can't find the data in the cache, then load the cache */
11940 + cache = yaffs_FindChunkCache(in, chunk);
11941
11942 - } else if (in && !in->valid) {
11943 - /* we need to load this info */
11944 + if (!cache
11945 + && yaffs_CheckSpaceForAllocation(dev, 1)) {
11946 + cache = yaffs_GrabChunkCache(dev);
11947 + cache->object = in;
11948 + cache->chunkId = chunk;
11949 + cache->dirty = 0;
11950 + cache->locked = 0;
11951 + yaffs_ReadChunkDataFromObject(in, chunk,
11952 + cache->data);
11953 + } else if (cache &&
11954 + !cache->dirty &&
11955 + !yaffs_CheckSpaceForAllocation(dev, 1)) {
11956 + /* Drop the cache if it was a read cache item and
11957 + * no space check has been made for it.
11958 + */
11959 + cache = NULL;
11960 + }
11961
11962 - in->valid = 1;
11963 - in->variantType = oh->type;
11964 + if (cache) {
11965 + yaffs_UseChunkCache(dev, cache, 1);
11966 + cache->locked = 1;
11967
11968 - in->yst_mode = oh->yst_mode;
11969 -#ifdef CONFIG_YAFFS_WINCE
11970 - in->win_atime[0] = oh->win_atime[0];
11971 - in->win_ctime[0] = oh->win_ctime[0];
11972 - in->win_mtime[0] = oh->win_mtime[0];
11973 - in->win_atime[1] = oh->win_atime[1];
11974 - in->win_ctime[1] = oh->win_ctime[1];
11975 - in->win_mtime[1] = oh->win_mtime[1];
11976 -#else
11977 - in->yst_uid = oh->yst_uid;
11978 - in->yst_gid = oh->yst_gid;
11979 - in->yst_atime = oh->yst_atime;
11980 - in->yst_mtime = oh->yst_mtime;
11981 - in->yst_ctime = oh->yst_ctime;
11982 - in->yst_rdev = oh->yst_rdev;
11983 -#endif
11984 - in->hdrChunk = chunk;
11985 - in->serial = tags.serialNumber;
11986
11987 - yaffs_SetObjectName(in, oh->name);
11988 - in->dirty = 0;
11989 + memcpy(&cache->data[start], buffer,
11990 + nToCopy);
11991
11992 - /* directory stuff...
11993 - * hook up to parent
11994 - */
11995
11996 - parent =
11997 - yaffs_FindOrCreateObjectByNumber
11998 - (dev, oh->parentObjectId,
11999 - YAFFS_OBJECT_TYPE_DIRECTORY);
12000 - if (!parent)
12001 - alloc_failed = 1;
12002 - if (parent && parent->variantType ==
12003 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12004 - /* Set up as a directory */
12005 - parent->variantType =
12006 - YAFFS_OBJECT_TYPE_DIRECTORY;
12007 - YINIT_LIST_HEAD(&parent->variant.
12008 - directoryVariant.
12009 - children);
12010 - } else if (!parent || parent->variantType !=
12011 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12012 - /* Hoosterman, another problem....
12013 - * We're trying to use a non-directory as a directory
12014 - */
12015 + cache->locked = 0;
12016 + cache->nBytes = nToWriteBack;
12017
12018 - T(YAFFS_TRACE_ERROR,
12019 - (TSTR
12020 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12021 - TENDSTR)));
12022 - parent = dev->lostNFoundDir;
12023 + if (writeThrough) {
12024 + chunkWritten =
12025 + yaffs_WriteChunkDataToObject
12026 + (cache->object,
12027 + cache->chunkId,
12028 + cache->data, cache->nBytes,
12029 + 1);
12030 + cache->dirty = 0;
12031 }
12032
12033 - yaffs_AddObjectToDirectory(parent, in);
12034 + } else {
12035 + chunkWritten = -1; /* fail the write */
12036 + }
12037 + } else {
12038 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12039 + * Read into the local buffer then copy, then copy over and write back.
12040 + */
12041
12042 - if (0 && (parent == dev->deletedDir ||
12043 - parent == dev->unlinkedDir)) {
12044 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12045 - dev->nDeletedFiles++;
12046 - }
12047 - /* Note re hardlinks.
12048 - * Since we might scan a hardlink before its equivalent object is scanned
12049 - * we put them all in a list.
12050 - * After scanning is complete, we should have all the objects, so we run through this
12051 - * list and fix up all the chains.
12052 - */
12053 + __u8 *localBuffer =
12054 + yaffs_GetTempBuffer(dev, __LINE__);
12055
12056 - switch (in->variantType) {
12057 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12058 - /* Todo got a problem */
12059 - break;
12060 - case YAFFS_OBJECT_TYPE_FILE:
12061 - if (dev->useHeaderFileSize)
12062 -
12063 - in->variant.fileVariant.
12064 - fileSize =
12065 - oh->fileSize;
12066 -
12067 - break;
12068 - case YAFFS_OBJECT_TYPE_HARDLINK:
12069 - in->variant.hardLinkVariant.
12070 - equivalentObjectId =
12071 - oh->equivalentObjectId;
12072 - in->hardLinks.next =
12073 - (struct ylist_head *)
12074 - hardList;
12075 - hardList = in;
12076 - break;
12077 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12078 - /* Do nothing */
12079 - break;
12080 - case YAFFS_OBJECT_TYPE_SPECIAL:
12081 - /* Do nothing */
12082 - break;
12083 - case YAFFS_OBJECT_TYPE_SYMLINK:
12084 - in->variant.symLinkVariant.alias =
12085 - yaffs_CloneString(oh->alias);
12086 - if (!in->variant.symLinkVariant.alias)
12087 - alloc_failed = 1;
12088 - break;
12089 - }
12090 + yaffs_ReadChunkDataFromObject(in, chunk,
12091 + localBuffer);
12092
12093 -/*
12094 - if (parent == dev->deletedDir) {
12095 - yaffs_DestroyObject(in);
12096 - bi->hasShrinkHeader = 1;
12097 - }
12098 -*/
12099 - }
12100 - }
12101 - }
12102
12103 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12104 - /* If we got this far while scanning, then the block is fully allocated.*/
12105 - state = YAFFS_BLOCK_STATE_FULL;
12106 - }
12107
12108 - bi->blockState = state;
12109 + memcpy(&localBuffer[start], buffer, nToCopy);
12110
12111 - /* Now let's see if it was dirty */
12112 - if (bi->pagesInUse == 0 &&
12113 - !bi->hasShrinkHeader &&
12114 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12115 - yaffs_BlockBecameDirty(dev, blk);
12116 - }
12117 + chunkWritten =
12118 + yaffs_WriteChunkDataToObject(in, chunk,
12119 + localBuffer,
12120 + nToWriteBack,
12121 + 0);
12122
12123 - }
12124 + yaffs_ReleaseTempBuffer(dev, localBuffer,
12125 + __LINE__);
12126
12127 + }
12128
12129 - /* Ok, we've done all the scanning.
12130 - * Fix up the hard link chains.
12131 - * We should now have scanned all the objects, now it's time to add these
12132 - * hardlinks.
12133 - */
12134 + } else {
12135 + /* A full chunk. Write directly from the supplied buffer. */
12136
12137 - yaffs_HardlinkFixup(dev, hardList);
12138
12139 - /* Fix up any shadowed objects */
12140 - {
12141 - struct yaffs_ShadowFixerStruct *fixer;
12142 - yaffs_Object *obj;
12143 -
12144 - while (shadowFixerList) {
12145 - fixer = shadowFixerList;
12146 - shadowFixerList = fixer->next;
12147 - /* Complete the rename transaction by deleting the shadowed object
12148 - * then setting the object header to unshadowed.
12149 - */
12150 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12151 - if (obj)
12152 - yaffs_DeleteObject(obj);
12153
12154 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12155 + chunkWritten =
12156 + yaffs_WriteChunkDataToObject(in, chunk, buffer,
12157 + dev->nDataBytesPerChunk,
12158 + 0);
12159
12160 - if (obj)
12161 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12162 + /* Since we've overwritten the cached data, we better invalidate it. */
12163 + yaffs_InvalidateChunkCache(in, chunk);
12164 + }
12165
12166 - YFREE(fixer);
12167 + if (chunkWritten >= 0) {
12168 + n -= nToCopy;
12169 + offset += nToCopy;
12170 + buffer += nToCopy;
12171 + nDone += nToCopy;
12172 }
12173 - }
12174
12175 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12176 + }
12177
12178 - if (alloc_failed)
12179 - return YAFFS_FAIL;
12180 + /* Update file object */
12181
12182 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12183 + if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
12184 + in->variant.fileVariant.fileSize = (startOfWrite + nDone);
12185
12186 + in->dirty = 1;
12187
12188 - return YAFFS_OK;
12189 + return nDone;
12190 }
12191
12192 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12193 +int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
12194 + int nBytes, int writeThrough)
12195 {
12196 - __u8 *chunkData;
12197 - yaffs_ObjectHeader *oh;
12198 - yaffs_Device *dev;
12199 - yaffs_ExtendedTags tags;
12200 - int result;
12201 - int alloc_failed = 0;
12202 + yaffs2_HandleHole(in,offset);
12203 + return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
12204 +}
12205
12206 - if (!in)
12207 - return;
12208
12209 - dev = in->myDev;
12210
12211 -#if 0
12212 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12213 - in->objectId,
12214 - in->lazyLoaded ? "not yet" : "already"));
12215 -#endif
12216 +/* ---------------------- File resizing stuff ------------------ */
12217
12218 - if (in->lazyLoaded && in->hdrChunk > 0) {
12219 - in->lazyLoaded = 0;
12220 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12221 +static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
12222 +{
12223
12224 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12225 - oh = (yaffs_ObjectHeader *) chunkData;
12226 + yaffs_Device *dev = in->myDev;
12227 + int oldFileSize = in->variant.fileVariant.fileSize;
12228
12229 - in->yst_mode = oh->yst_mode;
12230 -#ifdef CONFIG_YAFFS_WINCE
12231 - in->win_atime[0] = oh->win_atime[0];
12232 - in->win_ctime[0] = oh->win_ctime[0];
12233 - in->win_mtime[0] = oh->win_mtime[0];
12234 - in->win_atime[1] = oh->win_atime[1];
12235 - in->win_ctime[1] = oh->win_ctime[1];
12236 - in->win_mtime[1] = oh->win_mtime[1];
12237 -#else
12238 - in->yst_uid = oh->yst_uid;
12239 - in->yst_gid = oh->yst_gid;
12240 - in->yst_atime = oh->yst_atime;
12241 - in->yst_mtime = oh->yst_mtime;
12242 - in->yst_ctime = oh->yst_ctime;
12243 - in->yst_rdev = oh->yst_rdev;
12244 + int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
12245
12246 -#endif
12247 - yaffs_SetObjectName(in, oh->name);
12248 + int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
12249 + dev->nDataBytesPerChunk;
12250 + int i;
12251 + int chunkId;
12252
12253 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12254 - in->variant.symLinkVariant.alias =
12255 - yaffs_CloneString(oh->alias);
12256 - if (!in->variant.symLinkVariant.alias)
12257 - alloc_failed = 1; /* Not returned to caller */
12258 - }
12259 + /* Delete backwards so that we don't end up with holes if
12260 + * power is lost part-way through the operation.
12261 + */
12262 + for (i = lastDel; i >= startDel; i--) {
12263 + /* NB this could be optimised somewhat,
12264 + * eg. could retrieve the tags and write them without
12265 + * using yaffs_DeleteChunk
12266 + */
12267
12268 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12269 + chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
12270 + if (chunkId > 0) {
12271 + if (chunkId <
12272 + (dev->internalStartBlock * dev->param.nChunksPerBlock)
12273 + || chunkId >=
12274 + ((dev->internalEndBlock +
12275 + 1) * dev->param.nChunksPerBlock)) {
12276 + T(YAFFS_TRACE_ALWAYS,
12277 + (TSTR("Found daft chunkId %d for %d" TENDSTR),
12278 + chunkId, i));
12279 + } else {
12280 + in->nDataChunks--;
12281 + yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
12282 + }
12283 + }
12284 }
12285 +
12286 }
12287
12288 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12289 +
12290 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize)
12291 {
12292 - yaffs_ExtendedTags tags;
12293 - int blk;
12294 - int blockIterator;
12295 - int startIterator;
12296 - int endIterator;
12297 - int nBlocksToScan = 0;
12298 + int newFullChunks;
12299 + __u32 newSizeOfPartialChunk;
12300 + yaffs_Device *dev = obj->myDev;
12301
12302 - int chunk;
12303 - int result;
12304 - int c;
12305 - int deleted;
12306 - yaffs_BlockState state;
12307 - yaffs_Object *hardList = NULL;
12308 - yaffs_BlockInfo *bi;
12309 - __u32 sequenceNumber;
12310 - yaffs_ObjectHeader *oh;
12311 - yaffs_Object *in;
12312 - yaffs_Object *parent;
12313 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12314 - int itsUnlinked;
12315 - __u8 *chunkData;
12316 + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
12317
12318 - int fileSize;
12319 - int isShrink;
12320 - int foundChunksInBlock;
12321 - int equivalentObjectId;
12322 - int alloc_failed = 0;
12323 + yaffs_PruneResizedChunks(obj, newSize);
12324
12325 + if (newSizeOfPartialChunk != 0) {
12326 + int lastChunk = 1 + newFullChunks;
12327 + __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
12328
12329 - yaffs_BlockIndex *blockIndex = NULL;
12330 - int altBlockIndex = 0;
12331 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12332 + yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer);
12333 + memset(localBuffer + newSizeOfPartialChunk, 0,
12334 + dev->nDataBytesPerChunk - newSizeOfPartialChunk);
12335
12336 - if (!dev->isYaffs2) {
12337 - T(YAFFS_TRACE_SCAN,
12338 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12339 - return YAFFS_FAIL;
12340 + yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer,
12341 + newSizeOfPartialChunk, 1);
12342 +
12343 + yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
12344 }
12345
12346 - T(YAFFS_TRACE_SCAN,
12347 - (TSTR
12348 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12349 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12350 + obj->variant.fileVariant.fileSize = newSize;
12351 +
12352 + yaffs_PruneFileStructure(dev, &obj->variant.fileVariant);
12353 +}
12354
12355
12356 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12357 +int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
12358 +{
12359 + yaffs_Device *dev = in->myDev;
12360 + int oldFileSize = in->variant.fileVariant.fileSize;
12361
12362 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12363 + yaffs_FlushFilesChunkCache(in);
12364 + yaffs_InvalidateWholeChunkCache(in);
12365
12366 - if (!blockIndex) {
12367 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12368 - altBlockIndex = 1;
12369 - }
12370 + yaffs_CheckGarbageCollection(dev,0);
12371
12372 - if (!blockIndex) {
12373 - T(YAFFS_TRACE_SCAN,
12374 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
12375 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
12376 return YAFFS_FAIL;
12377 - }
12378
12379 - dev->blocksInCheckpoint = 0;
12380 + if (newSize == oldFileSize)
12381 + return YAFFS_OK;
12382 +
12383 + if(newSize > oldFileSize){
12384 + yaffs2_HandleHole(in,newSize);
12385 + in->variant.fileVariant.fileSize = newSize;
12386 + } else {
12387 + /* newSize < oldFileSize */
12388 + yaffs_ResizeDown(in, newSize);
12389 + }
12390 +
12391 + /* Write a new object header to reflect the resize.
12392 + * show we've shrunk the file, if need be
12393 + * Do this only if the file is not in the deleted directories
12394 + * and is not shadowed.
12395 + */
12396 + if (in->parent &&
12397 + !in->isShadowed &&
12398 + in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
12399 + in->parent->objectId != YAFFS_OBJECTID_DELETED)
12400 + yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL);
12401 +
12402
12403 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12404 + return YAFFS_OK;
12405 +}
12406
12407 - /* Scan all the blocks to determine their state */
12408 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12409 - bi = yaffs_GetBlockInfo(dev, blk);
12410 - yaffs_ClearChunkBits(dev, blk);
12411 - bi->pagesInUse = 0;
12412 - bi->softDeletions = 0;
12413 +loff_t yaffs_GetFileSize(yaffs_Object *obj)
12414 +{
12415 + YCHAR *alias = NULL;
12416 + obj = yaffs_GetEquivalentObject(obj);
12417 +
12418 + switch (obj->variantType) {
12419 + case YAFFS_OBJECT_TYPE_FILE:
12420 + return obj->variant.fileVariant.fileSize;
12421 + case YAFFS_OBJECT_TYPE_SYMLINK:
12422 + alias = obj->variant.symLinkVariant.alias;
12423 + if(!alias)
12424 + return 0;
12425 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
12426 + default:
12427 + return 0;
12428 + }
12429 +}
12430
12431 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12432
12433 - bi->blockState = state;
12434 - bi->sequenceNumber = sequenceNumber;
12435
12436 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
12437 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
12438 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12439 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12440 +int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
12441 +{
12442 + int retVal;
12443 + if (in->dirty) {
12444 + yaffs_FlushFilesChunkCache(in);
12445 + if(dataSync) /* Only sync data */
12446 + retVal=YAFFS_OK;
12447 + else {
12448 + if (updateTime) {
12449 +#ifdef CONFIG_YAFFS_WINCE
12450 + yfsd_WinFileTimeNow(in->win_mtime);
12451 +#else
12452
12453 - T(YAFFS_TRACE_SCAN_DEBUG,
12454 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12455 - state, sequenceNumber));
12456 + in->yst_mtime = Y_CURRENT_TIME;
12457
12458 +#endif
12459 + }
12460
12461 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
12462 - dev->blocksInCheckpoint++;
12463 + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >=
12464 + 0) ? YAFFS_OK : YAFFS_FAIL;
12465 + }
12466 + } else {
12467 + retVal = YAFFS_OK;
12468 + }
12469
12470 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
12471 - T(YAFFS_TRACE_BAD_BLOCKS,
12472 - (TSTR("block %d is bad" TENDSTR), blk));
12473 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12474 - T(YAFFS_TRACE_SCAN_DEBUG,
12475 - (TSTR("Block empty " TENDSTR)));
12476 - dev->nErasedBlocks++;
12477 - dev->nFreeChunks += dev->nChunksPerBlock;
12478 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12479 + return retVal;
12480
12481 - /* Determine the highest sequence number */
12482 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
12483 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
12484 +}
12485
12486 - blockIndex[nBlocksToScan].seq = sequenceNumber;
12487 - blockIndex[nBlocksToScan].block = blk;
12488 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
12489 +{
12490
12491 - nBlocksToScan++;
12492 + /* First off, invalidate the file's data in the cache, without flushing. */
12493 + yaffs_InvalidateWholeChunkCache(in);
12494
12495 - if (sequenceNumber >= dev->sequenceNumber)
12496 - dev->sequenceNumber = sequenceNumber;
12497 - } else {
12498 - /* TODO: Nasty sequence number! */
12499 - T(YAFFS_TRACE_SCAN,
12500 - (TSTR
12501 - ("Block scanning block %d has bad sequence number %d"
12502 - TENDSTR), blk, sequenceNumber));
12503 + if (in->myDev->param.isYaffs2 && (in->parent != in->myDev->deletedDir)) {
12504 + /* Move to the unlinked directory so we have a record that it was deleted. */
12505 + yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
12506
12507 - }
12508 - }
12509 }
12510
12511 - T(YAFFS_TRACE_SCAN,
12512 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
12513 + yaffs_RemoveObjectFromDirectory(in);
12514 + yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
12515 + in->hdrChunk = 0;
12516
12517 + yaffs_FreeObject(in);
12518 + return YAFFS_OK;
12519
12520 +}
12521
12522 - YYIELD();
12523 +/* yaffs_DeleteFile deletes the whole file data
12524 + * and the inode associated with the file.
12525 + * It does not delete the links associated with the file.
12526 + */
12527 +static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
12528 +{
12529
12530 - /* Sort the blocks */
12531 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
12532 - {
12533 - /* Use qsort now. */
12534 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
12535 - }
12536 -#else
12537 - {
12538 - /* Dungy old bubble sort... */
12539 + int retVal;
12540 + int immediateDeletion = 0;
12541 + yaffs_Device *dev = in->myDev;
12542
12543 - yaffs_BlockIndex temp;
12544 - int i;
12545 - int j;
12546 + if (!in->myInode)
12547 + immediateDeletion = 1;
12548
12549 - for (i = 0; i < nBlocksToScan; i++)
12550 - for (j = i + 1; j < nBlocksToScan; j++)
12551 - if (blockIndex[i].seq > blockIndex[j].seq) {
12552 - temp = blockIndex[j];
12553 - blockIndex[j] = blockIndex[i];
12554 - blockIndex[i] = temp;
12555 - }
12556 + if (immediateDeletion) {
12557 + retVal =
12558 + yaffs_ChangeObjectName(in, in->myDev->deletedDir,
12559 + _Y("deleted"), 0, 0);
12560 + T(YAFFS_TRACE_TRACING,
12561 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
12562 + in->objectId));
12563 + in->deleted = 1;
12564 + in->myDev->nDeletedFiles++;
12565 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12566 + yaffs_ResizeFile(in, 0);
12567 + yaffs_SoftDeleteFile(in);
12568 + } else {
12569 + retVal =
12570 + yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
12571 + _Y("unlinked"), 0, 0);
12572 }
12573 -#endif
12574
12575 - YYIELD();
12576
12577 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
12578 + return retVal;
12579 +}
12580 +
12581 +int yaffs_DeleteFile(yaffs_Object *in)
12582 +{
12583 + int retVal = YAFFS_OK;
12584 + int deleted; /* Need to cache value on stack if in is freed */
12585 + yaffs_Device *dev = in->myDev;
12586 +
12587 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12588 + yaffs_ResizeFile(in, 0);
12589 +
12590 + if (in->nDataChunks > 0) {
12591 + /* Use soft deletion if there is data in the file.
12592 + * That won't be the case if it has been resized to zero.
12593 + */
12594 + if (!in->unlinked)
12595 + retVal = yaffs_UnlinkFileIfNeeded(in);
12596
12597 - /* Now scan the blocks looking at the data. */
12598 - startIterator = 0;
12599 - endIterator = nBlocksToScan - 1;
12600 - T(YAFFS_TRACE_SCAN_DEBUG,
12601 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
12602 + deleted = in->deleted;
12603
12604 - /* For each block.... backwards */
12605 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
12606 - blockIterator--) {
12607 - /* Cooperative multitasking! This loop can run for so
12608 - long that watchdog timers expire. */
12609 - YYIELD();
12610 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
12611 + in->deleted = 1;
12612 + deleted = 1;
12613 + in->myDev->nDeletedFiles++;
12614 + yaffs_SoftDeleteFile(in);
12615 + }
12616 + return deleted ? YAFFS_OK : YAFFS_FAIL;
12617 + } else {
12618 + /* The file has no data chunks so we toss it immediately */
12619 + yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
12620 + in->variant.fileVariant.top = NULL;
12621 + yaffs_DoGenericObjectDeletion(in);
12622
12623 - /* get the block to scan in the correct order */
12624 - blk = blockIndex[blockIterator].block;
12625 + return YAFFS_OK;
12626 + }
12627 +}
12628
12629 - bi = yaffs_GetBlockInfo(dev, blk);
12630 +static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
12631 +{
12632 + return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
12633 + !(ylist_empty(&obj->variant.directoryVariant.children));
12634 +}
12635
12636 +static int yaffs_DeleteDirectory(yaffs_Object *obj)
12637 +{
12638 + /* First check that the directory is empty. */
12639 + if (yaffs_IsNonEmptyDirectory(obj))
12640 + return YAFFS_FAIL;
12641
12642 - state = bi->blockState;
12643 + return yaffs_DoGenericObjectDeletion(obj);
12644 +}
12645
12646 - deleted = 0;
12647 +static int yaffs_DeleteSymLink(yaffs_Object *in)
12648 +{
12649 + if(in->variant.symLinkVariant.alias)
12650 + YFREE(in->variant.symLinkVariant.alias);
12651 + in->variant.symLinkVariant.alias=NULL;
12652
12653 - /* For each chunk in each block that needs scanning.... */
12654 - foundChunksInBlock = 0;
12655 - for (c = dev->nChunksPerBlock - 1;
12656 - !alloc_failed && c >= 0 &&
12657 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12658 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
12659 - /* Scan backwards...
12660 - * Read the tags and decide what to do
12661 - */
12662 + return yaffs_DoGenericObjectDeletion(in);
12663 +}
12664
12665 - chunk = blk * dev->nChunksPerBlock + c;
12666 +static int yaffs_DeleteHardLink(yaffs_Object *in)
12667 +{
12668 + /* remove this hardlink from the list assocaited with the equivalent
12669 + * object
12670 + */
12671 + ylist_del_init(&in->hardLinks);
12672 + return yaffs_DoGenericObjectDeletion(in);
12673 +}
12674
12675 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12676 - &tags);
12677 +int yaffs_DeleteObject(yaffs_Object *obj)
12678 +{
12679 +int retVal = -1;
12680 + switch (obj->variantType) {
12681 + case YAFFS_OBJECT_TYPE_FILE:
12682 + retVal = yaffs_DeleteFile(obj);
12683 + break;
12684 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12685 + if(!ylist_empty(&obj->variant.directoryVariant.dirty)){
12686 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->objectId));
12687 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12688 + }
12689 + return yaffs_DeleteDirectory(obj);
12690 + break;
12691 + case YAFFS_OBJECT_TYPE_SYMLINK:
12692 + retVal = yaffs_DeleteSymLink(obj);
12693 + break;
12694 + case YAFFS_OBJECT_TYPE_HARDLINK:
12695 + retVal = yaffs_DeleteHardLink(obj);
12696 + break;
12697 + case YAFFS_OBJECT_TYPE_SPECIAL:
12698 + retVal = yaffs_DoGenericObjectDeletion(obj);
12699 + break;
12700 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12701 + retVal = 0;
12702 + break; /* should not happen. */
12703 + }
12704
12705 - /* Let's have a good look at this chunk... */
12706 + return retVal;
12707 +}
12708
12709 - if (!tags.chunkUsed) {
12710 - /* An unassigned chunk in the block.
12711 - * If there are used chunks after this one, then
12712 - * it is a chunk that was skipped due to failing the erased
12713 - * check. Just skip it so that it can be deleted.
12714 - * But, more typically, We get here when this is an unallocated
12715 - * chunk and his means that either the block is empty or
12716 - * this is the one being allocated from
12717 - */
12718 +static int yaffs_UnlinkWorker(yaffs_Object *obj)
12719 +{
12720
12721 - if (foundChunksInBlock) {
12722 - /* This is a chunk that was skipped due to failing the erased check */
12723 - } else if (c == 0) {
12724 - /* We're looking at the first chunk in the block so the block is unused */
12725 - state = YAFFS_BLOCK_STATE_EMPTY;
12726 - dev->nErasedBlocks++;
12727 - } else {
12728 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12729 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
12730 - if (dev->sequenceNumber == bi->sequenceNumber) {
12731 - /* this is the block being allocated from */
12732 -
12733 - T(YAFFS_TRACE_SCAN,
12734 - (TSTR
12735 - (" Allocating from %d %d"
12736 - TENDSTR), blk, c));
12737 -
12738 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12739 - dev->allocationBlock = blk;
12740 - dev->allocationPage = c;
12741 - dev->allocationBlockFinder = blk;
12742 - } else {
12743 - /* This is a partially written block that is not
12744 - * the current allocation block. This block must have
12745 - * had a write failure, so set up for retirement.
12746 - */
12747 -
12748 - /* bi->needsRetiring = 1; ??? TODO */
12749 - bi->gcPrioritise = 1;
12750 -
12751 - T(YAFFS_TRACE_ALWAYS,
12752 - (TSTR("Partially written block %d detected" TENDSTR),
12753 - blk));
12754 - }
12755 - }
12756 - }
12757 + int immediateDeletion = 0;
12758
12759 - dev->nFreeChunks++;
12760 + if (!obj->myInode)
12761 + immediateDeletion = 1;
12762
12763 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
12764 - T(YAFFS_TRACE_SCAN,
12765 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
12766 - blk, c));
12767 -
12768 - dev->nFreeChunks++;
12769 -
12770 - } else if (tags.chunkId > 0) {
12771 - /* chunkId > 0 so it is a data chunk... */
12772 - unsigned int endpos;
12773 - __u32 chunkBase =
12774 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
12775 -
12776 - foundChunksInBlock = 1;
12777 -
12778 -
12779 - yaffs_SetChunkBit(dev, blk, c);
12780 - bi->pagesInUse++;
12781 -
12782 - in = yaffs_FindOrCreateObjectByNumber(dev,
12783 - tags.
12784 - objectId,
12785 - YAFFS_OBJECT_TYPE_FILE);
12786 - if (!in) {
12787 - /* Out of memory */
12788 - alloc_failed = 1;
12789 - }
12790 + if(obj)
12791 + yaffs_UpdateParent(obj->parent);
12792
12793 - if (in &&
12794 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12795 - && chunkBase <
12796 - in->variant.fileVariant.shrinkSize) {
12797 - /* This has not been invalidated by a resize */
12798 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
12799 - chunk, -1)) {
12800 - alloc_failed = 1;
12801 - }
12802 + if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
12803 + return yaffs_DeleteHardLink(obj);
12804 + } else if (!ylist_empty(&obj->hardLinks)) {
12805 + /* Curve ball: We're unlinking an object that has a hardlink.
12806 + *
12807 + * This problem arises because we are not strictly following
12808 + * The Linux link/inode model.
12809 + *
12810 + * We can't really delete the object.
12811 + * Instead, we do the following:
12812 + * - Select a hardlink.
12813 + * - Unhook it from the hard links
12814 + * - Move it from its parent directory (so that the rename can work)
12815 + * - Rename the object to the hardlink's name.
12816 + * - Delete the hardlink
12817 + */
12818
12819 - /* File size is calculated by looking at the data chunks if we have not
12820 - * seen an object header yet. Stop this practice once we find an object header.
12821 - */
12822 - endpos =
12823 - (tags.chunkId -
12824 - 1) * dev->nDataBytesPerChunk +
12825 - tags.byteCount;
12826 -
12827 - if (!in->valid && /* have not got an object header yet */
12828 - in->variant.fileVariant.
12829 - scannedFileSize < endpos) {
12830 - in->variant.fileVariant.
12831 - scannedFileSize = endpos;
12832 - in->variant.fileVariant.
12833 - fileSize =
12834 - in->variant.fileVariant.
12835 - scannedFileSize;
12836 - }
12837 + yaffs_Object *hl;
12838 + yaffs_Object *parent;
12839 + int retVal;
12840 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
12841
12842 - } else if (in) {
12843 - /* This chunk has been invalidated by a resize, so delete */
12844 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
12845 + hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
12846
12847 - }
12848 - } else {
12849 - /* chunkId == 0, so it is an ObjectHeader.
12850 - * Thus, we read in the object header and make the object
12851 - */
12852 - foundChunksInBlock = 1;
12853 + yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
12854 + parent = hl->parent;
12855
12856 - yaffs_SetChunkBit(dev, blk, c);
12857 - bi->pagesInUse++;
12858 + ylist_del_init(&hl->hardLinks);
12859
12860 - oh = NULL;
12861 - in = NULL;
12862 + yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl);
12863
12864 - if (tags.extraHeaderInfoAvailable) {
12865 - in = yaffs_FindOrCreateObjectByNumber
12866 - (dev, tags.objectId,
12867 - tags.extraObjectType);
12868 - if (!in)
12869 - alloc_failed = 1;
12870 - }
12871 + retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0);
12872
12873 - if (!in ||
12874 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
12875 - !in->valid ||
12876 -#endif
12877 - tags.extraShadows ||
12878 - (!in->valid &&
12879 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12880 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
12881 -
12882 - /* If we don't have valid info then we need to read the chunk
12883 - * TODO In future we can probably defer reading the chunk and
12884 - * living with invalid data until needed.
12885 - */
12886 + if (retVal == YAFFS_OK)
12887 + retVal = yaffs_DoGenericObjectDeletion(hl);
12888
12889 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
12890 - chunk,
12891 - chunkData,
12892 - NULL);
12893 -
12894 - oh = (yaffs_ObjectHeader *) chunkData;
12895 -
12896 - if (dev->inbandTags) {
12897 - /* Fix up the header if they got corrupted by inband tags */
12898 - oh->shadowsObject = oh->inbandShadowsObject;
12899 - oh->isShrink = oh->inbandIsShrink;
12900 - }
12901 + return retVal;
12902
12903 - if (!in) {
12904 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
12905 - if (!in)
12906 - alloc_failed = 1;
12907 - }
12908 + } else if (immediateDeletion) {
12909 + switch (obj->variantType) {
12910 + case YAFFS_OBJECT_TYPE_FILE:
12911 + return yaffs_DeleteFile(obj);
12912 + break;
12913 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12914 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12915 + return yaffs_DeleteDirectory(obj);
12916 + break;
12917 + case YAFFS_OBJECT_TYPE_SYMLINK:
12918 + return yaffs_DeleteSymLink(obj);
12919 + break;
12920 + case YAFFS_OBJECT_TYPE_SPECIAL:
12921 + return yaffs_DoGenericObjectDeletion(obj);
12922 + break;
12923 + case YAFFS_OBJECT_TYPE_HARDLINK:
12924 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12925 + default:
12926 + return YAFFS_FAIL;
12927 + }
12928 + } else if(yaffs_IsNonEmptyDirectory(obj))
12929 + return YAFFS_FAIL;
12930 + else
12931 + return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
12932 + _Y("unlinked"), 0, 0);
12933 +}
12934
12935 - }
12936
12937 - if (!in) {
12938 - /* TODO Hoosterman we have a problem! */
12939 - T(YAFFS_TRACE_ERROR,
12940 - (TSTR
12941 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
12942 - TENDSTR), tags.objectId, chunk));
12943 - continue;
12944 - }
12945 +static int yaffs_UnlinkObject(yaffs_Object *obj)
12946 +{
12947
12948 - if (in->valid) {
12949 - /* We have already filled this one.
12950 - * We have a duplicate that will be discarded, but
12951 - * we first have to suck out resize info if it is a file.
12952 - */
12953 + if (obj && obj->unlinkAllowed)
12954 + return yaffs_UnlinkWorker(obj);
12955
12956 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
12957 - ((oh &&
12958 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
12959 - (tags.extraHeaderInfoAvailable &&
12960 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
12961 - __u32 thisSize =
12962 - (oh) ? oh->fileSize : tags.
12963 - extraFileLength;
12964 - __u32 parentObjectId =
12965 - (oh) ? oh->
12966 - parentObjectId : tags.
12967 - extraParentObjectId;
12968 -
12969 -
12970 - isShrink =
12971 - (oh) ? oh->isShrink : tags.
12972 - extraIsShrinkHeader;
12973 + return YAFFS_FAIL;
12974
12975 - /* If it is deleted (unlinked at start also means deleted)
12976 - * we treat the file size as being zeroed at this point.
12977 - */
12978 - if (parentObjectId ==
12979 - YAFFS_OBJECTID_DELETED
12980 - || parentObjectId ==
12981 - YAFFS_OBJECTID_UNLINKED) {
12982 - thisSize = 0;
12983 - isShrink = 1;
12984 - }
12985 +}
12986 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
12987 +{
12988 + yaffs_Object *obj;
12989
12990 - if (isShrink &&
12991 - in->variant.fileVariant.
12992 - shrinkSize > thisSize) {
12993 - in->variant.fileVariant.
12994 - shrinkSize =
12995 - thisSize;
12996 - }
12997 + obj = yaffs_FindObjectByName(dir, name);
12998 + return yaffs_UnlinkObject(obj);
12999 +}
13000
13001 - if (isShrink)
13002 - bi->hasShrinkHeader = 1;
13003 +/*----------------------- Initialisation Scanning ---------------------- */
13004
13005 - }
13006 - /* Use existing - destroy this one. */
13007 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13008 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
13009 + int backwardScanning)
13010 +{
13011 + yaffs_Object *obj;
13012
13013 - }
13014 + if (!backwardScanning) {
13015 + /* Handle YAFFS1 forward scanning case
13016 + * For YAFFS1 we always do the deletion
13017 + */
13018
13019 - if (!in->valid && in->variantType !=
13020 - (oh ? oh->type : tags.extraObjectType))
13021 - T(YAFFS_TRACE_ERROR, (
13022 - TSTR("yaffs tragedy: Bad object type, "
13023 - TCONT("%d != %d, for object %d at chunk ")
13024 - TCONT("%d during scan")
13025 - TENDSTR), oh ?
13026 - oh->type : tags.extraObjectType,
13027 - in->variantType, tags.objectId,
13028 - chunk));
13029 -
13030 - if (!in->valid &&
13031 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13032 - tags.objectId ==
13033 - YAFFS_OBJECTID_LOSTNFOUND)) {
13034 - /* We only load some info, don't fiddle with directory structure */
13035 - in->valid = 1;
13036 + } else {
13037 + /* Handle YAFFS2 case (backward scanning)
13038 + * If the shadowed object exists then ignore.
13039 + */
13040 + obj = yaffs_FindObjectByNumber(dev, objId);
13041 + if(obj)
13042 + return;
13043 + }
13044
13045 - if (oh) {
13046 - in->variantType = oh->type;
13047 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13048 + * We put it in unlinked dir to be cleaned up after the scanning
13049 + */
13050 + obj =
13051 + yaffs_FindOrCreateObjectByNumber(dev, objId,
13052 + YAFFS_OBJECT_TYPE_FILE);
13053 + if (!obj)
13054 + return;
13055 + obj->isShadowed = 1;
13056 + yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
13057 + obj->variant.fileVariant.shrinkSize = 0;
13058 + obj->valid = 1; /* So that we don't read any other info for this file */
13059
13060 - in->yst_mode = oh->yst_mode;
13061 -#ifdef CONFIG_YAFFS_WINCE
13062 - in->win_atime[0] = oh->win_atime[0];
13063 - in->win_ctime[0] = oh->win_ctime[0];
13064 - in->win_mtime[0] = oh->win_mtime[0];
13065 - in->win_atime[1] = oh->win_atime[1];
13066 - in->win_ctime[1] = oh->win_ctime[1];
13067 - in->win_mtime[1] = oh->win_mtime[1];
13068 -#else
13069 - in->yst_uid = oh->yst_uid;
13070 - in->yst_gid = oh->yst_gid;
13071 - in->yst_atime = oh->yst_atime;
13072 - in->yst_mtime = oh->yst_mtime;
13073 - in->yst_ctime = oh->yst_ctime;
13074 - in->yst_rdev = oh->yst_rdev;
13075 +}
13076
13077 -#endif
13078 - } else {
13079 - in->variantType = tags.extraObjectType;
13080 - in->lazyLoaded = 1;
13081 - }
13082
13083 - in->hdrChunk = chunk;
13084 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
13085 +{
13086 + yaffs_Object *hl;
13087 + yaffs_Object *in;
13088
13089 - } else if (!in->valid) {
13090 - /* we need to load this info */
13091 + while (hardList) {
13092 + hl = hardList;
13093 + hardList = (yaffs_Object *) (hardList->hardLinks.next);
13094
13095 - in->valid = 1;
13096 - in->hdrChunk = chunk;
13097 + in = yaffs_FindObjectByNumber(dev,
13098 + hl->variant.hardLinkVariant.
13099 + equivalentObjectId);
13100
13101 - if (oh) {
13102 - in->variantType = oh->type;
13103 + if (in) {
13104 + /* Add the hardlink pointers */
13105 + hl->variant.hardLinkVariant.equivalentObject = in;
13106 + ylist_add(&hl->hardLinks, &in->hardLinks);
13107 + } else {
13108 + /* Todo Need to report/handle this better.
13109 + * Got a problem... hardlink to a non-existant object
13110 + */
13111 + hl->variant.hardLinkVariant.equivalentObject = NULL;
13112 + YINIT_LIST_HEAD(&hl->hardLinks);
13113
13114 - in->yst_mode = oh->yst_mode;
13115 -#ifdef CONFIG_YAFFS_WINCE
13116 - in->win_atime[0] = oh->win_atime[0];
13117 - in->win_ctime[0] = oh->win_ctime[0];
13118 - in->win_mtime[0] = oh->win_mtime[0];
13119 - in->win_atime[1] = oh->win_atime[1];
13120 - in->win_ctime[1] = oh->win_ctime[1];
13121 - in->win_mtime[1] = oh->win_mtime[1];
13122 -#else
13123 - in->yst_uid = oh->yst_uid;
13124 - in->yst_gid = oh->yst_gid;
13125 - in->yst_atime = oh->yst_atime;
13126 - in->yst_mtime = oh->yst_mtime;
13127 - in->yst_ctime = oh->yst_ctime;
13128 - in->yst_rdev = oh->yst_rdev;
13129 -#endif
13130 + }
13131 + }
13132 +}
13133
13134 - if (oh->shadowsObject > 0)
13135 - yaffs_HandleShadowedObject(dev,
13136 - oh->
13137 - shadowsObject,
13138 - 1);
13139 -
13140 -
13141 - yaffs_SetObjectName(in, oh->name);
13142 - parent =
13143 - yaffs_FindOrCreateObjectByNumber
13144 - (dev, oh->parentObjectId,
13145 - YAFFS_OBJECT_TYPE_DIRECTORY);
13146 -
13147 - fileSize = oh->fileSize;
13148 - isShrink = oh->isShrink;
13149 - equivalentObjectId = oh->equivalentObjectId;
13150
13151 - } else {
13152 - in->variantType = tags.extraObjectType;
13153 - parent =
13154 - yaffs_FindOrCreateObjectByNumber
13155 - (dev, tags.extraParentObjectId,
13156 - YAFFS_OBJECT_TYPE_DIRECTORY);
13157 - fileSize = tags.extraFileLength;
13158 - isShrink = tags.extraIsShrinkHeader;
13159 - equivalentObjectId = tags.extraEquivalentObjectId;
13160 - in->lazyLoaded = 1;
13161 +static void yaffs_StripDeletedObjects(yaffs_Device *dev)
13162 +{
13163 + /*
13164 + * Sort out state of unlinked and deleted objects after scanning.
13165 + */
13166 + struct ylist_head *i;
13167 + struct ylist_head *n;
13168 + yaffs_Object *l;
13169
13170 - }
13171 - in->dirty = 0;
13172 + if (dev->readOnly)
13173 + return;
13174
13175 - if (!parent)
13176 - alloc_failed = 1;
13177 + /* Soft delete all the unlinked files */
13178 + ylist_for_each_safe(i, n,
13179 + &dev->unlinkedDir->variant.directoryVariant.children) {
13180 + if (i) {
13181 + l = ylist_entry(i, yaffs_Object, siblings);
13182 + yaffs_DeleteObject(l);
13183 + }
13184 + }
13185
13186 - /* directory stuff...
13187 - * hook up to parent
13188 - */
13189 + ylist_for_each_safe(i, n,
13190 + &dev->deletedDir->variant.directoryVariant.children) {
13191 + if (i) {
13192 + l = ylist_entry(i, yaffs_Object, siblings);
13193 + yaffs_DeleteObject(l);
13194 + }
13195 + }
13196
13197 - if (parent && parent->variantType ==
13198 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13199 - /* Set up as a directory */
13200 - parent->variantType =
13201 - YAFFS_OBJECT_TYPE_DIRECTORY;
13202 - YINIT_LIST_HEAD(&parent->variant.
13203 - directoryVariant.
13204 - children);
13205 - } else if (!parent || parent->variantType !=
13206 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13207 - /* Hoosterman, another problem....
13208 - * We're trying to use a non-directory as a directory
13209 - */
13210 +}
13211
13212 - T(YAFFS_TRACE_ERROR,
13213 - (TSTR
13214 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13215 - TENDSTR)));
13216 - parent = dev->lostNFoundDir;
13217 - }
13218 +/*
13219 + * This code iterates through all the objects making sure that they are rooted.
13220 + * Any unrooted objects are re-rooted in lost+found.
13221 + * An object needs to be in one of:
13222 + * - Directly under deleted, unlinked
13223 + * - Directly or indirectly under root.
13224 + *
13225 + * Note:
13226 + * This code assumes that we don't ever change the current relationships between
13227 + * directories:
13228 + * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
13229 + * lostNfound->parent == rootDir
13230 + *
13231 + * This fixes the problem where directories might have inadvertently been deleted
13232 + * leaving the object "hanging" without being rooted in the directory tree.
13233 + */
13234 +
13235 +static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
13236 +{
13237 + return (obj == dev->deletedDir ||
13238 + obj == dev->unlinkedDir||
13239 + obj == dev->rootDir);
13240 +}
13241
13242 - yaffs_AddObjectToDirectory(parent, in);
13243 +static void yaffs_FixHangingObjects(yaffs_Device *dev)
13244 +{
13245 + yaffs_Object *obj;
13246 + yaffs_Object *parent;
13247 + int i;
13248 + struct ylist_head *lh;
13249 + struct ylist_head *n;
13250 + int depthLimit;
13251 + int hanging;
13252
13253 - itsUnlinked = (parent == dev->deletedDir) ||
13254 - (parent == dev->unlinkedDir);
13255 + if (dev->readOnly)
13256 + return;
13257
13258 - if (isShrink) {
13259 - /* Mark the block as having a shrinkHeader */
13260 - bi->hasShrinkHeader = 1;
13261 - }
13262 + /* Iterate through the objects in each hash entry,
13263 + * looking at each object.
13264 + * Make sure it is rooted.
13265 + */
13266
13267 - /* Note re hardlinks.
13268 - * Since we might scan a hardlink before its equivalent object is scanned
13269 - * we put them all in a list.
13270 - * After scanning is complete, we should have all the objects, so we run
13271 - * through this list and fix up all the chains.
13272 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13273 + ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
13274 + if (lh) {
13275 + obj = ylist_entry(lh, yaffs_Object, hashLink);
13276 + parent= obj->parent;
13277 +
13278 + if(yaffs_HasNULLParent(dev,obj)){
13279 + /* These directories are not hanging */
13280 + hanging = 0;
13281 + }
13282 + else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13283 + hanging = 1;
13284 + else if(yaffs_HasNULLParent(dev,parent))
13285 + hanging = 0;
13286 + else {
13287 + /*
13288 + * Need to follow the parent chain to see if it is hanging.
13289 */
13290 + hanging = 0;
13291 + depthLimit=100;
13292
13293 - switch (in->variantType) {
13294 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13295 - /* Todo got a problem */
13296 - break;
13297 - case YAFFS_OBJECT_TYPE_FILE:
13298 -
13299 - if (in->variant.fileVariant.
13300 - scannedFileSize < fileSize) {
13301 - /* This covers the case where the file size is greater
13302 - * than where the data is
13303 - * This will happen if the file is resized to be larger
13304 - * than its current data extents.
13305 - */
13306 - in->variant.fileVariant.fileSize = fileSize;
13307 - in->variant.fileVariant.scannedFileSize =
13308 - in->variant.fileVariant.fileSize;
13309 - }
13310 -
13311 - if (isShrink &&
13312 - in->variant.fileVariant.shrinkSize > fileSize) {
13313 - in->variant.fileVariant.shrinkSize = fileSize;
13314 - }
13315 -
13316 - break;
13317 - case YAFFS_OBJECT_TYPE_HARDLINK:
13318 - if (!itsUnlinked) {
13319 - in->variant.hardLinkVariant.equivalentObjectId =
13320 - equivalentObjectId;
13321 - in->hardLinks.next =
13322 - (struct ylist_head *) hardList;
13323 - hardList = in;
13324 - }
13325 - break;
13326 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13327 - /* Do nothing */
13328 - break;
13329 - case YAFFS_OBJECT_TYPE_SPECIAL:
13330 - /* Do nothing */
13331 - break;
13332 - case YAFFS_OBJECT_TYPE_SYMLINK:
13333 - if (oh) {
13334 - in->variant.symLinkVariant.alias =
13335 - yaffs_CloneString(oh->alias);
13336 - if (!in->variant.symLinkVariant.alias)
13337 - alloc_failed = 1;
13338 - }
13339 - break;
13340 + while(parent != dev->rootDir &&
13341 + parent->parent &&
13342 + parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
13343 + depthLimit > 0){
13344 + parent = parent->parent;
13345 + depthLimit--;
13346 }
13347 -
13348 + if(parent != dev->rootDir)
13349 + hanging = 1;
13350 + }
13351 + if(hanging){
13352 + T(YAFFS_TRACE_SCAN,
13353 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13354 + obj->objectId));
13355 + yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
13356 }
13357 -
13358 }
13359 + }
13360 + }
13361 +}
13362
13363 - } /* End of scanning for each chunk */
13364
13365 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13366 - /* If we got this far while scanning, then the block is fully allocated. */
13367 - state = YAFFS_BLOCK_STATE_FULL;
13368 - }
13369 +/*
13370 + * Delete directory contents for cleaning up lost and found.
13371 + */
13372 +static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
13373 +{
13374 + yaffs_Object *obj;
13375 + struct ylist_head *lh;
13376 + struct ylist_head *n;
13377
13378 - bi->blockState = state;
13379 + if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13380 + YBUG();
13381 +
13382 + ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
13383 + if (lh) {
13384 + obj = ylist_entry(lh, yaffs_Object, siblings);
13385 + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
13386 + yaffs_DeleteDirectoryContents(obj);
13387 +
13388 + T(YAFFS_TRACE_SCAN,
13389 + (TSTR("Deleting lost_found object %d" TENDSTR),
13390 + obj->objectId));
13391
13392 - /* Now let's see if it was dirty */
13393 - if (bi->pagesInUse == 0 &&
13394 - !bi->hasShrinkHeader &&
13395 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13396 - yaffs_BlockBecameDirty(dev, blk);
13397 + /* Need to use UnlinkObject since Delete would not handle
13398 + * hardlinked objects correctly.
13399 + */
13400 + yaffs_UnlinkObject(obj);
13401 }
13402 -
13403 }
13404 +
13405 +}
13406
13407 - if (altBlockIndex)
13408 - YFREE_ALT(blockIndex);
13409 - else
13410 - YFREE(blockIndex);
13411 +static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
13412 +{
13413 + yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
13414 +}
13415
13416 - /* Ok, we've done all the scanning.
13417 - * Fix up the hard link chains.
13418 - * We should now have scanned all the objects, now it's time to add these
13419 - * hardlinks.
13420 - */
13421 - yaffs_HardlinkFixup(dev, hardList);
13422 +static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
13423 +{
13424 + __u8 *chunkData;
13425 + yaffs_ObjectHeader *oh;
13426 + yaffs_Device *dev;
13427 + yaffs_ExtendedTags tags;
13428 + int result;
13429 + int alloc_failed = 0;
13430
13431 + if (!in)
13432 + return;
13433
13434 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13435 + dev = in->myDev;
13436
13437 - if (alloc_failed)
13438 - return YAFFS_FAIL;
13439 +#if 0
13440 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
13441 + in->objectId,
13442 + in->lazyLoaded ? "not yet" : "already"));
13443 +#endif
13444
13445 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
13446 + if (in->lazyLoaded && in->hdrChunk > 0) {
13447 + in->lazyLoaded = 0;
13448 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13449
13450 - return YAFFS_OK;
13451 -}
13452 + result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
13453 + oh = (yaffs_ObjectHeader *) chunkData;
13454
13455 -/*------------------------------ Directory Functions ----------------------------- */
13456 + in->yst_mode = oh->yst_mode;
13457 +#ifdef CONFIG_YAFFS_WINCE
13458 + in->win_atime[0] = oh->win_atime[0];
13459 + in->win_ctime[0] = oh->win_ctime[0];
13460 + in->win_mtime[0] = oh->win_mtime[0];
13461 + in->win_atime[1] = oh->win_atime[1];
13462 + in->win_ctime[1] = oh->win_ctime[1];
13463 + in->win_mtime[1] = oh->win_mtime[1];
13464 +#else
13465 + in->yst_uid = oh->yst_uid;
13466 + in->yst_gid = oh->yst_gid;
13467 + in->yst_atime = oh->yst_atime;
13468 + in->yst_mtime = oh->yst_mtime;
13469 + in->yst_ctime = oh->yst_ctime;
13470 + in->yst_rdev = oh->yst_rdev;
13471
13472 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
13473 -{
13474 - struct ylist_head *lh;
13475 - yaffs_Object *listObj;
13476 +#endif
13477 + yaffs_SetObjectNameFromOH(in, oh);
13478
13479 - int count = 0;
13480 + if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
13481 + in->variant.symLinkVariant.alias =
13482 + yaffs_CloneString(oh->alias);
13483 + if (!in->variant.symLinkVariant.alias)
13484 + alloc_failed = 1; /* Not returned to caller */
13485 + }
13486
13487 - if (!obj) {
13488 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
13489 - YBUG();
13490 - return;
13491 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13492 }
13493 +}
13494
13495 - if (yaffs_SkipVerification(obj->myDev))
13496 - return;
13497 +/*------------------------------ Directory Functions ----------------------------- */
13498
13499 - if (!obj->parent) {
13500 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
13501 - YBUG();
13502 +/*
13503 + *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
13504 + * link (ie. name) is created or deleted in the directory.
13505 + *
13506 + * ie.
13507 + * create dir/a : update dir's mtime/ctime
13508 + * rm dir/a: update dir's mtime/ctime
13509 + * modify dir/a: don't update dir's mtimme/ctime
13510 + *
13511 + * This can be handled immediately or defered. Defering helps reduce the number
13512 + * of updates when many files in a directory are changed within a brief period.
13513 + *
13514 + * If the directory updating is defered then yaffs_UpdateDirtyDirecories must be
13515 + * called periodically.
13516 + */
13517 +
13518 +static void yaffs_UpdateParent(yaffs_Object *obj)
13519 +{
13520 + yaffs_Device *dev;
13521 + if(!obj)
13522 return;
13523 - }
13524 -
13525 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13526 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
13527 - YBUG();
13528 - }
13529 -
13530 - /* Iterate through the objects in each hash entry */
13531 +#ifndef CONFIG_YAFFS_WINCE
13532
13533 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
13534 - if (lh) {
13535 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13536 - yaffs_VerifyObject(listObj);
13537 - if (obj == listObj)
13538 - count++;
13539 + dev = obj->myDev;
13540 + obj->dirty = 1;
13541 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
13542 + if(dev->param.deferDirectoryUpdate){
13543 + struct ylist_head *link = &obj->variant.directoryVariant.dirty;
13544 +
13545 + if(ylist_empty(link)){
13546 + ylist_add(link,&dev->dirtyDirectories);
13547 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->objectId));
13548 }
13549 - }
13550
13551 - if (count != 1) {
13552 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
13553 - YBUG();
13554 - }
13555 + } else
13556 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13557 +#endif
13558 }
13559
13560 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
13561 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
13562 {
13563 - struct ylist_head *lh;
13564 - yaffs_Object *listObj;
13565 -
13566 - if (!directory) {
13567 - YBUG();
13568 - return;
13569 - }
13570 + struct ylist_head *link;
13571 + yaffs_Object *obj;
13572 + yaffs_DirectoryStructure *dS;
13573 + yaffs_ObjectVariant *oV;
13574
13575 - if (yaffs_SkipFullVerification(directory->myDev))
13576 - return;
13577 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
13578
13579 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13580 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
13581 - YBUG();
13582 - }
13583 + while(!ylist_empty(&dev->dirtyDirectories)){
13584 + link = dev->dirtyDirectories.next;
13585 + ylist_del_init(link);
13586 +
13587 + dS=ylist_entry(link,yaffs_DirectoryStructure,dirty);
13588 + oV = ylist_entry(dS,yaffs_ObjectVariant,directoryVariant);
13589 + obj = ylist_entry(oV,yaffs_Object,variant);
13590
13591 - /* Iterate through the objects in each hash entry */
13592 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId));
13593
13594 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
13595 - if (lh) {
13596 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13597 - if (listObj->parent != directory) {
13598 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
13599 - YBUG();
13600 - }
13601 - yaffs_VerifyObjectInDirectory(listObj);
13602 - }
13603 + if(obj->dirty)
13604 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13605 }
13606 }
13607
13608 -
13609 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
13610 {
13611 yaffs_Device *dev = obj->myDev;
13612 @@ -6677,18 +4474,17 @@ static void yaffs_RemoveObjectFromDirect
13613
13614 yaffs_VerifyDirectory(parent);
13615
13616 - if (dev && dev->removeObjectCallback)
13617 - dev->removeObjectCallback(obj);
13618 + if (dev && dev->param.removeObjectCallback)
13619 + dev->param.removeObjectCallback(obj);
13620
13621
13622 ylist_del_init(&obj->siblings);
13623 obj->parent = NULL;
13624 -
13625 +
13626 yaffs_VerifyDirectory(parent);
13627 }
13628
13629 -
13630 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13631 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13632 yaffs_Object *obj)
13633 {
13634 if (!directory) {
13635 @@ -6781,7 +4577,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
13636 * Do a real check
13637 */
13638 yaffs_GetObjectName(l, buffer,
13639 - YAFFS_MAX_NAME_LENGTH);
13640 + YAFFS_MAX_NAME_LENGTH + 1);
13641 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
13642 return l;
13643 }
13644 @@ -6842,36 +4638,124 @@ yaffs_Object *yaffs_GetEquivalentObject(
13645 return obj;
13646 }
13647
13648 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
13649 -{
13650 - memset(name, 0, buffSize * sizeof(YCHAR));
13651 -
13652 - yaffs_CheckObjectDetailsLoaded(obj);
13653 +/*
13654 + * A note or two on object names.
13655 + * * If the object name is missing, we then make one up in the form objnnn
13656 + *
13657 + * * ASCII names are stored in the object header's name field from byte zero
13658 + * * Unicode names are historically stored starting from byte zero.
13659 + *
13660 + * Then there are automatic Unicode names...
13661 + * The purpose of these is to save names in a way that can be read as
13662 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
13663 + * system to share files.
13664 + *
13665 + * These automatic unicode are stored slightly differently...
13666 + * - If the name can fit in the ASCII character space then they are saved as
13667 + * ascii names as per above.
13668 + * - If the name needs Unicode then the name is saved in Unicode
13669 + * starting at oh->name[1].
13670
13671 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13672 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13673 - } else if (obj->hdrChunk <= 0) {
13674 + */
13675 +static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize)
13676 +{
13677 + /* Create an object name if we could not find one. */
13678 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
13679 YCHAR locName[20];
13680 YCHAR numString[20];
13681 YCHAR *x = &numString[19];
13682 unsigned v = obj->objectId;
13683 numString[19] = 0;
13684 - while (v > 0) {
13685 + while(v>0){
13686 x--;
13687 *x = '0' + (v % 10);
13688 v /= 10;
13689 }
13690 /* make up a name */
13691 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
13692 - yaffs_strcat(locName, x);
13693 + yaffs_strcat(locName,x);
13694 yaffs_strncpy(name, locName, buffSize - 1);
13695 + }
13696 +}
13697 +
13698 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
13699 +{
13700 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13701 + if(dev->param.autoUnicode){
13702 + if(*ohName){
13703 + /* It is an ASCII name, so do an ASCII to unicode conversion */
13704 + const char *asciiOhName = (const char *)ohName;
13705 + int n = bufferSize - 1;
13706 + while(n > 0 && *asciiOhName){
13707 + *name = *asciiOhName;
13708 + name++;
13709 + asciiOhName++;
13710 + n--;
13711 + }
13712 + } else
13713 + yaffs_strncpy(name,ohName+1, bufferSize -1);
13714 + } else
13715 +#endif
13716 + yaffs_strncpy(name, ohName, bufferSize - 1);
13717 +}
13718 +
13719 +
13720 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name)
13721 +{
13722 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13723 +
13724 + int isAscii;
13725 + YCHAR *w;
13726
13727 + if(dev->param.autoUnicode){
13728 +
13729 + isAscii = 1;
13730 + w = name;
13731 +
13732 + /* Figure out if the name will fit in ascii character set */
13733 + while(isAscii && *w){
13734 + if((*w) & 0xff00)
13735 + isAscii = 0;
13736 + w++;
13737 + }
13738 +
13739 + if(isAscii){
13740 + /* It is an ASCII name, so do a unicode to ascii conversion */
13741 + char *asciiOhName = (char *)ohName;
13742 + int n = YAFFS_MAX_NAME_LENGTH - 1;
13743 + while(n > 0 && *name){
13744 + *asciiOhName= *name;
13745 + name++;
13746 + asciiOhName++;
13747 + n--;
13748 + }
13749 + } else{
13750 + /* It is a unicode name, so save starting at the second YCHAR */
13751 + *ohName = 0;
13752 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
13753 + }
13754 }
13755 + else
13756 +#endif
13757 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
13758 +
13759 +}
13760 +
13761 +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
13762 +{
13763 + memset(name, 0, buffSize * sizeof(YCHAR));
13764 +
13765 + yaffs_CheckObjectDetailsLoaded(obj);
13766 +
13767 + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13768 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13769 + }
13770 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
13771 - else if (obj->shortName[0])
13772 + else if (obj->shortName[0]) {
13773 yaffs_strcpy(name, obj->shortName);
13774 + }
13775 #endif
13776 - else {
13777 + else if(obj->hdrChunk > 0) {
13778 int result;
13779 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
13780
13781 @@ -6884,14 +4768,17 @@ int yaffs_GetObjectName(yaffs_Object *ob
13782 obj->hdrChunk, buffer,
13783 NULL);
13784 }
13785 - yaffs_strncpy(name, oh->name, buffSize - 1);
13786 + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize);
13787
13788 yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
13789 }
13790
13791 - return yaffs_strlen(name);
13792 + yaffs_FixNullName(obj,name,buffSize);
13793 +
13794 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
13795 }
13796
13797 +
13798 int yaffs_GetObjectFileLength(yaffs_Object *obj)
13799 {
13800 /* Dereference any hard linking */
13801 @@ -6899,9 +4786,11 @@ int yaffs_GetObjectFileLength(yaffs_Obje
13802
13803 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
13804 return obj->variant.fileVariant.fileSize;
13805 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
13806 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
13807 - else {
13808 + if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
13809 + if(!obj->variant.symLinkVariant.alias)
13810 + return 0;
13811 + return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
13812 + } else {
13813 /* Only a directory should drop through to here */
13814 return obj->myDev->nDataBytesPerChunk;
13815 }
13816 @@ -6992,7 +4881,7 @@ int yaffs_SetAttributes(yaffs_Object *ob
13817 if (valid & ATTR_SIZE)
13818 yaffs_ResizeFile(obj, attr->ia_size);
13819
13820 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
13821 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
13822
13823 return YAFFS_OK;
13824
13825 @@ -7025,12 +4914,129 @@ int yaffs_GetAttributes(yaffs_Object *ob
13826
13827 #endif
13828
13829 +
13830 +static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags)
13831 +{
13832 + yaffs_XAttrMod xmod;
13833 +
13834 + int result;
13835 +
13836 + xmod.set = set;
13837 + xmod.name = name;
13838 + xmod.data = value;
13839 + xmod.size = size;
13840 + xmod.flags = flags;
13841 + xmod.result = -ENOSPC;
13842 +
13843 + result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod);
13844 +
13845 + if(result > 0)
13846 + return xmod.result;
13847 + else
13848 + return -ENOSPC;
13849 +}
13850 +
13851 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod)
13852 +{
13853 + int retval = 0;
13854 + int x_offs = sizeof(yaffs_ObjectHeader);
13855 + yaffs_Device *dev = obj->myDev;
13856 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13857 +
13858 + char * x_buffer = buffer + x_offs;
13859 +
13860 + if(xmod->set)
13861 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
13862 + else
13863 + retval = nval_del(x_buffer, x_size, xmod->name);
13864 +
13865 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13866 + obj->xattrKnown = 1;
13867 +
13868 + xmod->result = retval;
13869 +
13870 + return retval;
13871 +}
13872 +
13873 +static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13874 +{
13875 + char *buffer = NULL;
13876 + int result;
13877 + yaffs_ExtendedTags tags;
13878 + yaffs_Device *dev = obj->myDev;
13879 + int x_offs = sizeof(yaffs_ObjectHeader);
13880 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13881 +
13882 + char * x_buffer;
13883 +
13884 + int retval = 0;
13885 +
13886 + if(obj->hdrChunk < 1)
13887 + return -ENODATA;
13888 +
13889 + /* If we know that the object has no xattribs then don't do all the
13890 + * reading and parsing.
13891 + */
13892 + if(obj->xattrKnown && !obj->hasXattr){
13893 + if(name)
13894 + return -ENODATA;
13895 + else
13896 + return 0;
13897 + }
13898 +
13899 + buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__);
13900 + if(!buffer)
13901 + return -ENOMEM;
13902 +
13903 + result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags);
13904 +
13905 + if(result != YAFFS_OK)
13906 + retval = -ENOENT;
13907 + else{
13908 + x_buffer = buffer + x_offs;
13909 +
13910 + if (!obj->xattrKnown){
13911 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13912 + obj->xattrKnown = 1;
13913 + }
13914 +
13915 + if(name)
13916 + retval = nval_get(x_buffer, x_size, name, value, size);
13917 + else
13918 + retval = nval_list(x_buffer, x_size, value,size);
13919 + }
13920 + yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__);
13921 + return retval;
13922 +}
13923 +
13924 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags)
13925 +{
13926 + return yaffs_DoXMod(obj, 1, name, value, size, flags);
13927 +}
13928 +
13929 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name)
13930 +{
13931 + return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
13932 +}
13933 +
13934 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13935 +{
13936 + return yaffs_DoXFetch(obj, name, value, size);
13937 +}
13938 +
13939 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size)
13940 +{
13941 + return yaffs_DoXFetch(obj, NULL, buffer,size);
13942 +}
13943 +
13944 +
13945 +
13946 #if 0
13947 int yaffs_DumpObject(yaffs_Object *obj)
13948 {
13949 YCHAR name[257];
13950
13951 - yaffs_GetObjectName(obj, name, 256);
13952 + yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
13953
13954 T(YAFFS_TRACE_ALWAYS,
13955 (TSTR
13956 @@ -7050,30 +5056,32 @@ static int yaffs_CheckDevFunctions(const
13957 {
13958
13959 /* Common functions, gotta have */
13960 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
13961 + if (!dev->param.eraseBlockInNAND || !dev->param.initialiseNAND)
13962 return 0;
13963
13964 #ifdef CONFIG_YAFFS_YAFFS2
13965
13966 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
13967 - if (dev->writeChunkWithTagsToNAND &&
13968 - dev->readChunkWithTagsFromNAND &&
13969 - !dev->writeChunkToNAND &&
13970 - !dev->readChunkFromNAND &&
13971 - dev->markNANDBlockBad && dev->queryNANDBlock)
13972 + if (dev->param.writeChunkWithTagsToNAND &&
13973 + dev->param.readChunkWithTagsFromNAND &&
13974 + !dev->param.writeChunkToNAND &&
13975 + !dev->param.readChunkFromNAND &&
13976 + dev->param.markNANDBlockBad &&
13977 + dev->param.queryNANDBlock)
13978 return 1;
13979 #endif
13980
13981 /* Can use the "spare" style interface for yaffs1 */
13982 - if (!dev->isYaffs2 &&
13983 - !dev->writeChunkWithTagsToNAND &&
13984 - !dev->readChunkWithTagsFromNAND &&
13985 - dev->writeChunkToNAND &&
13986 - dev->readChunkFromNAND &&
13987 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
13988 + if (!dev->param.isYaffs2 &&
13989 + !dev->param.writeChunkWithTagsToNAND &&
13990 + !dev->param.readChunkWithTagsFromNAND &&
13991 + dev->param.writeChunkToNAND &&
13992 + dev->param.readChunkFromNAND &&
13993 + !dev->param.markNANDBlockBad &&
13994 + !dev->param.queryNANDBlock)
13995 return 1;
13996
13997 - return 0; /* bad */
13998 + return 0; /* bad */
13999 }
14000
14001
14002 @@ -7120,35 +5128,35 @@ int yaffs_GutsInitialise(yaffs_Device *d
14003 return YAFFS_FAIL;
14004 }
14005
14006 - dev->internalStartBlock = dev->startBlock;
14007 - dev->internalEndBlock = dev->endBlock;
14008 + dev->internalStartBlock = dev->param.startBlock;
14009 + dev->internalEndBlock = dev->param.endBlock;
14010 dev->blockOffset = 0;
14011 dev->chunkOffset = 0;
14012 dev->nFreeChunks = 0;
14013
14014 - dev->gcBlock = -1;
14015 + dev->gcBlock = 0;
14016
14017 - if (dev->startBlock == 0) {
14018 - dev->internalStartBlock = dev->startBlock + 1;
14019 - dev->internalEndBlock = dev->endBlock + 1;
14020 + if (dev->param.startBlock == 0) {
14021 + dev->internalStartBlock = dev->param.startBlock + 1;
14022 + dev->internalEndBlock = dev->param.endBlock + 1;
14023 dev->blockOffset = 1;
14024 - dev->chunkOffset = dev->nChunksPerBlock;
14025 + dev->chunkOffset = dev->param.nChunksPerBlock;
14026 }
14027
14028 /* Check geometry parameters. */
14029
14030 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14031 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14032 - (dev->inbandTags && !dev->isYaffs2) ||
14033 - dev->nChunksPerBlock < 2 ||
14034 - dev->nReservedBlocks < 2 ||
14035 + if ((!dev->param.inbandTags && dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 1024) ||
14036 + (!dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 512) ||
14037 + (dev->param.inbandTags && !dev->param.isYaffs2) ||
14038 + dev->param.nChunksPerBlock < 2 ||
14039 + dev->param.nReservedBlocks < 2 ||
14040 dev->internalStartBlock <= 0 ||
14041 dev->internalEndBlock <= 0 ||
14042 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14043 + dev->internalEndBlock <= (dev->internalStartBlock + dev->param.nReservedBlocks + 2)) { /* otherwise it is too small */
14044 T(YAFFS_TRACE_ALWAYS,
14045 (TSTR
14046 ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14047 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14048 + TENDSTR), dev->param.totalBytesPerChunk, dev->param.isYaffs2 ? "2" : "", dev->param.inbandTags));
14049 return YAFFS_FAIL;
14050 }
14051
14052 @@ -7159,10 +5167,10 @@ int yaffs_GutsInitialise(yaffs_Device *d
14053 }
14054
14055 /* Sort out space for inband tags, if required */
14056 - if (dev->inbandTags)
14057 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14058 + if (dev->param.inbandTags)
14059 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14060 else
14061 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
14062 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk;
14063
14064 /* Got the right mix of functions? */
14065 if (!yaffs_CheckDevFunctions(dev)) {
14066 @@ -7209,12 +5217,12 @@ int yaffs_GutsInitialise(yaffs_Device *d
14067 * We need to find the next power of 2 > than internalEndBlock
14068 */
14069
14070 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
14071 + x = dev->param.nChunksPerBlock * (dev->internalEndBlock + 1);
14072
14073 bits = ShiftsGE(x);
14074
14075 /* Set up tnode width if wide tnodes are enabled. */
14076 - if (!dev->wideTnodesDisabled) {
14077 + if (!dev->param.wideTnodesDisabled) {
14078 /* bits must be even so that we end up with 32-bit words */
14079 if (bits & 1)
14080 bits++;
14081 @@ -7238,10 +5246,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14082 else
14083 dev->chunkGroupBits = bits - dev->tnodeWidth;
14084
14085 + dev->tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
14086 + if(dev->tnodeSize < sizeof(yaffs_Tnode))
14087 + dev->tnodeSize = sizeof(yaffs_Tnode);
14088
14089 dev->chunkGroupSize = 1 << dev->chunkGroupBits;
14090
14091 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
14092 + if (dev->param.nChunksPerBlock < dev->chunkGroupSize) {
14093 /* We have a problem because the soft delete won't work if
14094 * the chunk group size > chunks per block.
14095 * This can be remedied by using larger "virtual blocks".
14096 @@ -7255,9 +5266,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14097 /* OK, we've finished verifying the device, lets continue with initialisation */
14098
14099 /* More device initialisation */
14100 - dev->garbageCollections = 0;
14101 - dev->passiveGarbageCollections = 0;
14102 - dev->currentDirtyChecker = 0;
14103 + dev->allGCs = 0;
14104 + dev->passiveGCs = 0;
14105 + dev->oldestDirtyGCs = 0;
14106 + dev->backgroundGCs = 0;
14107 + dev->gcBlockFinder = 0;
14108 dev->bufferedBlock = -1;
14109 dev->doingBufferedBlockRewrite = 0;
14110 dev->nDeletedFiles = 0;
14111 @@ -7269,8 +5282,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14112 dev->tagsEccUnfixed = 0;
14113 dev->nErasureFailures = 0;
14114 dev->nErasedBlocks = 0;
14115 - dev->isDoingGC = 0;
14116 + dev->gcDisable= 0;
14117 dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
14118 + YINIT_LIST_HEAD(&dev->dirtyDirectories);
14119 + dev->oldestDirtySequence = 0;
14120 + dev->oldestDirtyBlock = 0;
14121
14122 /* Initialise temporary buffers and caches. */
14123 if (!yaffs_InitialiseTempBuffers(dev))
14124 @@ -7281,13 +5297,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14125
14126
14127 if (!init_failed &&
14128 - dev->nShortOpCaches > 0) {
14129 + dev->param.nShortOpCaches > 0) {
14130 int i;
14131 void *buf;
14132 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
14133 + int srCacheBytes = dev->param.nShortOpCaches * sizeof(yaffs_ChunkCache);
14134
14135 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14136 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14137 + if (dev->param.nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14138 + dev->param.nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14139
14140 dev->srCache = YMALLOC(srCacheBytes);
14141
14142 @@ -7296,11 +5312,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14143 if (dev->srCache)
14144 memset(dev->srCache, 0, srCacheBytes);
14145
14146 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
14147 + for (i = 0; i < dev->param.nShortOpCaches && buf; i++) {
14148 dev->srCache[i].object = NULL;
14149 dev->srCache[i].lastUse = 0;
14150 dev->srCache[i].dirty = 0;
14151 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
14152 + dev->srCache[i].data = buf = YMALLOC_DMA(dev->param.totalBytesPerChunk);
14153 }
14154 if (!buf)
14155 init_failed = 1;
14156 @@ -7311,19 +5327,18 @@ int yaffs_GutsInitialise(yaffs_Device *d
14157 dev->cacheHits = 0;
14158
14159 if (!init_failed) {
14160 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
14161 + dev->gcCleanupList = YMALLOC(dev->param.nChunksPerBlock * sizeof(__u32));
14162 if (!dev->gcCleanupList)
14163 init_failed = 1;
14164 }
14165
14166 - if (dev->isYaffs2)
14167 - dev->useHeaderFileSize = 1;
14168 + if (dev->param.isYaffs2)
14169 + dev->param.useHeaderFileSize = 1;
14170
14171 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14172 init_failed = 1;
14173
14174 - yaffs_InitialiseTnodes(dev);
14175 - yaffs_InitialiseObjects(dev);
14176 + yaffs_InitialiseTnodesAndObjects(dev);
14177
14178 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14179 init_failed = 1;
14180 @@ -7331,8 +5346,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14181
14182 if (!init_failed) {
14183 /* Now scan the flash. */
14184 - if (dev->isYaffs2) {
14185 - if (yaffs_CheckpointRestore(dev)) {
14186 + if (dev->param.isYaffs2) {
14187 + if (yaffs2_CheckpointRestore(dev)) {
14188 yaffs_CheckObjectDetailsLoaded(dev->rootDir);
14189 T(YAFFS_TRACE_ALWAYS,
14190 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
14191 @@ -7342,9 +5357,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14192 * and scan backwards.
14193 */
14194 yaffs_DeinitialiseBlocks(dev);
14195 - yaffs_DeinitialiseTnodes(dev);
14196 - yaffs_DeinitialiseObjects(dev);
14197
14198 + yaffs_DeinitialiseTnodesAndObjects(dev);
14199
14200 dev->nErasedBlocks = 0;
14201 dev->nFreeChunks = 0;
14202 @@ -7353,24 +5367,25 @@ int yaffs_GutsInitialise(yaffs_Device *d
14203 dev->nDeletedFiles = 0;
14204 dev->nUnlinkedFiles = 0;
14205 dev->nBackgroundDeletions = 0;
14206 - dev->oldestDirtySequence = 0;
14207
14208 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14209 init_failed = 1;
14210
14211 - yaffs_InitialiseTnodes(dev);
14212 - yaffs_InitialiseObjects(dev);
14213 + yaffs_InitialiseTnodesAndObjects(dev);
14214
14215 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14216 init_failed = 1;
14217
14218 - if (!init_failed && !yaffs_ScanBackwards(dev))
14219 + if (!init_failed && !yaffs2_ScanBackwards(dev))
14220 init_failed = 1;
14221 }
14222 - } else if (!yaffs_Scan(dev))
14223 + } else if (!yaffs1_Scan(dev))
14224 init_failed = 1;
14225
14226 yaffs_StripDeletedObjects(dev);
14227 + yaffs_FixHangingObjects(dev);
14228 + if(dev->param.emptyLostAndFound)
14229 + yaffs_EmptyLostAndFound(dev);
14230 }
14231
14232 if (init_failed) {
14233 @@ -7394,6 +5409,9 @@ int yaffs_GutsInitialise(yaffs_Device *d
14234 yaffs_VerifyFreeChunks(dev);
14235 yaffs_VerifyBlocks(dev);
14236
14237 + /* Clean up any aborted checkpoint data */
14238 + if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
14239 + yaffs2_InvalidateCheckpoint(dev);
14240
14241 T(YAFFS_TRACE_TRACING,
14242 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
14243 @@ -7407,12 +5425,11 @@ void yaffs_Deinitialise(yaffs_Device *de
14244 int i;
14245
14246 yaffs_DeinitialiseBlocks(dev);
14247 - yaffs_DeinitialiseTnodes(dev);
14248 - yaffs_DeinitialiseObjects(dev);
14249 - if (dev->nShortOpCaches > 0 &&
14250 + yaffs_DeinitialiseTnodesAndObjects(dev);
14251 + if (dev->param.nShortOpCaches > 0 &&
14252 dev->srCache) {
14253
14254 - for (i = 0; i < dev->nShortOpCaches; i++) {
14255 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
14256 if (dev->srCache[i].data)
14257 YFREE(dev->srCache[i].data);
14258 dev->srCache[i].data = NULL;
14259 @@ -7429,34 +5446,33 @@ void yaffs_Deinitialise(yaffs_Device *de
14260
14261 dev->isMounted = 0;
14262
14263 - if (dev->deinitialiseNAND)
14264 - dev->deinitialiseNAND(dev);
14265 + if (dev->param.deinitialiseNAND)
14266 + dev->param.deinitialiseNAND(dev);
14267 }
14268 }
14269
14270 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
14271 +int yaffs_CountFreeChunks(yaffs_Device *dev)
14272 {
14273 - int nFree;
14274 + int nFree=0;
14275 int b;
14276
14277 yaffs_BlockInfo *blk;
14278
14279 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
14280 - b++) {
14281 - blk = yaffs_GetBlockInfo(dev, b);
14282 -
14283 + blk = dev->blockInfo;
14284 + for (b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) {
14285 switch (blk->blockState) {
14286 case YAFFS_BLOCK_STATE_EMPTY:
14287 case YAFFS_BLOCK_STATE_ALLOCATING:
14288 case YAFFS_BLOCK_STATE_COLLECTING:
14289 case YAFFS_BLOCK_STATE_FULL:
14290 nFree +=
14291 - (dev->nChunksPerBlock - blk->pagesInUse +
14292 + (dev->param.nChunksPerBlock - blk->pagesInUse +
14293 blk->softDeletions);
14294 break;
14295 default:
14296 break;
14297 }
14298 + blk++;
14299 }
14300
14301 return nFree;
14302 @@ -7481,21 +5497,19 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14303
14304 /* Now count the number of dirty chunks in the cache and subtract those */
14305
14306 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
14307 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.nShortOpCaches; i++) {
14308 if (dev->srCache[i].dirty)
14309 nDirtyCacheChunks++;
14310 }
14311
14312 nFree -= nDirtyCacheChunks;
14313
14314 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
14315 + nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock);
14316
14317 /* Now we figure out how much to reserve for the checkpoint and report that... */
14318 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
14319 - if (blocksForCheckpoint < 0)
14320 - blocksForCheckpoint = 0;
14321 + blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev);
14322
14323 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
14324 + nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock);
14325
14326 if (nFree < 0)
14327 nFree = 0;
14328 @@ -7504,27 +5518,6 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14329
14330 }
14331
14332 -static int yaffs_freeVerificationFailures;
14333 -
14334 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
14335 -{
14336 - int counted;
14337 - int difference;
14338 -
14339 - if (yaffs_SkipVerification(dev))
14340 - return;
14341 -
14342 - counted = yaffs_CountFreeChunks(dev);
14343 -
14344 - difference = dev->nFreeChunks - counted;
14345 -
14346 - if (difference) {
14347 - T(YAFFS_TRACE_ALWAYS,
14348 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
14349 - dev->nFreeChunks, counted, difference));
14350 - yaffs_freeVerificationFailures++;
14351 - }
14352 -}
14353
14354 /*---------------------------------------- YAFFS test code ----------------------*/
14355
14356 @@ -7532,7 +5525,7 @@ static void yaffs_VerifyFreeChunks(yaffs
14357 do { \
14358 if (sizeof(structure) != syze) { \
14359 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
14360 - name, syze, sizeof(structure))); \
14361 + name, syze, (int) sizeof(structure))); \
14362 return YAFFS_FAIL; \
14363 } \
14364 } while (0)
14365 @@ -7542,9 +5535,8 @@ static int yaffs_CheckStructures(void)
14366 /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
14367 /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
14368 /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
14369 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
14370 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
14371 -#endif
14372 +/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
14373 +
14374 #ifndef CONFIG_YAFFS_WINCE
14375 yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
14376 #endif
14377 --- a/fs/yaffs2/yaffs_guts.h
14378 +++ b/fs/yaffs2/yaffs_guts.h
14379 @@ -1,7 +1,7 @@
14380 /*
14381 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14382 *
14383 - * Copyright (C) 2002-2007 Aleph One Ltd.
14384 + * Copyright (C) 2002-2010 Aleph One Ltd.
14385 * for Toby Churchill Ltd and Brightstar Engineering
14386 *
14387 * Created by Charles Manning <charles@aleph1.co.uk>
14388 @@ -16,8 +16,9 @@
14389 #ifndef __YAFFS_GUTS_H__
14390 #define __YAFFS_GUTS_H__
14391
14392 -#include "devextras.h"
14393 #include "yportenv.h"
14394 +#include "devextras.h"
14395 +#include "yaffs_list.h"
14396
14397 #define YAFFS_OK 1
14398 #define YAFFS_FAIL 0
14399 @@ -52,7 +53,6 @@
14400
14401 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
14402
14403 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
14404
14405 #define YAFFS_ALLOCATION_NOBJECTS 100
14406 #define YAFFS_ALLOCATION_NTNODES 100
14407 @@ -62,8 +62,9 @@
14408
14409
14410 #define YAFFS_OBJECT_SPACE 0x40000
14411 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
14412
14413 -#define YAFFS_CHECKPOINT_VERSION 3
14414 +#define YAFFS_CHECKPOINT_VERSION 4
14415
14416 #ifdef CONFIG_YAFFS_UNICODE
14417 #define YAFFS_MAX_NAME_LENGTH 127
14418 @@ -81,12 +82,11 @@
14419 #define YAFFS_OBJECTID_UNLINKED 3
14420 #define YAFFS_OBJECTID_DELETED 4
14421
14422 -/* Sseudo object ids for checkpointing */
14423 +/* Pseudo object ids for checkpointing */
14424 #define YAFFS_OBJECTID_SB_HEADER 0x10
14425 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
14426 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
14427
14428 -/* */
14429
14430 #define YAFFS_MAX_SHORT_OP_CACHES 20
14431
14432 @@ -119,11 +119,7 @@ typedef struct {
14433 int dirty;
14434 int nBytes; /* Only valid if the cache is dirty */
14435 int locked; /* Can't push out or flush while locked. */
14436 -#ifdef CONFIG_YAFFS_YAFFS2
14437 __u8 *data;
14438 -#else
14439 - __u8 data[YAFFS_BYTES_PER_CHUNK];
14440 -#endif
14441 } yaffs_ChunkCache;
14442
14443
14444 @@ -234,6 +230,8 @@ typedef enum {
14445 YAFFS_BLOCK_STATE_UNKNOWN = 0,
14446
14447 YAFFS_BLOCK_STATE_SCANNING,
14448 + /* Being scanned */
14449 +
14450 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
14451 /* The block might have something on it (ie it is allocating or full, perhaps empty)
14452 * but it needs to be scanned to determine its true state.
14453 @@ -249,21 +247,23 @@ typedef enum {
14454 /* This block is partially allocated.
14455 * At least one page holds valid data.
14456 * This is the one currently being used for page
14457 - * allocation. Should never be more than one of these
14458 + * allocation. Should never be more than one of these.
14459 + * If a block is only partially allocated at mount it is treated as full.
14460 */
14461
14462 YAFFS_BLOCK_STATE_FULL,
14463 /* All the pages in this block have been allocated.
14464 + * If a block was only partially allocated when mounted we treat
14465 + * it as fully allocated.
14466 */
14467
14468 YAFFS_BLOCK_STATE_DIRTY,
14469 - /* All pages have been allocated and deleted.
14470 + /* The block was full and now all chunks have been deleted.
14471 * Erase me, reuse me.
14472 */
14473
14474 YAFFS_BLOCK_STATE_CHECKPOINT,
14475 - /* This block is assigned to holding checkpoint data.
14476 - */
14477 + /* This block is assigned to holding checkpoint data. */
14478
14479 YAFFS_BLOCK_STATE_COLLECTING,
14480 /* This block is being garbage collected */
14481 @@ -351,23 +351,12 @@ typedef struct {
14482 /*--------------------------- Tnode -------------------------- */
14483
14484 union yaffs_Tnode_union {
14485 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
14486 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
14487 -#else
14488 union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
14489 -#endif
14490 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
14491
14492 };
14493
14494 typedef union yaffs_Tnode_union yaffs_Tnode;
14495
14496 -struct yaffs_TnodeList_struct {
14497 - struct yaffs_TnodeList_struct *next;
14498 - yaffs_Tnode *tnodes;
14499 -};
14500 -
14501 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
14502
14503 /*------------------------ Object -----------------------------*/
14504 /* An object can be one of:
14505 @@ -387,6 +376,7 @@ typedef struct {
14506
14507 typedef struct {
14508 struct ylist_head children; /* list of child links */
14509 + struct ylist_head dirty; /* Entry for list of dirty directories */
14510 } yaffs_DirectoryStructure;
14511
14512 typedef struct {
14513 @@ -405,6 +395,8 @@ typedef union {
14514 yaffs_HardLinkStructure hardLinkVariant;
14515 } yaffs_ObjectVariant;
14516
14517 +
14518 +
14519 struct yaffs_ObjectStruct {
14520 __u8 deleted:1; /* This should only apply to unlinked files. */
14521 __u8 softDeleted:1; /* it has also been soft deleted */
14522 @@ -424,6 +416,10 @@ struct yaffs_ObjectStruct {
14523 * until the inode is released.
14524 */
14525 __u8 beingCreated:1; /* This object is still being created so skip some checks. */
14526 + __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */
14527 +
14528 + __u8 xattrKnown:1; /* We know if this has object has xattribs or not. */
14529 + __u8 hasXattr:1; /* This object has xattribs. Valid if xattrKnown. */
14530
14531 __u8 serial; /* serial number of chunk in NAND. Cached here */
14532 __u16 sum; /* sum of the name to speed searching */
14533 @@ -452,10 +448,6 @@ struct yaffs_ObjectStruct {
14534 YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
14535 #endif
14536
14537 -#ifndef __KERNEL__
14538 - __u32 inUse;
14539 -#endif
14540 -
14541 #ifdef CONFIG_YAFFS_WINCE
14542 __u32 win_ctime[2];
14543 __u32 win_mtime[2];
14544 @@ -470,10 +462,7 @@ struct yaffs_ObjectStruct {
14545
14546 __u32 yst_rdev;
14547
14548 -#ifdef __KERNEL__
14549 - struct inode *myInode;
14550 -
14551 -#endif
14552 + void *myInode;
14553
14554 yaffs_ObjectType variantType;
14555
14556 @@ -483,13 +472,6 @@ struct yaffs_ObjectStruct {
14557
14558 typedef struct yaffs_ObjectStruct yaffs_Object;
14559
14560 -struct yaffs_ObjectList_struct {
14561 - yaffs_Object *objects;
14562 - struct yaffs_ObjectList_struct *next;
14563 -};
14564 -
14565 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
14566 -
14567 typedef struct {
14568 struct ylist_head list;
14569 int count;
14570 @@ -531,12 +513,18 @@ typedef struct {
14571
14572 /*----------------- Device ---------------------------------*/
14573
14574 -struct yaffs_DeviceStruct {
14575 - struct ylist_head devList;
14576 - const char *name;
14577
14578 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
14579 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
14580 +struct yaffs_DeviceParamStruct {
14581 + const YCHAR *name;
14582 +
14583 + /*
14584 + * Entry parameters set up way early. Yaffs sets up the rest.
14585 + * The structure should be zeroed out before use so that unused
14586 + * and defualt values are zero.
14587 + */
14588 +
14589 + int inbandTags; /* Use unband tags */
14590 + __u32 totalBytesPerChunk; /* Should be >= 512, does not need to be a power of 2 */
14591 int nChunksPerBlock; /* does not need to be a power of 2 */
14592 int spareBytesPerChunk; /* spare area size */
14593 int startBlock; /* Start block we're allowed to use */
14594 @@ -545,24 +533,24 @@ struct yaffs_DeviceStruct {
14595 /* reserved blocks on NOR and RAM. */
14596
14597
14598 - /* Stuff used by the shared space checkpointing mechanism */
14599 - /* If this value is zero, then this mechanism is disabled */
14600 -
14601 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
14602 -
14603 -
14604 int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
14605 - * the number of short op caches (don't use too many)
14606 + * the number of short op caches (don't use too many).
14607 + * 10 to 20 is a good bet.
14608 */
14609 + int useNANDECC; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
14610 + int noTagsECC; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
14611
14612 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14613 + int isYaffs2; /* Use yaffs2 mode on this device */
14614
14615 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
14616 + int emptyLostAndFound; /* Auto-empty lost+found directory on mount */
14617
14618 - void *genericDevice; /* Pointer to device context
14619 - * On an mtd this holds the mtd pointer.
14620 - */
14621 - void *superBlock;
14622 + int refreshPeriod; /* How often we should check to do a block refresh */
14623 +
14624 + /* Checkpoint control. Can be set before or after initialisation */
14625 + __u8 skipCheckpointRead;
14626 + __u8 skipCheckpointWrite;
14627 +
14628 + int enableXattr; /* Enable xattribs */
14629
14630 /* NAND access functions (Must be set before calling YAFFS)*/
14631
14632 @@ -589,58 +577,68 @@ struct yaffs_DeviceStruct {
14633 yaffs_BlockState *state, __u32 *sequenceNumber);
14634 #endif
14635
14636 - int isYaffs2;
14637 -
14638 /* The removeObjectCallback function must be supplied by OS flavours that
14639 - * need it. The Linux kernel does not use this, but yaffs direct does use
14640 - * it to implement the faster readdir
14641 + * need it.
14642 + * yaffs direct uses it to implement the faster readdir.
14643 + * Linux uses it to protect the directory during unlocking.
14644 */
14645 void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
14646
14647 - /* Callback to mark the superblock dirsty */
14648 - void (*markSuperBlockDirty)(void *superblock);
14649 + /* Callback to mark the superblock dirty */
14650 + void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev);
14651 +
14652 + /* Callback to control garbage collection. */
14653 + unsigned (*gcControl)(struct yaffs_DeviceStruct *dev);
14654
14655 + /* Debug control flags. Don't use unless you know what you're doing */
14656 + int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14657 + int disableLazyLoad; /* Disable lazy loading on this device */
14658 int wideTnodesDisabled; /* Set to disable wide tnodes */
14659 + int disableSoftDelete; /* yaffs 1 only: Set to disable the use of softdeletion. */
14660 +
14661 + int deferDirectoryUpdate; /* Set to defer directory updates */
14662 +
14663 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14664 + int autoUnicode;
14665 +#endif
14666 + int alwaysCheckErased; /* Force chunk erased check always on */
14667 +};
14668
14669 - YCHAR *pathDividers; /* String of legal path dividers */
14670 +typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam;
14671
14672 +struct yaffs_DeviceStruct {
14673 + struct yaffs_DeviceParamStruct param;
14674
14675 - /* End of stuff that must be set before initialisation. */
14676 + /* Context storage. Holds extra OS specific data for this device */
14677
14678 - /* Checkpoint control. Can be set before or after initialisation */
14679 - __u8 skipCheckpointRead;
14680 - __u8 skipCheckpointWrite;
14681 + void *osContext;
14682 + void *driverContext;
14683 +
14684 + struct ylist_head devList;
14685
14686 /* Runtime parameters. Set up by YAFFS. */
14687 + int nDataBytesPerChunk;
14688
14689 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
14690 + /* Non-wide tnode stuff */
14691 + __u16 chunkGroupBits; /* Number of bits that need to be resolved if
14692 + * the tnodes are not wide enough.
14693 + */
14694 __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
14695
14696 /* Stuff to support wide tnodes */
14697 __u32 tnodeWidth;
14698 __u32 tnodeMask;
14699 + __u32 tnodeSize;
14700
14701 /* Stuff for figuring out file offset to chunk conversions */
14702 __u32 chunkShift; /* Shift value */
14703 __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
14704 __u32 chunkMask; /* Mask to use for power-of-2 case */
14705
14706 - /* Stuff to handle inband tags */
14707 - int inbandTags;
14708 - __u32 totalBytesPerChunk;
14709 -
14710 -#ifdef __KERNEL__
14711 -
14712 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
14713 - struct semaphore grossLock; /* Gross locking semaphore */
14714 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
14715 - * at compile time so we have to allocate it.
14716 - */
14717 - void (*putSuperFunc) (struct super_block *sb);
14718 -#endif
14719
14720 - int isMounted;
14721
14722 + int isMounted;
14723 + int readOnly;
14724 int isCheckpointed;
14725
14726
14727 @@ -682,51 +680,31 @@ struct yaffs_DeviceStruct {
14728 __u32 allocationPage;
14729 int allocationBlockFinder; /* Used to search for next allocation block */
14730
14731 - /* Runtime state */
14732 - int nTnodesCreated;
14733 - yaffs_Tnode *freeTnodes;
14734 - int nFreeTnodes;
14735 - yaffs_TnodeList *allocatedTnodeList;
14736 -
14737 - int isDoingGC;
14738 - int gcBlock;
14739 - int gcChunk;
14740 -
14741 - int nObjectsCreated;
14742 - yaffs_Object *freeObjects;
14743 - int nFreeObjects;
14744 + /* Object and Tnode memory management */
14745 + void *allocator;
14746 + int nObjects;
14747 + int nTnodes;
14748
14749 int nHardLinks;
14750
14751 - yaffs_ObjectList *allocatedObjectList;
14752 -
14753 yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
14754 + __u32 bucketFinder;
14755
14756 int nFreeChunks;
14757
14758 - int currentDirtyChecker; /* Used to find current dirtiest block */
14759 -
14760 + /* Garbage collection control */
14761 __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
14762 - int nonAggressiveSkip; /* GC state/mode */
14763 + __u32 nCleanups;
14764
14765 - /* Statistcs */
14766 - int nPageWrites;
14767 - int nPageReads;
14768 - int nBlockErasures;
14769 - int nErasureFailures;
14770 - int nGCCopies;
14771 - int garbageCollections;
14772 - int passiveGarbageCollections;
14773 - int nRetriedWrites;
14774 - int nRetiredBlocks;
14775 - int eccFixed;
14776 - int eccUnfixed;
14777 - int tagsEccFixed;
14778 - int tagsEccUnfixed;
14779 - int nDeletions;
14780 - int nUnmarkedDeletions;
14781 -
14782 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14783 + unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14784 + unsigned gcDisable;
14785 + unsigned gcBlockFinder;
14786 + unsigned gcDirtiest;
14787 + unsigned gcPagesInUse;
14788 + unsigned gcNotDone;
14789 + unsigned gcBlock;
14790 + unsigned gcChunk;
14791 + unsigned gcSkip;
14792
14793 /* Special directories */
14794 yaffs_Object *rootDir;
14795 @@ -743,8 +721,6 @@ struct yaffs_DeviceStruct {
14796 yaffs_ChunkCache *srCache;
14797 int srLastUse;
14798
14799 - int cacheHits;
14800 -
14801 /* Stuff for background deletion and unlinked files.*/
14802 yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
14803 yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
14804 @@ -753,7 +729,6 @@ struct yaffs_DeviceStruct {
14805 int nUnlinkedFiles; /* Count of unlinked files. */
14806 int nBackgroundDeletions; /* Count of background deletions. */
14807
14808 -
14809 /* Temporary buffer management */
14810 yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
14811 int maxTemp;
14812 @@ -764,6 +739,36 @@ struct yaffs_DeviceStruct {
14813 /* yaffs2 runtime stuff */
14814 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14815 unsigned oldestDirtySequence;
14816 + unsigned oldestDirtyBlock;
14817 +
14818 + /* Block refreshing */
14819 + int refreshSkip; /* A skip down counter. Refresh happens when this gets to zero. */
14820 +
14821 + /* Dirty directory handling */
14822 + struct ylist_head dirtyDirectories; /* List of dirty directories */
14823 +
14824 +
14825 + /* Statistcs */
14826 + __u32 nPageWrites;
14827 + __u32 nPageReads;
14828 + __u32 nBlockErasures;
14829 + __u32 nErasureFailures;
14830 + __u32 nGCCopies;
14831 + __u32 allGCs;
14832 + __u32 passiveGCs;
14833 + __u32 oldestDirtyGCs;
14834 + __u32 nGCBlocks;
14835 + __u32 backgroundGCs;
14836 + __u32 nRetriedWrites;
14837 + __u32 nRetiredBlocks;
14838 + __u32 eccFixed;
14839 + __u32 eccUnfixed;
14840 + __u32 tagsEccFixed;
14841 + __u32 tagsEccUnfixed;
14842 + __u32 nDeletions;
14843 + __u32 nUnmarkedDeletions;
14844 + __u32 refreshCount;
14845 + __u32 cacheHits;
14846
14847 };
14848
14849 @@ -796,7 +801,6 @@ typedef struct {
14850
14851 /* yaffs2 runtime stuff */
14852 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14853 - unsigned oldestDirtySequence;
14854
14855 } yaffs_CheckpointDevice;
14856
14857 @@ -809,6 +813,23 @@ typedef struct {
14858 } yaffs_CheckpointValidity;
14859
14860
14861 +struct yaffs_ShadowFixerStruct {
14862 + int objectId;
14863 + int shadowedId;
14864 + struct yaffs_ShadowFixerStruct *next;
14865 +};
14866 +
14867 +/* Structure for doing xattr modifications */
14868 +typedef struct {
14869 + int set; /* If 0 then this is a deletion */
14870 + const YCHAR *name;
14871 + const void *data;
14872 + int size;
14873 + int flags;
14874 + int result;
14875 +}yaffs_XAttrMod;
14876 +
14877 +
14878 /*----------------------- YAFFS Functions -----------------------*/
14879
14880 int yaffs_GutsInitialise(yaffs_Device *dev);
14881 @@ -840,7 +861,8 @@ int yaffs_ResizeFile(yaffs_Object *obj,
14882
14883 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
14884 __u32 mode, __u32 uid, __u32 gid);
14885 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
14886 +
14887 +int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync);
14888
14889 /* Flushing and checkpointing */
14890 void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
14891 @@ -873,6 +895,12 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Objec
14892 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
14893 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
14894
14895 +
14896 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags);
14897 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size);
14898 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size);
14899 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name);
14900 +
14901 /* Special directories */
14902 yaffs_Object *yaffs_Root(yaffs_Device *dev);
14903 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
14904 @@ -882,18 +910,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Dev
14905 void yfsd_WinFileTimeNow(__u32 target[2]);
14906 #endif
14907
14908 -#ifdef __KERNEL__
14909 -
14910 void yaffs_HandleDeferedFree(yaffs_Object *obj);
14911 -#endif
14912 +
14913 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev);
14914 +
14915 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency);
14916
14917 /* Debug dump */
14918 int yaffs_DumpObject(yaffs_Object *obj);
14919
14920 void yaffs_GutsTest(yaffs_Device *dev);
14921
14922 -/* A few useful functions */
14923 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
14924 +/* A few useful functions to be used within the core files*/
14925 void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
14926 int yaffs_CheckFF(__u8 *buffer, int nBytes);
14927 void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
14928 @@ -901,4 +929,41 @@ void yaffs_HandleChunkError(yaffs_Device
14929 __u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
14930 void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
14931
14932 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
14933 + int number,
14934 + yaffs_ObjectType type);
14935 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
14936 + int chunkInNAND, int inScan);
14937 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name);
14938 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh);
14939 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14940 + yaffs_Object *obj);
14941 +YCHAR *yaffs_CloneString(const YCHAR *str);
14942 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
14943 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo);
14944 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
14945 + int force, int isShrink, int shadows,
14946 + yaffs_XAttrMod *xop);
14947 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
14948 + int backwardScanning);
14949 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks);
14950 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev);
14951 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
14952 + yaffs_FileStructure *fStruct,
14953 + __u32 chunkId,
14954 + yaffs_Tnode *passedTn);
14955 +
14956 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
14957 + int nBytes, int writeThrough);
14958 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize);
14959 +void yaffs_SkipRestOfBlock(yaffs_Device *dev);
14960 +
14961 +int yaffs_CountFreeChunks(yaffs_Device *dev);
14962 +
14963 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
14964 + yaffs_FileStructure *fStruct,
14965 + __u32 chunkId);
14966 +
14967 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
14968 +
14969 #endif
14970 --- a/fs/yaffs2/yaffsinterface.h
14971 +++ b/fs/yaffs2/yaffsinterface.h
14972 @@ -1,7 +1,7 @@
14973 /*
14974 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14975 *
14976 - * Copyright (C) 2002-2007 Aleph One Ltd.
14977 + * Copyright (C) 2002-2010 Aleph One Ltd.
14978 * for Toby Churchill Ltd and Brightstar Engineering
14979 *
14980 * Created by Charles Manning <charles@aleph1.co.uk>
14981 --- /dev/null
14982 +++ b/fs/yaffs2/yaffs_linux_allocator.c
14983 @@ -0,0 +1,200 @@
14984 +/*
14985 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14986 + *
14987 + * Copyright (C) 2002-2010 Aleph One Ltd.
14988 + * for Toby Churchill Ltd and Brightstar Engineering
14989 + *
14990 + * Created by Charles Manning <charles@aleph1.co.uk>
14991 + *
14992 + * This program is free software; you can redistribute it and/or modify
14993 + * it under the terms of the GNU Lesser General Public License version 2.1 as
14994 + * published by the Free Software Foundation.
14995 + *
14996 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14997 + *
14998 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
14999 + */
15000 +
15001 +
15002 +#include "yaffs_allocator.h"
15003 +#include "yaffs_guts.h"
15004 +#include "yaffs_trace.h"
15005 +#include "yportenv.h"
15006 +#include "yaffs_linux.h"
15007 +/*
15008 + * Start out with the same allocator as yaffs direct.
15009 + * Todo: Change to Linux slab allocator.
15010 + */
15011 +
15012 +
15013 +
15014 +#define NAMELEN 20
15015 +struct yaffs_AllocatorStruct {
15016 + char tnode_name[NAMELEN+1];
15017 + char object_name[NAMELEN+1];
15018 + struct kmem_cache *tnode_cache;
15019 + struct kmem_cache *object_cache;
15020 +};
15021 +
15022 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
15023 +
15024 +int mount_id;
15025 +
15026 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
15027 +{
15028 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
15029 +
15030 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
15031 +
15032 + if(allocator){
15033 + if(allocator->tnode_cache){
15034 + kmem_cache_destroy(allocator->tnode_cache);
15035 + allocator->tnode_cache = NULL;
15036 + } else {
15037 + T(YAFFS_TRACE_ALWAYS,
15038 + (TSTR("NULL tnode cache\n")));
15039 + YBUG();
15040 + }
15041 +
15042 + if(allocator->object_cache){
15043 + kmem_cache_destroy(allocator->object_cache);
15044 + allocator->object_cache = NULL;
15045 + } else {
15046 + T(YAFFS_TRACE_ALWAYS,
15047 + (TSTR("NULL object cache\n")));
15048 + YBUG();
15049 + }
15050 +
15051 + YFREE(allocator);
15052 +
15053 + } else {
15054 + T(YAFFS_TRACE_ALWAYS,
15055 + (TSTR("Deinitialising NULL allocator\n")));
15056 + YBUG();
15057 + }
15058 + dev->allocator = NULL;
15059 +}
15060 +
15061 +
15062 +static void fake_ctor0(void *data){data = data;}
15063 +static void fake_ctor1(void *data){data = data;}
15064 +static void fake_ctor2(void *data){data = data;}
15065 +static void fake_ctor3(void *data){data = data;}
15066 +static void fake_ctor4(void *data){data = data;}
15067 +static void fake_ctor5(void *data){data = data;}
15068 +static void fake_ctor6(void *data){data = data;}
15069 +static void fake_ctor7(void *data){data = data;}
15070 +static void fake_ctor8(void *data){data = data;}
15071 +static void fake_ctor9(void *data){data = data;}
15072 +
15073 +static void (*fake_ctor_list[10]) (void *) = {
15074 + fake_ctor0,
15075 + fake_ctor1,
15076 + fake_ctor2,
15077 + fake_ctor3,
15078 + fake_ctor4,
15079 + fake_ctor5,
15080 + fake_ctor6,
15081 + fake_ctor7,
15082 + fake_ctor8,
15083 + fake_ctor9,
15084 +};
15085 +
15086 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
15087 +{
15088 + yaffs_Allocator *allocator;
15089 + unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id;
15090 +
15091 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
15092 +
15093 + if(dev->allocator)
15094 + YBUG();
15095 + else if(mount_id >= 10){
15096 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
15097 + } else {
15098 + allocator = YMALLOC(sizeof(yaffs_Allocator));
15099 + memset(allocator,0,sizeof(yaffs_Allocator));
15100 + dev->allocator = allocator;
15101 +
15102 + if(!dev->allocator){
15103 + T(YAFFS_TRACE_ALWAYS,
15104 + (TSTR("yaffs allocator creation failed\n")));
15105 + YBUG();
15106 + return;
15107 +
15108 + }
15109 +
15110 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
15111 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
15112 +
15113 + allocator->tnode_cache =
15114 + kmem_cache_create(allocator->tnode_name,
15115 + dev->tnodeSize,
15116 + 0, 0,
15117 + fake_ctor_list[mount_id]);
15118 + if(allocator->tnode_cache)
15119 + T(YAFFS_TRACE_ALLOCATE,
15120 + (TSTR("tnode cache \"%s\" %p\n"),
15121 + allocator->tnode_name,allocator->tnode_cache));
15122 + else {
15123 + T(YAFFS_TRACE_ALWAYS,
15124 + (TSTR("yaffs cache creation failed\n")));
15125 + YBUG();
15126 + }
15127 +
15128 +
15129 + allocator->object_cache =
15130 + kmem_cache_create(allocator->object_name,
15131 + sizeof(yaffs_Object),
15132 + 0, 0,
15133 + fake_ctor_list[mount_id]);
15134 +
15135 + if(allocator->object_cache)
15136 + T(YAFFS_TRACE_ALLOCATE,
15137 + (TSTR("object cache \"%s\" %p\n"),
15138 + allocator->object_name,allocator->object_cache));
15139 +
15140 + else {
15141 + T(YAFFS_TRACE_ALWAYS,
15142 + (TSTR("yaffs cache creation failed\n")));
15143 + YBUG();
15144 + }
15145 + }
15146 +}
15147 +
15148 +
15149 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
15150 +{
15151 + yaffs_Allocator *allocator = dev->allocator;
15152 + if(!allocator || !allocator->tnode_cache){
15153 + YBUG();
15154 + return NULL;
15155 + }
15156 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
15157 +}
15158 +
15159 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
15160 +{
15161 + yaffs_Allocator *allocator = dev->allocator;
15162 + kmem_cache_free(allocator->tnode_cache,tn);
15163 +}
15164 +
15165 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
15166 +{
15167 + yaffs_Allocator *allocator = dev->allocator;
15168 + if(!allocator){
15169 + YBUG();
15170 + return NULL;
15171 + }
15172 + if(!allocator->object_cache){
15173 + YBUG();
15174 + return NULL;
15175 + }
15176 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
15177 +}
15178 +
15179 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
15180 +{
15181 + yaffs_Allocator *allocator = dev->allocator;
15182 + kmem_cache_free(allocator->object_cache,obj);
15183 +}
15184 --- /dev/null
15185 +++ b/fs/yaffs2/yaffs_linux.h
15186 @@ -0,0 +1,43 @@
15187 +/*
15188 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15189 + *
15190 + * Copyright (C) 2002-2010 Aleph One Ltd.
15191 + * for Toby Churchill Ltd and Brightstar Engineering
15192 + *
15193 + * Created by Charles Manning <charles@aleph1.co.uk>
15194 + *
15195 + * This program is free software; you can redistribute it and/or modify
15196 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15197 + * published by the Free Software Foundation.
15198 + *
15199 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15200 + */
15201 +
15202 +#ifndef __YAFFS_LINUX_H__
15203 +#define __YAFFS_LINUX_H__
15204 +
15205 +#include "devextras.h"
15206 +#include "yportenv.h"
15207 +
15208 +struct yaffs_LinuxContext {
15209 + struct ylist_head contextList; /* List of these we have mounted */
15210 + struct yaffs_DeviceStruct *dev;
15211 + struct super_block * superBlock;
15212 + struct task_struct *bgThread; /* Background thread for this device */
15213 + int bgRunning;
15214 + struct semaphore grossLock; /* Gross locking semaphore */
15215 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
15216 + * at compile time so we have to allocate it.
15217 + */
15218 + struct ylist_head searchContexts;
15219 + void (*putSuperFunc)(struct super_block *sb);
15220 +
15221 + struct task_struct *readdirProcess;
15222 + unsigned mount_id;
15223 +};
15224 +
15225 +#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext))
15226 +#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext))
15227 +
15228 +#endif
15229 +
15230 --- /dev/null
15231 +++ b/fs/yaffs2/yaffs_list.h
15232 @@ -0,0 +1,127 @@
15233 +/*
15234 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15235 + *
15236 + * Copyright (C) 2002-2010 Aleph One Ltd.
15237 + * for Toby Churchill Ltd and Brightstar Engineering
15238 + *
15239 + * Created by Charles Manning <charles@aleph1.co.uk>
15240 + *
15241 + * This program is free software; you can redistribute it and/or modify
15242 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15243 + * published by the Free Software Foundation.
15244 + *
15245 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15246 + */
15247 +
15248 +/*
15249 + * This file is just holds extra declarations of macros that would normally
15250 + * be providesd in the Linux kernel. These macros have been written from
15251 + * scratch but are functionally equivalent to the Linux ones.
15252 + *
15253 + */
15254 +
15255 +#ifndef __YAFFS_LIST_H__
15256 +#define __YAFFS_LIST_H__
15257 +
15258 +
15259 +#include "yportenv.h"
15260 +
15261 +/*
15262 + * This is a simple doubly linked list implementation that matches the
15263 + * way the Linux kernel doubly linked list implementation works.
15264 + */
15265 +
15266 +struct ylist_head {
15267 + struct ylist_head *next; /* next in chain */
15268 + struct ylist_head *prev; /* previous in chain */
15269 +};
15270 +
15271 +
15272 +/* Initialise a static list */
15273 +#define YLIST_HEAD(name) \
15274 +struct ylist_head name = { &(name), &(name)}
15275 +
15276 +
15277 +
15278 +/* Initialise a list head to an empty list */
15279 +#define YINIT_LIST_HEAD(p) \
15280 +do { \
15281 + (p)->next = (p);\
15282 + (p)->prev = (p); \
15283 +} while (0)
15284 +
15285 +
15286 +/* Add an element to a list */
15287 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
15288 + struct ylist_head *list)
15289 +{
15290 + struct ylist_head *listNext = list->next;
15291 +
15292 + list->next = newEntry;
15293 + newEntry->prev = list;
15294 + newEntry->next = listNext;
15295 + listNext->prev = newEntry;
15296 +
15297 +}
15298 +
15299 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
15300 + struct ylist_head *list)
15301 +{
15302 + struct ylist_head *listPrev = list->prev;
15303 +
15304 + list->prev = newEntry;
15305 + newEntry->next = list;
15306 + newEntry->prev = listPrev;
15307 + listPrev->next = newEntry;
15308 +
15309 +}
15310 +
15311 +
15312 +/* Take an element out of its current list, with or without
15313 + * reinitialising the links.of the entry*/
15314 +static Y_INLINE void ylist_del(struct ylist_head *entry)
15315 +{
15316 + struct ylist_head *listNext = entry->next;
15317 + struct ylist_head *listPrev = entry->prev;
15318 +
15319 + listNext->prev = listPrev;
15320 + listPrev->next = listNext;
15321 +
15322 +}
15323 +
15324 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
15325 +{
15326 + ylist_del(entry);
15327 + entry->next = entry->prev = entry;
15328 +}
15329 +
15330 +
15331 +/* Test if the list is empty */
15332 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
15333 +{
15334 + return (entry->next == entry);
15335 +}
15336 +
15337 +
15338 +/* ylist_entry takes a pointer to a list entry and offsets it to that
15339 + * we can find a pointer to the object it is embedded in.
15340 + */
15341 +
15342 +
15343 +#define ylist_entry(entry, type, member) \
15344 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
15345 +
15346 +
15347 +/* ylist_for_each and list_for_each_safe iterate over lists.
15348 + * ylist_for_each_safe uses temporary storage to make the list delete safe
15349 + */
15350 +
15351 +#define ylist_for_each(itervar, list) \
15352 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
15353 +
15354 +#define ylist_for_each_safe(itervar, saveVar, list) \
15355 + for (itervar = (list)->next, saveVar = (list)->next->next; \
15356 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
15357 +
15358 +
15359 +#endif
15360 --- a/fs/yaffs2/yaffs_mtdif1.c
15361 +++ b/fs/yaffs2/yaffs_mtdif1.c
15362 @@ -2,7 +2,7 @@
15363 * YAFFS: Yet another FFS. A NAND-flash specific file system.
15364 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15365 *
15366 - * Copyright (C) 2002 Aleph One Ltd.
15367 + * Copyright (C) 2002-2010 Aleph One Ltd.
15368 * for Toby Churchill Ltd and Brightstar Engineering
15369 *
15370 * This program is free software; you can redistribute it and/or modify
15371 @@ -24,9 +24,11 @@
15372 */
15373
15374 #include "yportenv.h"
15375 +#include "yaffs_trace.h"
15376 #include "yaffs_guts.h"
15377 #include "yaffs_packedtags1.h"
15378 #include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
15379 +#include "yaffs_linux.h"
15380
15381 #include "linux/kernel.h"
15382 #include "linux/version.h"
15383 @@ -36,8 +38,6 @@
15384 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15385 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
15386
15387 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
15388 -
15389 #ifndef CONFIG_YAFFS_9BYTE_TAGS
15390 # define YTAG1_SIZE 8
15391 #else
15392 @@ -91,7 +91,7 @@ static struct nand_ecclayout nand_oob_16
15393 int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15394 int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
15395 {
15396 - struct mtd_info *mtd = dev->genericDevice;
15397 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15398 int chunkBytes = dev->nDataBytesPerChunk;
15399 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15400 struct mtd_oob_ops ops;
15401 @@ -102,8 +102,6 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15402 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15403 compile_time_assertion(sizeof(yaffs_Tags) == 8);
15404
15405 - dev->nPageWrites++;
15406 -
15407 yaffs_PackTags1(&pt1, etags);
15408 yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15409
15410 @@ -137,9 +135,9 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15411
15412 retval = mtd->write_oob(mtd, addr, &ops);
15413 if (retval) {
15414 - yaffs_trace(YAFFS_TRACE_MTD,
15415 - "write_oob failed, chunk %d, mtd error %d\n",
15416 - chunkInNAND, retval);
15417 + T(YAFFS_TRACE_MTD,
15418 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
15419 + chunkInNAND, retval));
15420 }
15421 return retval ? YAFFS_FAIL : YAFFS_OK;
15422 }
15423 @@ -171,7 +169,7 @@ static int rettags(yaffs_ExtendedTags *e
15424 int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15425 int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
15426 {
15427 - struct mtd_info *mtd = dev->genericDevice;
15428 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15429 int chunkBytes = dev->nDataBytesPerChunk;
15430 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15431 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15432 @@ -180,8 +178,6 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15433 int retval;
15434 int deleted;
15435
15436 - dev->nPageReads++;
15437 -
15438 memset(&ops, 0, sizeof(ops));
15439 ops.mode = MTD_OOB_AUTO;
15440 ops.len = (data) ? chunkBytes : 0;
15441 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15442 */
15443 retval = mtd->read_oob(mtd, addr, &ops);
15444 if (retval) {
15445 - yaffs_trace(YAFFS_TRACE_MTD,
15446 - "read_oob failed, chunk %d, mtd error %d\n",
15447 - chunkInNAND, retval);
15448 + T(YAFFS_TRACE_MTD,
15449 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
15450 + chunkInNAND, retval));
15451 }
15452
15453 switch (retval) {
15454 @@ -284,11 +280,11 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15455 */
15456 int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15457 {
15458 - struct mtd_info *mtd = dev->genericDevice;
15459 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15460 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15461 + int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk;
15462 int retval;
15463
15464 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
15465 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), blockNo));
15466
15467 retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15468 return (retval) ? YAFFS_FAIL : YAFFS_OK;
15469 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
15470 int oobavail = mtd->ecclayout->oobavail;
15471
15472 if (oobavail < YTAG1_SIZE) {
15473 - yaffs_trace(YAFFS_TRACE_ERROR,
15474 - "mtd device has only %d bytes for tags, need %d\n",
15475 - oobavail, YTAG1_SIZE);
15476 + T(YAFFS_TRACE_ERROR,
15477 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
15478 + oobavail, YTAG1_SIZE));
15479 return YAFFS_FAIL;
15480 }
15481 return YAFFS_OK;
15482 @@ -325,8 +321,8 @@ static int nandmtd1_TestPrerequists(stru
15483 int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15484 yaffs_BlockState *pState, __u32 *pSequenceNumber)
15485 {
15486 - struct mtd_info *mtd = dev->genericDevice;
15487 - int chunkNo = blockNo * dev->nChunksPerBlock;
15488 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15489 + int chunkNo = blockNo * dev->param.nChunksPerBlock;
15490 loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
15491 yaffs_ExtendedTags etags;
15492 int state = YAFFS_BLOCK_STATE_DEAD;
15493 @@ -342,8 +338,8 @@ int nandmtd1_QueryNANDBlock(struct yaffs
15494 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15495 etags.blockBad = (mtd->block_isbad)(mtd, addr);
15496 if (etags.blockBad) {
15497 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15498 - "block %d is marked bad\n", blockNo);
15499 + T(YAFFS_TRACE_BAD_BLOCKS,
15500 + (TSTR("block %d is marked bad"TENDSTR), blockNo));
15501 state = YAFFS_BLOCK_STATE_DEAD;
15502 } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
15503 /* bad tags, need to look more closely */
15504 --- a/fs/yaffs2/yaffs_mtdif1-compat.c
15505 +++ /dev/null
15506 @@ -1,434 +0,0 @@
15507 -From ian@brightstareng.com Fri May 18 15:06:49 2007
15508 -From ian@brightstareng.com Fri May 18 15:08:21 2007
15509 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
15510 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
15511 - (envelope-from <ian@brightstareng.com>)
15512 - id 1Hp380-00011e-T6
15513 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
15514 -Received: from localhost (localhost.localdomain [127.0.0.1])
15515 - by zebra.brightstareng.com (Postfix) with ESMTP
15516 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
15517 -Received: from zebra.brightstareng.com ([127.0.0.1])
15518 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
15519 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
15520 -Received: from pippin (unknown [192.168.1.25])
15521 - by zebra.brightstareng.com (Postfix) with ESMTP
15522 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
15523 -From: Ian McDonnell <ian@brightstareng.com>
15524 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
15525 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
15526 -Date: Fri, 18 May 2007 10:06:49 -0400
15527 -User-Agent: KMail/1.9.1
15528 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
15529 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
15530 -Cc: Andrea Conti <alyf@alyf.net>,
15531 - Charles Manning <manningc2@actrix.gen.nz>
15532 -MIME-Version: 1.0
15533 -Content-Type: Multipart/Mixed;
15534 - boundary="Boundary-00=_5LbTGmt62YoutxM"
15535 -Message-Id: <200705181006.49860.ian@brightstareng.com>
15536 -X-Virus-Scanned: by amavisd-new at brightstareng.com
15537 -Status: R
15538 -X-Status: NT
15539 -X-KMail-EncryptionState:
15540 -X-KMail-SignatureState:
15541 -X-KMail-MDN-Sent:
15542 -
15543 ---Boundary-00=_5LbTGmt62YoutxM
15544 -Content-Type: text/plain;
15545 - charset="iso-8859-15"
15546 -Content-Transfer-Encoding: 7bit
15547 -Content-Disposition: inline
15548 -
15549 -David, Andrea,
15550 -
15551 -On Friday 18 May 2007 08:34, you wrote:
15552 -> Yea team. With this fix in place (I put it in the wrong place
15553 -> at first) I can now mount and ls the Yaffs partition without
15554 -> an error messages!
15555 -
15556 -Good news!
15557 -
15558 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
15559 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
15560 -See the LINUX_VERSION_CODE conditional in
15561 -nandmtd1_ReadChunkWithTagsFromNAND.
15562 -
15563 --imcd
15564 -
15565 ---Boundary-00=_5LbTGmt62YoutxM
15566 -Content-Type: text/x-csrc;
15567 - charset="iso-8859-15";
15568 - name="yaffs_mtdif1.c"
15569 -Content-Transfer-Encoding: 7bit
15570 -Content-Disposition: attachment;
15571 - filename="yaffs_mtdif1.c"
15572 -
15573 -/*
15574 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
15575 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15576 - *
15577 - * Copyright (C) 2002 Aleph One Ltd.
15578 - * for Toby Churchill Ltd and Brightstar Engineering
15579 - *
15580 - * This program is free software; you can redistribute it and/or modify
15581 - * it under the terms of the GNU General Public License version 2 as
15582 - * published by the Free Software Foundation.
15583 - */
15584 -
15585 -/*
15586 - * This module provides the interface between yaffs_nand.c and the
15587 - * MTD API. This version is used when the MTD interface supports the
15588 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
15589 - * and we have small-page NAND device.
15590 - *
15591 - * These functions are invoked via function pointers in yaffs_nand.c.
15592 - * This replaces functionality provided by functions in yaffs_mtdif.c
15593 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
15594 - * called in yaffs_mtdif.c when the function pointers are NULL.
15595 - * We assume the MTD layer is performing ECC (useNANDECC is true).
15596 - */
15597 -
15598 -#include "yportenv.h"
15599 -#include "yaffs_guts.h"
15600 -#include "yaffs_packedtags1.h"
15601 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
15602 -
15603 -#include "linux/kernel.h"
15604 -#include "linux/version.h"
15605 -#include "linux/types.h"
15606 -#include "linux/mtd/mtd.h"
15607 -
15608 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15609 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
15610 -
15611 -const char *yaffs_mtdif1_c_version = "$Id$";
15612 -
15613 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15614 -# define YTAG1_SIZE 8
15615 -#else
15616 -# define YTAG1_SIZE 9
15617 -#endif
15618 -
15619 -#if 0
15620 -/* Use the following nand_ecclayout with MTD when using
15621 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
15622 - * If you have existing Yaffs images and the byte order differs from this,
15623 - * adjust 'oobfree' to match your existing Yaffs data.
15624 - *
15625 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
15626 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
15627 - * the 9th byte.
15628 - *
15629 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
15630 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
15631 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
15632 - * byte and B is the small-page bad-block indicator byte.
15633 - */
15634 -static struct nand_ecclayout nand_oob_16 = {
15635 - .eccbytes = 6,
15636 - .eccpos = { 8, 9, 10, 13, 14, 15 },
15637 - .oobavail = 9,
15638 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
15639 -};
15640 -#endif
15641 -
15642 -/* Write a chunk (page) of data to NAND.
15643 - *
15644 - * Caller always provides ExtendedTags data which are converted to a more
15645 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
15646 - * contents of the tags meta-data; used to valid the tags when read.
15647 - *
15648 - * - Pack ExtendedTags to PackedTags1 form
15649 - * - Compute mini-ECC for PackedTags1
15650 - * - Write data and packed tags to NAND.
15651 - *
15652 - * Note: Due to the use of the PackedTags1 meta-data which does not include
15653 - * a full sequence number (as found in the larger PackedTags2 form) it is
15654 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
15655 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
15656 - * to be written just once. When Yaffs performs this operation, this
15657 - * function is called with a NULL data pointer -- calling MTD write_oob
15658 - * without data is valid usage (2.6.17).
15659 - *
15660 - * Any underlying MTD error results in YAFFS_FAIL.
15661 - * Returns YAFFS_OK or YAFFS_FAIL.
15662 - */
15663 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15664 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
15665 -{
15666 - struct mtd_info * mtd = dev->genericDevice;
15667 - int chunkBytes = dev->nDataBytesPerChunk;
15668 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15669 - struct mtd_oob_ops ops;
15670 - yaffs_PackedTags1 pt1;
15671 - int retval;
15672 -
15673 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
15674 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15675 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
15676 -
15677 - yaffs_PackTags1(&pt1, etags);
15678 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15679 -
15680 - /* When deleting a chunk, the upper layer provides only skeletal
15681 - * etags, one with chunkDeleted set. However, we need to update the
15682 - * tags, not erase them completely. So we use the NAND write property
15683 - * that only zeroed-bits stick and set tag bytes to all-ones and
15684 - * zero just the (not) deleted bit.
15685 - */
15686 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15687 - if (etags->chunkDeleted) {
15688 - memset(&pt1, 0xff, 8);
15689 - /* clear delete status bit to indicate deleted */
15690 - pt1.deleted = 0;
15691 - }
15692 -#else
15693 - ((__u8 *)&pt1)[8] = 0xff;
15694 - if (etags->chunkDeleted) {
15695 - memset(&pt1, 0xff, 8);
15696 - /* zero pageStatus byte to indicate deleted */
15697 - ((__u8 *)&pt1)[8] = 0;
15698 - }
15699 -#endif
15700 -
15701 - memset(&ops, 0, sizeof(ops));
15702 - ops.mode = MTD_OOB_AUTO;
15703 - ops.len = (data) ? chunkBytes : 0;
15704 - ops.ooblen = YTAG1_SIZE;
15705 - ops.datbuf = (__u8 *)data;
15706 - ops.oobbuf = (__u8 *)&pt1;
15707 -
15708 - retval = mtd->write_oob(mtd, addr, &ops);
15709 - if (retval) {
15710 - yaffs_trace(YAFFS_TRACE_MTD,
15711 - "write_oob failed, chunk %d, mtd error %d\n",
15712 - chunkInNAND, retval);
15713 - }
15714 - return retval ? YAFFS_FAIL : YAFFS_OK;
15715 -}
15716 -
15717 -/* Return with empty ExtendedTags but add eccResult.
15718 - */
15719 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
15720 -{
15721 - if (etags) {
15722 - memset(etags, 0, sizeof(*etags));
15723 - etags->eccResult = eccResult;
15724 - }
15725 - return retval;
15726 -}
15727 -
15728 -/* Read a chunk (page) from NAND.
15729 - *
15730 - * Caller expects ExtendedTags data to be usable even on error; that is,
15731 - * all members except eccResult and blockBad are zeroed.
15732 - *
15733 - * - Check ECC results for data (if applicable)
15734 - * - Check for blank/erased block (return empty ExtendedTags if blank)
15735 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
15736 - * - Convert PackedTags1 to ExtendedTags
15737 - * - Update eccResult and blockBad members to refect state.
15738 - *
15739 - * Returns YAFFS_OK or YAFFS_FAIL.
15740 - */
15741 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15742 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
15743 -{
15744 - struct mtd_info * mtd = dev->genericDevice;
15745 - int chunkBytes = dev->nDataBytesPerChunk;
15746 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15747 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15748 - struct mtd_oob_ops ops;
15749 - yaffs_PackedTags1 pt1;
15750 - int retval;
15751 - int deleted;
15752 -
15753 - memset(&ops, 0, sizeof(ops));
15754 - ops.mode = MTD_OOB_AUTO;
15755 - ops.len = (data) ? chunkBytes : 0;
15756 - ops.ooblen = YTAG1_SIZE;
15757 - ops.datbuf = data;
15758 - ops.oobbuf = (__u8 *)&pt1;
15759 -
15760 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
15761 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
15762 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
15763 - */
15764 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
15765 -#endif
15766 - /* Read page and oob using MTD.
15767 - * Check status and determine ECC result.
15768 - */
15769 - retval = mtd->read_oob(mtd, addr, &ops);
15770 - if (retval) {
15771 - yaffs_trace(YAFFS_TRACE_MTD,
15772 - "read_oob failed, chunk %d, mtd error %d\n",
15773 - chunkInNAND, retval);
15774 - }
15775 -
15776 - switch (retval) {
15777 - case 0:
15778 - /* no error */
15779 - break;
15780 -
15781 - case -EUCLEAN:
15782 - /* MTD's ECC fixed the data */
15783 - eccres = YAFFS_ECC_RESULT_FIXED;
15784 - dev->eccFixed++;
15785 - break;
15786 -
15787 - case -EBADMSG:
15788 - /* MTD's ECC could not fix the data */
15789 - dev->eccUnfixed++;
15790 - /* fall into... */
15791 - default:
15792 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
15793 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
15794 - return YAFFS_FAIL;
15795 - }
15796 -
15797 - /* Check for a blank/erased chunk.
15798 - */
15799 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
15800 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
15801 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
15802 - }
15803 -
15804 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15805 - /* Read deleted status (bit) then return it to it's non-deleted
15806 - * state before performing tags mini-ECC check. pt1.deleted is
15807 - * inverted.
15808 - */
15809 - deleted = !pt1.deleted;
15810 - pt1.deleted = 1;
15811 -#else
15812 - (void) deleted; /* not used */
15813 -#endif
15814 -
15815 - /* Check the packed tags mini-ECC and correct if necessary/possible.
15816 - */
15817 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
15818 - switch (retval) {
15819 - case 0:
15820 - /* no tags error, use MTD result */
15821 - break;
15822 - case 1:
15823 - /* recovered tags-ECC error */
15824 - dev->tagsEccFixed++;
15825 - eccres = YAFFS_ECC_RESULT_FIXED;
15826 - break;
15827 - default:
15828 - /* unrecovered tags-ECC error */
15829 - dev->tagsEccUnfixed++;
15830 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
15831 - }
15832 -
15833 - /* Unpack the tags to extended form and set ECC result.
15834 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
15835 - */
15836 - pt1.shouldBeFF = 0xFFFFFFFF;
15837 - yaffs_UnpackTags1(etags, &pt1);
15838 - etags->eccResult = eccres;
15839 -
15840 - /* Set deleted state.
15841 - */
15842 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15843 - etags->chunkDeleted = deleted;
15844 -#else
15845 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
15846 -#endif
15847 - return YAFFS_OK;
15848 -}
15849 -
15850 -/* Mark a block bad.
15851 - *
15852 - * This is a persistant state.
15853 - * Use of this function should be rare.
15854 - *
15855 - * Returns YAFFS_OK or YAFFS_FAIL.
15856 - */
15857 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15858 -{
15859 - struct mtd_info * mtd = dev->genericDevice;
15860 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15861 - int retval;
15862 -
15863 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
15864 -
15865 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15866 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
15867 -}
15868 -
15869 -/* Check any MTD prerequists.
15870 - *
15871 - * Returns YAFFS_OK or YAFFS_FAIL.
15872 - */
15873 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
15874 -{
15875 - /* 2.6.18 has mtd->ecclayout->oobavail */
15876 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
15877 - int oobavail = mtd->ecclayout->oobavail;
15878 -
15879 - if (oobavail < YTAG1_SIZE) {
15880 - yaffs_trace(YAFFS_TRACE_ERROR,
15881 - "mtd device has only %d bytes for tags, need %d",
15882 - oobavail, YTAG1_SIZE);
15883 - return YAFFS_FAIL;
15884 - }
15885 - return YAFFS_OK;
15886 -}
15887 -
15888 -/* Query for the current state of a specific block.
15889 - *
15890 - * Examine the tags of the first chunk of the block and return the state:
15891 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
15892 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
15893 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
15894 - *
15895 - * Always returns YAFFS_OK.
15896 - */
15897 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15898 - yaffs_BlockState * pState, int *pSequenceNumber)
15899 -{
15900 - struct mtd_info * mtd = dev->genericDevice;
15901 - int chunkNo = blockNo * dev->nChunksPerBlock;
15902 - yaffs_ExtendedTags etags;
15903 - int state = YAFFS_BLOCK_STATE_DEAD;
15904 - int seqnum = 0;
15905 - int retval;
15906 -
15907 - /* We don't yet have a good place to test for MTD config prerequists.
15908 - * Do it here as we are called during the initial scan.
15909 - */
15910 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
15911 - return YAFFS_FAIL;
15912 - }
15913 -
15914 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15915 - if (etags.blockBad) {
15916 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15917 - "block %d is marked bad", blockNo);
15918 - state = YAFFS_BLOCK_STATE_DEAD;
15919 - }
15920 - else if (etags.chunkUsed) {
15921 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
15922 - seqnum = etags.sequenceNumber;
15923 - }
15924 - else {
15925 - state = YAFFS_BLOCK_STATE_EMPTY;
15926 - }
15927 -
15928 - *pState = state;
15929 - *pSequenceNumber = seqnum;
15930 -
15931 - /* query always succeeds */
15932 - return YAFFS_OK;
15933 -}
15934 -
15935 -#endif /*KERNEL_VERSION*/
15936 -
15937 ---Boundary-00=_5LbTGmt62YoutxM--
15938 -
15939 -
15940 -
15941 --- a/fs/yaffs2/yaffs_mtdif1.h
15942 +++ b/fs/yaffs2/yaffs_mtdif1.h
15943 @@ -1,7 +1,7 @@
15944 /*
15945 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
15946 *
15947 - * Copyright (C) 2002-2007 Aleph One Ltd.
15948 + * Copyright (C) 2002-2010 Aleph One Ltd.
15949 * for Toby Churchill Ltd and Brightstar Engineering
15950 *
15951 * This program is free software; you can redistribute it and/or modify
15952 --- a/fs/yaffs2/yaffs_mtdif2.c
15953 +++ b/fs/yaffs2/yaffs_mtdif2.c
15954 @@ -1,7 +1,7 @@
15955 /*
15956 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
15957 *
15958 - * Copyright (C) 2002-2007 Aleph One Ltd.
15959 + * Copyright (C) 2002-2010 Aleph One Ltd.
15960 * for Toby Churchill Ltd and Brightstar Engineering
15961 *
15962 * Created by Charles Manning <charles@aleph1.co.uk>
15963 @@ -13,11 +13,8 @@
15964
15965 /* mtd interface for YAFFS2 */
15966
15967 -const char *yaffs_mtdif2_c_version =
15968 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
15969 -
15970 #include "yportenv.h"
15971 -
15972 +#include "yaffs_trace.h"
15973
15974 #include "yaffs_mtdif2.h"
15975
15976 @@ -27,6 +24,8 @@ const char *yaffs_mtdif2_c_version =
15977
15978 #include "yaffs_packedtags2.h"
15979
15980 +#include "yaffs_linux.h"
15981 +
15982 /* NB For use with inband tags....
15983 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
15984 * use it to load the tags.
15985 @@ -35,7 +34,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
15986 const __u8 *data,
15987 const yaffs_ExtendedTags *tags)
15988 {
15989 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
15990 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15991 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
15992 struct mtd_oob_ops ops;
15993 #else
15994 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
15995
15996 yaffs_PackedTags2 pt;
15997
15998 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
15999 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt;
16000 +
16001 T(YAFFS_TRACE_MTD,
16002 (TSTR
16003 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
16004 TENDSTR), chunkInNAND, data, tags));
16005
16006
16007 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16008 + addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16009
16010 /* For yaffs2 writing there must be both data and tags.
16011 * If we're using inband tags, then the tags are stuffed into
16012 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16013 */
16014 if (!data || !tags)
16015 BUG();
16016 - else if (dev->inbandTags) {
16017 + else if (dev->param.inbandTags) {
16018 yaffs_PackedTags2TagsPart *pt2tp;
16019 pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
16020 yaffs_PackTags2TagsPart(pt2tp, tags);
16021 } else
16022 - yaffs_PackTags2(&pt, tags);
16023 + yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC);
16024
16025 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16026 ops.mode = MTD_OOB_AUTO;
16027 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
16028 - ops.len = dev->totalBytesPerChunk;
16029 + ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size;
16030 + ops.len = dev->param.totalBytesPerChunk;
16031 ops.ooboffs = 0;
16032 ops.datbuf = (__u8 *)data;
16033 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
16034 + ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr;
16035 retval = mtd->write_oob(mtd, addr, &ops);
16036
16037 #else
16038 - if (!dev->inbandTags) {
16039 + if (!dev->param.inbandTags) {
16040 retval =
16041 mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16042 - &dummy, data, (__u8 *) &pt, NULL);
16043 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
16044 } else {
16045 retval =
16046 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
16047 + mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy,
16048 data);
16049 }
16050 #endif
16051 @@ -98,7 +100,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16052 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
16053 __u8 *data, yaffs_ExtendedTags *tags)
16054 {
16055 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16056 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16057 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16058 struct mtd_oob_ops ops;
16059 #endif
16060 @@ -106,16 +108,19 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16061 int retval = 0;
16062 int localData = 0;
16063
16064 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16065 + loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16066
16067 yaffs_PackedTags2 pt;
16068
16069 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
16070 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt;
16071 +
16072 T(YAFFS_TRACE_MTD,
16073 (TSTR
16074 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
16075 TENDSTR), chunkInNAND, data, tags));
16076
16077 - if (dev->inbandTags) {
16078 + if (dev->param.inbandTags) {
16079
16080 if (!data) {
16081 localData = 1;
16082 @@ -127,20 +132,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16083
16084
16085 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16086 - if (dev->inbandTags || (data && !tags))
16087 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
16088 + if (dev->param.inbandTags || (data && !tags))
16089 + retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk,
16090 &dummy, data);
16091 else if (tags) {
16092 ops.mode = MTD_OOB_AUTO;
16093 - ops.ooblen = sizeof(pt);
16094 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
16095 + ops.ooblen = packed_tags_size;
16096 + ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size;
16097 ops.ooboffs = 0;
16098 ops.datbuf = data;
16099 - ops.oobbuf = dev->spareBuffer;
16100 + ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer;
16101 retval = mtd->read_oob(mtd, addr, &ops);
16102 }
16103 #else
16104 - if (!dev->inbandTags && data && tags) {
16105 + if (!dev->param.inbandTags && data && tags) {
16106
16107 retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16108 &dummy, data, dev->spareBuffer,
16109 @@ -150,7 +155,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16110 retval =
16111 mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16112 data);
16113 - if (!dev->inbandTags && tags)
16114 + if (!dev->param.inbandTags && tags)
16115 retval =
16116 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
16117 dev->spareBuffer);
16118 @@ -158,7 +163,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16119 #endif
16120
16121
16122 - if (dev->inbandTags) {
16123 + if (dev->param.inbandTags) {
16124 if (tags) {
16125 yaffs_PackedTags2TagsPart *pt2tp;
16126 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
16127 @@ -166,16 +171,22 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16128 }
16129 } else {
16130 if (tags) {
16131 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
16132 - yaffs_UnpackTags2(tags, &pt);
16133 + memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size);
16134 + yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC);
16135 }
16136 }
16137
16138 if (localData)
16139 yaffs_ReleaseTempBuffer(dev, data, __LINE__);
16140
16141 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
16142 + if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16143 tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
16144 + dev->eccUnfixed++;
16145 + }
16146 + if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16147 + tags->eccResult = YAFFS_ECC_RESULT_FIXED;
16148 + dev->eccFixed++;
16149 + }
16150 if (retval == 0)
16151 return YAFFS_OK;
16152 else
16153 @@ -184,15 +195,15 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16154
16155 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
16156 {
16157 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16158 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16159 int retval;
16160 T(YAFFS_TRACE_MTD,
16161 (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
16162
16163 retval =
16164 mtd->block_markbad(mtd,
16165 - blockNo * dev->nChunksPerBlock *
16166 - dev->totalBytesPerChunk);
16167 + blockNo * dev->param.nChunksPerBlock *
16168 + dev->param.totalBytesPerChunk);
16169
16170 if (retval == 0)
16171 return YAFFS_OK;
16172 @@ -204,15 +215,15 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
16173 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
16174 yaffs_BlockState *state, __u32 *sequenceNumber)
16175 {
16176 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16177 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16178 int retval;
16179
16180 T(YAFFS_TRACE_MTD,
16181 (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
16182 retval =
16183 mtd->block_isbad(mtd,
16184 - blockNo * dev->nChunksPerBlock *
16185 - dev->totalBytesPerChunk);
16186 + blockNo * dev->param.nChunksPerBlock *
16187 + dev->param.totalBytesPerChunk);
16188
16189 if (retval) {
16190 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
16191 @@ -223,7 +234,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs
16192 yaffs_ExtendedTags t;
16193 nandmtd2_ReadChunkWithTagsFromNAND(dev,
16194 blockNo *
16195 - dev->nChunksPerBlock, NULL,
16196 + dev->param.nChunksPerBlock, NULL,
16197 &t);
16198
16199 if (t.chunkUsed) {
16200 --- a/fs/yaffs2/yaffs_mtdif2.h
16201 +++ b/fs/yaffs2/yaffs_mtdif2.h
16202 @@ -1,7 +1,7 @@
16203 /*
16204 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16205 *
16206 - * Copyright (C) 2002-2007 Aleph One Ltd.
16207 + * Copyright (C) 2002-2010 Aleph One Ltd.
16208 * for Toby Churchill Ltd and Brightstar Engineering
16209 *
16210 * Created by Charles Manning <charles@aleph1.co.uk>
16211 --- a/fs/yaffs2/yaffs_mtdif.c
16212 +++ b/fs/yaffs2/yaffs_mtdif.c
16213 @@ -1,7 +1,7 @@
16214 /*
16215 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16216 *
16217 - * Copyright (C) 2002-2007 Aleph One Ltd.
16218 + * Copyright (C) 2002-2010 Aleph One Ltd.
16219 * for Toby Churchill Ltd and Brightstar Engineering
16220 *
16221 * Created by Charles Manning <charles@aleph1.co.uk>
16222 @@ -11,9 +11,6 @@
16223 * published by the Free Software Foundation.
16224 */
16225
16226 -const char *yaffs_mtdif_c_version =
16227 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
16228 -
16229 #include "yportenv.h"
16230
16231
16232 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
16233 #include "linux/time.h"
16234 #include "linux/mtd/nand.h"
16235
16236 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
16237 -static struct nand_oobinfo yaffs_oobinfo = {
16238 - .useecc = 1,
16239 - .eccbytes = 6,
16240 - .eccpos = {8, 9, 10, 13, 14, 15}
16241 -};
16242 -
16243 -static struct nand_oobinfo yaffs_noeccinfo = {
16244 - .useecc = 0,
16245 -};
16246 -#endif
16247 -
16248 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16249 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
16250 -{
16251 - oob[0] = spare->tagByte0;
16252 - oob[1] = spare->tagByte1;
16253 - oob[2] = spare->tagByte2;
16254 - oob[3] = spare->tagByte3;
16255 - oob[4] = spare->tagByte4;
16256 - oob[5] = spare->tagByte5 & 0x3f;
16257 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
16258 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
16259 - oob[6] = spare->tagByte6;
16260 - oob[7] = spare->tagByte7;
16261 -}
16262 -
16263 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
16264 -{
16265 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
16266 - spare->tagByte0 = oob[0];
16267 - spare->tagByte1 = oob[1];
16268 - spare->tagByte2 = oob[2];
16269 - spare->tagByte3 = oob[3];
16270 - spare->tagByte4 = oob[4];
16271 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
16272 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
16273 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
16274 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
16275 - spare->tagByte6 = oob[6];
16276 - spare->tagByte7 = oob[7];
16277 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
16278 -
16279 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
16280 -}
16281 -#endif
16282 -
16283 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16284 - const __u8 *data, const yaffs_Spare *spare)
16285 -{
16286 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16287 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16288 - struct mtd_oob_ops ops;
16289 -#endif
16290 - size_t dummy;
16291 - int retval = 0;
16292 -
16293 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16294 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16295 - __u8 spareAsBytes[8]; /* OOB */
16296 -
16297 - if (data && !spare)
16298 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
16299 - &dummy, data);
16300 - else if (spare) {
16301 - if (dev->useNANDECC) {
16302 - translate_spare2oob(spare, spareAsBytes);
16303 - ops.mode = MTD_OOB_AUTO;
16304 - ops.ooblen = 8; /* temp hack */
16305 - } else {
16306 - ops.mode = MTD_OOB_RAW;
16307 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16308 - }
16309 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16310 - ops.datbuf = (u8 *)data;
16311 - ops.ooboffs = 0;
16312 - ops.oobbuf = spareAsBytes;
16313 - retval = mtd->write_oob(mtd, addr, &ops);
16314 - }
16315 -#else
16316 - __u8 *spareAsBytes = (__u8 *) spare;
16317 -
16318 - if (data && spare) {
16319 - if (dev->useNANDECC)
16320 - retval =
16321 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16322 - &dummy, data, spareAsBytes,
16323 - &yaffs_oobinfo);
16324 - else
16325 - retval =
16326 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16327 - &dummy, data, spareAsBytes,
16328 - &yaffs_noeccinfo);
16329 - } else {
16330 - if (data)
16331 - retval =
16332 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16333 - data);
16334 - if (spare)
16335 - retval =
16336 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16337 - &dummy, spareAsBytes);
16338 - }
16339 -#endif
16340 -
16341 - if (retval == 0)
16342 - return YAFFS_OK;
16343 - else
16344 - return YAFFS_FAIL;
16345 -}
16346 -
16347 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16348 - yaffs_Spare *spare)
16349 -{
16350 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16351 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16352 - struct mtd_oob_ops ops;
16353 -#endif
16354 - size_t dummy;
16355 - int retval = 0;
16356 -
16357 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16358 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16359 - __u8 spareAsBytes[8]; /* OOB */
16360 -
16361 - if (data && !spare)
16362 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
16363 - &dummy, data);
16364 - else if (spare) {
16365 - if (dev->useNANDECC) {
16366 - ops.mode = MTD_OOB_AUTO;
16367 - ops.ooblen = 8; /* temp hack */
16368 - } else {
16369 - ops.mode = MTD_OOB_RAW;
16370 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16371 - }
16372 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16373 - ops.datbuf = data;
16374 - ops.ooboffs = 0;
16375 - ops.oobbuf = spareAsBytes;
16376 - retval = mtd->read_oob(mtd, addr, &ops);
16377 - if (dev->useNANDECC)
16378 - translate_oob2spare(spare, spareAsBytes);
16379 - }
16380 -#else
16381 - __u8 *spareAsBytes = (__u8 *) spare;
16382 -
16383 - if (data && spare) {
16384 - if (dev->useNANDECC) {
16385 - /* Careful, this call adds 2 ints */
16386 - /* to the end of the spare data. Calling function */
16387 - /* should allocate enough memory for spare, */
16388 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
16389 - retval =
16390 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16391 - &dummy, data, spareAsBytes,
16392 - &yaffs_oobinfo);
16393 - } else {
16394 - retval =
16395 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16396 - &dummy, data, spareAsBytes,
16397 - &yaffs_noeccinfo);
16398 - }
16399 - } else {
16400 - if (data)
16401 - retval =
16402 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16403 - data);
16404 - if (spare)
16405 - retval =
16406 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16407 - &dummy, spareAsBytes);
16408 - }
16409 -#endif
16410 -
16411 - if (retval == 0)
16412 - return YAFFS_OK;
16413 - else
16414 - return YAFFS_FAIL;
16415 -}
16416 +#include "yaffs_linux.h"
16417
16418 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
16419 {
16420 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16421 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16422 __u32 addr =
16423 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
16424 - * dev->nChunksPerBlock;
16425 + ((loff_t) blockNumber) * dev->param.totalBytesPerChunk
16426 + * dev->param.nChunksPerBlock;
16427 struct erase_info ei;
16428 +
16429 int retval = 0;
16430
16431 ei.mtd = mtd;
16432 ei.addr = addr;
16433 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
16434 + ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock;
16435 ei.time = 1000;
16436 ei.retries = 2;
16437 ei.callback = NULL;
16438 ei.priv = (u_long) dev;
16439
16440 - /* Todo finish off the ei if required */
16441 -
16442 - sema_init(&dev->sem, 0);
16443 -
16444 retval = mtd->erase(mtd, &ei);
16445
16446 if (retval == 0)
16447 --- a/fs/yaffs2/yaffs_mtdif.h
16448 +++ b/fs/yaffs2/yaffs_mtdif.h
16449 @@ -1,7 +1,7 @@
16450 /*
16451 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16452 *
16453 - * Copyright (C) 2002-2007 Aleph One Ltd.
16454 + * Copyright (C) 2002-2010 Aleph One Ltd.
16455 * for Toby Churchill Ltd and Brightstar Engineering
16456 *
16457 * Created by Charles Manning <charles@aleph1.co.uk>
16458 @@ -22,11 +22,6 @@
16459 extern struct nand_oobinfo yaffs_oobinfo;
16460 extern struct nand_oobinfo yaffs_noeccinfo;
16461 #endif
16462 -
16463 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16464 - const __u8 *data, const yaffs_Spare *spare);
16465 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16466 - yaffs_Spare *spare);
16467 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
16468 int nandmtd_InitialiseNAND(yaffs_Device *dev);
16469 #endif
16470 --- /dev/null
16471 +++ b/fs/yaffs2/yaffs_nameval.c
16472 @@ -0,0 +1,197 @@
16473 +/*
16474 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16475 + *
16476 + * Copyright (C) 2002-2010 Aleph One Ltd.
16477 + * for Toby Churchill Ltd and Brightstar Engineering
16478 + *
16479 + * Created by Charles Manning <charles@aleph1.co.uk>
16480 + *
16481 + * This program is free software; you can redistribute it and/or modify
16482 + * it under the terms of the GNU General Public License version 2 as
16483 + * published by the Free Software Foundation.
16484 + */
16485 +
16486 +/*
16487 + * This simple implementation of a name-value store assumes a small number of values and fits
16488 + * into a small finite buffer.
16489 + *
16490 + * Each attribute is stored as a record:
16491 + * sizeof(int) bytes record size.
16492 + * strnlen+1 bytes name null terminated.
16493 + * nbytes value.
16494 + * ----------
16495 + * total size stored in record size
16496 + *
16497 + * This code has not been tested with unicode yet.
16498 + */
16499 +
16500 +
16501 +#include "yaffs_nameval.h"
16502 +
16503 +#include "yportenv.h"
16504 +
16505 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
16506 + int *exist_size)
16507 +{
16508 + int pos=0;
16509 + int size;
16510 +
16511 + memcpy(&size,xb,sizeof(int));
16512 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16513 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
16514 + if(exist_size)
16515 + *exist_size = size;
16516 + return pos;
16517 + }
16518 + pos += size;
16519 + if(pos < xb_size -sizeof(int))
16520 + memcpy(&size,xb + pos,sizeof(int));
16521 + else
16522 + size = 0;
16523 + }
16524 + if(exist_size)
16525 + *exist_size = 0;
16526 + return -1;
16527 +}
16528 +
16529 +static int nval_used(const char *xb, int xb_size)
16530 +{
16531 + int pos=0;
16532 + int size;
16533 +
16534 + memcpy(&size,xb + pos,sizeof(int));
16535 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16536 + pos += size;
16537 + if(pos < xb_size -sizeof(int))
16538 + memcpy(&size,xb + pos,sizeof(int));
16539 + else
16540 + size = 0;
16541 + }
16542 + return pos;
16543 +}
16544 +
16545 +int nval_del(char *xb, int xb_size, const YCHAR *name)
16546 +{
16547 + int pos = nval_find(xb, xb_size, name, NULL);
16548 + int size;
16549 +
16550 + if(pos >= 0 && pos < xb_size){
16551 + /* Find size, shift rest over this record, then zero out the rest of buffer */
16552 + memcpy(&size,xb+pos,sizeof(int));
16553 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
16554 + memset(xb + (xb_size - size),0,size);
16555 + return 0;
16556 + } else
16557 + return -ENODATA;
16558 +}
16559 +
16560 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
16561 +{
16562 + int pos;
16563 + int namelen = yaffs_strnlen(name,xb_size);
16564 + int reclen;
16565 + int size_exist = 0;
16566 + int space;
16567 + int start;
16568 +
16569 + pos = nval_find(xb,xb_size,name, &size_exist);
16570 +
16571 + if(flags & XATTR_CREATE && pos >= 0)
16572 + return -EEXIST;
16573 + if(flags & XATTR_REPLACE && pos < 0)
16574 + return -ENODATA;
16575 +
16576 + start = nval_used(xb,xb_size);
16577 + space = xb_size - start + size_exist;
16578 +
16579 + reclen = (sizeof(int) + namelen + 1 + bsize);
16580 +
16581 + if(reclen > space)
16582 + return -ENOSPC;
16583 +
16584 + if(pos >= 0){
16585 + nval_del(xb,xb_size,name);
16586 + start = nval_used(xb, xb_size);
16587 + }
16588 +
16589 + pos = start;
16590 +
16591 + memcpy(xb + pos,&reclen,sizeof(int));
16592 + pos +=sizeof(int);
16593 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
16594 + pos+= (namelen+1);
16595 + memcpy(xb + pos,buf,bsize);
16596 + return 0;
16597 +}
16598 +
16599 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
16600 +{
16601 + int pos = nval_find(xb,xb_size,name,NULL);
16602 + int size;
16603 +
16604 + if(pos >= 0 && pos< xb_size){
16605 +
16606 + memcpy(&size,xb +pos,sizeof(int));
16607 + pos+=sizeof(int); /* advance past record length */
16608 + size -= sizeof(int);
16609 +
16610 + /* Advance over name string */
16611 + while(xb[pos] && size > 0 && pos < xb_size){
16612 + pos++;
16613 + size--;
16614 + }
16615 + /*Advance over NUL */
16616 + pos++;
16617 + size--;
16618 +
16619 + if(size <= bsize){
16620 + memcpy(buf,xb + pos,size);
16621 + return size;
16622 + }
16623 +
16624 + }
16625 + if(pos >= 0)
16626 + return -ERANGE;
16627 + else
16628 + return -ENODATA;
16629 +}
16630 +
16631 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
16632 +{
16633 + int pos = 0;
16634 + int size;
16635 + int name_len;
16636 + int ncopied = 0;
16637 + int filled = 0;
16638 +
16639 + memcpy(&size,xb + pos,sizeof(int));
16640 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
16641 + pos+= sizeof(int);
16642 + size-=sizeof(int);
16643 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
16644 + if(ncopied + name_len + 1 < bsize){
16645 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
16646 + buf+= name_len;
16647 + *buf = '\0';
16648 + buf++;
16649 + if(sizeof(YCHAR) > 1){
16650 + *buf = '\0';
16651 + buf++;
16652 + }
16653 + ncopied += (name_len+1);
16654 + } else
16655 + filled = 1;
16656 + pos+=size;
16657 + if(pos < xb_size -sizeof(int))
16658 + memcpy(&size,xb + pos,sizeof(int));
16659 + else
16660 + size = 0;
16661 + }
16662 + return ncopied;
16663 +}
16664 +
16665 +
16666 +int nval_hasvalues(const char *xb, int xb_size)
16667 +{
16668 + return nval_used(xb, xb_size) > 0;
16669 +}
16670 --- /dev/null
16671 +++ b/fs/yaffs2/yaffs_nameval.h
16672 @@ -0,0 +1,25 @@
16673 +/*
16674 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16675 + *
16676 + * Copyright (C) 2002-2010 Aleph One Ltd.
16677 + * for Toby Churchill Ltd and Brightstar Engineering
16678 + *
16679 + * Created by Charles Manning <charles@aleph1.co.uk>
16680 + *
16681 + * This program is free software; you can redistribute it and/or modify
16682 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16683 + * published by the Free Software Foundation.
16684 + *
16685 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16686 + */
16687 +#ifndef __NAMEVAL_H__
16688 +#define __NAMEVAL_H__
16689 +
16690 +#include "yportenv.h"
16691 +
16692 +int nval_del(char *xb, int xb_size, const YCHAR *name);
16693 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
16694 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
16695 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
16696 +int nval_hasvalues(const char *xb, int xb_size);
16697 +#endif
16698 --- a/fs/yaffs2/yaffs_nand.c
16699 +++ b/fs/yaffs2/yaffs_nand.c
16700 @@ -1,7 +1,7 @@
16701 /*
16702 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16703 *
16704 - * Copyright (C) 2002-2007 Aleph One Ltd.
16705 + * Copyright (C) 2002-2010 Aleph One Ltd.
16706 * for Toby Churchill Ltd and Brightstar Engineering
16707 *
16708 * Created by Charles Manning <charles@aleph1.co.uk>
16709 @@ -11,9 +11,6 @@
16710 * published by the Free Software Foundation.
16711 */
16712
16713 -const char *yaffs_nand_c_version =
16714 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
16715 -
16716 #include "yaffs_nand.h"
16717 #include "yaffs_tagscompat.h"
16718 #include "yaffs_tagsvalidity.h"
16719 @@ -29,12 +26,14 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16720
16721 int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
16722
16723 + dev->nPageReads++;
16724 +
16725 /* If there are no tags provided, use local tags to get prioritised gc working */
16726 if (!tags)
16727 tags = &localTags;
16728
16729 - if (dev->readChunkWithTagsFromNAND)
16730 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16731 + if (dev->param.readChunkWithTagsFromNAND)
16732 + result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16733 tags);
16734 else
16735 result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
16736 @@ -44,7 +43,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16737 if (tags &&
16738 tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
16739
16740 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
16741 + yaffs_BlockInfo *bi;
16742 + bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock);
16743 yaffs_HandleChunkError(dev, bi);
16744 }
16745
16746 @@ -56,6 +56,9 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16747 const __u8 *buffer,
16748 yaffs_ExtendedTags *tags)
16749 {
16750 +
16751 + dev->nPageWrites++;
16752 +
16753 chunkInNAND -= dev->chunkOffset;
16754
16755
16756 @@ -75,8 +78,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16757 YBUG();
16758 }
16759
16760 - if (dev->writeChunkWithTagsToNAND)
16761 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16762 + if (dev->param.writeChunkWithTagsToNAND)
16763 + return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16764 tags);
16765 else
16766 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
16767 @@ -89,9 +92,9 @@ int yaffs_MarkBlockBad(yaffs_Device *dev
16768 {
16769 blockNo -= dev->blockOffset;
16770
16771 -;
16772 - if (dev->markNANDBlockBad)
16773 - return dev->markNANDBlockBad(dev, blockNo);
16774 +
16775 + if (dev->param.markNANDBlockBad)
16776 + return dev->param.markNANDBlockBad(dev, blockNo);
16777 else
16778 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
16779 }
16780 @@ -103,8 +106,8 @@ int yaffs_QueryInitialBlockState(yaffs_D
16781 {
16782 blockNo -= dev->blockOffset;
16783
16784 - if (dev->queryNANDBlock)
16785 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
16786 + if (dev->param.queryNANDBlock)
16787 + return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber);
16788 else
16789 return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
16790 state,
16791 @@ -119,16 +122,18 @@ int yaffs_EraseBlockInNAND(struct yaffs_
16792
16793 blockInNAND -= dev->blockOffset;
16794
16795 -
16796 dev->nBlockErasures++;
16797 - result = dev->eraseBlockInNAND(dev, blockInNAND);
16798 +
16799 + result = dev->param.eraseBlockInNAND(dev, blockInNAND);
16800
16801 return result;
16802 }
16803
16804 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
16805 {
16806 - return dev->initialiseNAND(dev);
16807 + if(dev->param.initialiseNAND)
16808 + return dev->param.initialiseNAND(dev);
16809 + return YAFFS_OK;
16810 }
16811
16812
16813 --- a/fs/yaffs2/yaffs_nandemul2k.h
16814 +++ b/fs/yaffs2/yaffs_nandemul2k.h
16815 @@ -1,7 +1,7 @@
16816 /*
16817 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16818 *
16819 - * Copyright (C) 2002-2007 Aleph One Ltd.
16820 + * Copyright (C) 2002-2010 Aleph One Ltd.
16821 * for Toby Churchill Ltd and Brightstar Engineering
16822 *
16823 * Created by Charles Manning <charles@aleph1.co.uk>
16824 --- a/fs/yaffs2/yaffs_nand.h
16825 +++ b/fs/yaffs2/yaffs_nand.h
16826 @@ -1,7 +1,7 @@
16827 /*
16828 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16829 *
16830 - * Copyright (C) 2002-2007 Aleph One Ltd.
16831 + * Copyright (C) 2002-2010 Aleph One Ltd.
16832 * for Toby Churchill Ltd and Brightstar Engineering
16833 *
16834 * Created by Charles Manning <charles@aleph1.co.uk>
16835 --- a/fs/yaffs2/yaffs_packedtags1.c
16836 +++ b/fs/yaffs2/yaffs_packedtags1.c
16837 @@ -1,7 +1,7 @@
16838 /*
16839 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16840 *
16841 - * Copyright (C) 2002-2007 Aleph One Ltd.
16842 + * Copyright (C) 2002-2010 Aleph One Ltd.
16843 * for Toby Churchill Ltd and Brightstar Engineering
16844 *
16845 * Created by Charles Manning <charles@aleph1.co.uk>
16846 --- a/fs/yaffs2/yaffs_packedtags1.h
16847 +++ b/fs/yaffs2/yaffs_packedtags1.h
16848 @@ -1,7 +1,7 @@
16849 /*
16850 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16851 *
16852 - * Copyright (C) 2002-2007 Aleph One Ltd.
16853 + * Copyright (C) 2002-2010 Aleph One Ltd.
16854 * for Toby Churchill Ltd and Brightstar Engineering
16855 *
16856 * Created by Charles Manning <charles@aleph1.co.uk>
16857 --- a/fs/yaffs2/yaffs_packedtags2.c
16858 +++ b/fs/yaffs2/yaffs_packedtags2.c
16859 @@ -1,7 +1,7 @@
16860 /*
16861 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16862 *
16863 - * Copyright (C) 2002-2007 Aleph One Ltd.
16864 + * Copyright (C) 2002-2010 Aleph One Ltd.
16865 * for Toby Churchill Ltd and Brightstar Engineering
16866 *
16867 * Created by Charles Manning <charles@aleph1.co.uk>
16868 @@ -13,6 +13,7 @@
16869
16870 #include "yaffs_packedtags2.h"
16871 #include "yportenv.h"
16872 +#include "yaffs_trace.h"
16873 #include "yaffs_tagsvalidity.h"
16874
16875 /* This code packs a set of extended tags into a binary structure for
16876 @@ -96,17 +97,14 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
16877 }
16878
16879
16880 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
16881 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC)
16882 {
16883 yaffs_PackTags2TagsPart(&pt->t, t);
16884
16885 -#ifndef YAFFS_IGNORE_TAGS_ECC
16886 - {
16887 + if(tagsECC)
16888 yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16889 sizeof(yaffs_PackedTags2TagsPart),
16890 &pt->ecc);
16891 - }
16892 -#endif
16893 }
16894
16895
16896 @@ -158,27 +156,24 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
16897 }
16898
16899
16900 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
16901 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC)
16902 {
16903
16904 yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16905
16906 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
16907 - /* Page is in use */
16908 -#ifndef YAFFS_IGNORE_TAGS_ECC
16909 - {
16910 - yaffs_ECCOther ecc;
16911 - int result;
16912 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16913 - sizeof
16914 - (yaffs_PackedTags2TagsPart),
16915 - &ecc);
16916 - result =
16917 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16918 - sizeof
16919 - (yaffs_PackedTags2TagsPart),
16920 - &pt->ecc, &ecc);
16921 - switch (result) {
16922 + if (pt->t.sequenceNumber != 0xFFFFFFFF &&
16923 + tagsECC){
16924 + /* Chunk is in use and we need to do ECC */
16925 +
16926 + yaffs_ECCOther ecc;
16927 + int result;
16928 + yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16929 + sizeof(yaffs_PackedTags2TagsPart),
16930 + &ecc);
16931 + result = yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16932 + sizeof(yaffs_PackedTags2TagsPart),
16933 + &pt->ecc, &ecc);
16934 + switch (result) {
16935 case 0:
16936 eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16937 break;
16938 @@ -190,9 +185,7 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16939 break;
16940 default:
16941 eccResult = YAFFS_ECC_RESULT_UNKNOWN;
16942 - }
16943 }
16944 -#endif
16945 }
16946
16947 yaffs_UnpackTags2TagsPart(t, &pt->t);
16948 @@ -201,6 +194,5 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16949
16950 yaffs_DumpPackedTags2(pt);
16951 yaffs_DumpTags2(t);
16952 -
16953 }
16954
16955 --- a/fs/yaffs2/yaffs_packedtags2.h
16956 +++ b/fs/yaffs2/yaffs_packedtags2.h
16957 @@ -1,7 +1,7 @@
16958 /*
16959 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16960 *
16961 - * Copyright (C) 2002-2007 Aleph One Ltd.
16962 + * Copyright (C) 2002-2010 Aleph One Ltd.
16963 * for Toby Churchill Ltd and Brightstar Engineering
16964 *
16965 * Created by Charles Manning <charles@aleph1.co.uk>
16966 @@ -34,8 +34,8 @@ typedef struct {
16967 } yaffs_PackedTags2;
16968
16969 /* Full packed tags with ECC, used for oob tags */
16970 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
16971 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
16972 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC);
16973 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC);
16974
16975 /* Only the tags part (no ECC for use with inband tags */
16976 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
16977 --- a/fs/yaffs2/yaffs_qsort.h
16978 +++ b/fs/yaffs2/yaffs_qsort.h
16979 @@ -1,7 +1,7 @@
16980 /*
16981 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16982 *
16983 - * Copyright (C) 2002-2007 Aleph One Ltd.
16984 + * Copyright (C) 2002-2010 Aleph One Ltd.
16985 * for Toby Churchill Ltd and Brightstar Engineering
16986 *
16987 * Created by Charles Manning <charles@aleph1.co.uk>
16988 @@ -17,7 +17,18 @@
16989 #ifndef __YAFFS_QSORT_H__
16990 #define __YAFFS_QSORT_H__
16991
16992 +#ifdef __KERNEL__
16993 +#include <linux/sort.h>
16994 +
16995 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
16996 + int (*cmp)(const void *, const void *)){
16997 + sort(base, total_elems, size, cmp, NULL);
16998 +}
16999 +
17000 +#else
17001 +
17002 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
17003 int (*cmp)(const void *, const void *));
17004
17005 #endif
17006 +#endif
17007 --- a/fs/yaffs2/yaffs_tagscompat.c
17008 +++ b/fs/yaffs2/yaffs_tagscompat.c
17009 @@ -1,7 +1,7 @@
17010 /*
17011 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17012 *
17013 - * Copyright (C) 2002-2007 Aleph One Ltd.
17014 + * Copyright (C) 2002-2010 Aleph One Ltd.
17015 * for Toby Churchill Ltd and Brightstar Engineering
17016 *
17017 * Created by Charles Manning <charles@aleph1.co.uk>
17018 @@ -15,6 +15,7 @@
17019 #include "yaffs_tagscompat.h"
17020 #include "yaffs_ecc.h"
17021 #include "yaffs_getblockinfo.h"
17022 +#include "yaffs_trace.h"
17023
17024 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
17025 #ifdef NOTYET
17026 @@ -163,15 +164,14 @@ static int yaffs_WriteChunkToNAND(struct
17027 int chunkInNAND, const __u8 *data,
17028 yaffs_Spare *spare)
17029 {
17030 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
17031 + if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) {
17032 T(YAFFS_TRACE_ERROR,
17033 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
17034 chunkInNAND));
17035 return YAFFS_FAIL;
17036 }
17037
17038 - dev->nPageWrites++;
17039 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
17040 + return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare);
17041 }
17042
17043 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
17044 @@ -184,16 +184,14 @@ static int yaffs_ReadChunkFromNAND(struc
17045 int retVal;
17046 yaffs_Spare localSpare;
17047
17048 - dev->nPageReads++;
17049 -
17050 if (!spare && data) {
17051 /* If we don't have a real spare, then we use a local one. */
17052 /* Need this for the calculation of the ecc */
17053 spare = &localSpare;
17054 }
17055
17056 - if (!dev->useNANDECC) {
17057 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
17058 + if (!dev->param.useNANDECC) {
17059 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare);
17060 if (data && doErrorCorrection) {
17061 /* Do ECC correction */
17062 /* Todo handle any errors */
17063 @@ -254,7 +252,7 @@ static int yaffs_ReadChunkFromNAND(struc
17064
17065 memset(&nspare, 0, sizeof(nspare));
17066
17067 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
17068 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data,
17069 (yaffs_Spare *) &nspare);
17070 memcpy(spare, &nspare, sizeof(yaffs_Spare));
17071 if (data && doErrorCorrection) {
17072 @@ -307,10 +305,10 @@ static int yaffs_CheckChunkErased(struct
17073 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
17074 static __u8 data[YAFFS_BYTES_PER_CHUNK];
17075 /* Might as well always allocate the larger size for */
17076 - /* dev->useNANDECC == true; */
17077 + /* dev->param.useNANDECC == true; */
17078 static __u8 spare[sizeof(struct yaffs_NANDSpare)];
17079
17080 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17081 + dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17082
17083 if (!init) {
17084 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
17085 @@ -333,7 +331,7 @@ static int yaffs_CheckChunkErased(struct
17086
17087 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
17088 {
17089 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17090 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17091
17092 /* Mark the block for retirement */
17093 yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
17094 @@ -365,7 +363,7 @@ static void yaffs_HandleUpdateChunk(yaff
17095
17096 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
17097 {
17098 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17099 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17100
17101 /* Mark the block for retirement */
17102 yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
17103 @@ -424,7 +422,7 @@ int yaffs_TagsCompatabilityWriteChunkWit
17104
17105 tags.serialNumber = eTags->serialNumber;
17106
17107 - if (!dev->useNANDECC && data)
17108 + if (!dev->param.useNANDECC && data)
17109 yaffs_CalcECC(data, &spare);
17110
17111 yaffs_LoadTagsIntoSpare(&spare, &tags);
17112 @@ -498,9 +496,9 @@ int yaffs_TagsCompatabilityMarkNANDBlock
17113
17114 spare.blockStatus = 'Y';
17115
17116 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
17117 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL,
17118 &spare);
17119 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
17120 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1,
17121 NULL, &spare);
17122
17123 return YAFFS_OK;
17124 @@ -525,9 +523,9 @@ int yaffs_TagsCompatabilityQueryNANDBloc
17125
17126 *sequenceNumber = 0;
17127
17128 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
17129 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL,
17130 &spare0, &dummy, 1);
17131 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
17132 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL,
17133 &spare1, &dummy, 1);
17134
17135 if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
17136 --- a/fs/yaffs2/yaffs_tagscompat.h
17137 +++ b/fs/yaffs2/yaffs_tagscompat.h
17138 @@ -1,7 +1,7 @@
17139 /*
17140 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17141 *
17142 - * Copyright (C) 2002-2007 Aleph One Ltd.
17143 + * Copyright (C) 2002-2010 Aleph One Ltd.
17144 * for Toby Churchill Ltd and Brightstar Engineering
17145 *
17146 * Created by Charles Manning <charles@aleph1.co.uk>
17147 --- a/fs/yaffs2/yaffs_tagsvalidity.c
17148 +++ b/fs/yaffs2/yaffs_tagsvalidity.c
17149 @@ -1,7 +1,7 @@
17150 /*
17151 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17152 *
17153 - * Copyright (C) 2002-2007 Aleph One Ltd.
17154 + * Copyright (C) 2002-2010 Aleph One Ltd.
17155 * for Toby Churchill Ltd and Brightstar Engineering
17156 *
17157 * Created by Charles Manning <charles@aleph1.co.uk>
17158 --- a/fs/yaffs2/yaffs_tagsvalidity.h
17159 +++ b/fs/yaffs2/yaffs_tagsvalidity.h
17160 @@ -1,7 +1,7 @@
17161 /*
17162 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17163 *
17164 - * Copyright (C) 2002-2007 Aleph One Ltd.
17165 + * Copyright (C) 2002-2010 Aleph One Ltd.
17166 * for Toby Churchill Ltd and Brightstar Engineering
17167 *
17168 * Created by Charles Manning <charles@aleph1.co.uk>
17169 --- /dev/null
17170 +++ b/fs/yaffs2/yaffs_trace.h
17171 @@ -0,0 +1,60 @@
17172 +/*
17173 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17174 + *
17175 + * Copyright (C) 2002-2010 Aleph One Ltd.
17176 + * for Toby Churchill Ltd and Brightstar Engineering
17177 + *
17178 + * Created by Charles Manning <charles@aleph1.co.uk>
17179 + *
17180 + * This program is free software; you can redistribute it and/or modify
17181 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17182 + * published by the Free Software Foundation.
17183 + *
17184 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17185 + */
17186 +
17187 +
17188 +#ifndef __YTRACE_H__
17189 +#define __YTRACE_H__
17190 +
17191 +extern unsigned int yaffs_traceMask;
17192 +extern unsigned int yaffs_wr_attempts;
17193 +
17194 +/*
17195 + * Tracing flags.
17196 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
17197 + */
17198 +
17199 +#define YAFFS_TRACE_OS 0x00000002
17200 +#define YAFFS_TRACE_ALLOCATE 0x00000004
17201 +#define YAFFS_TRACE_SCAN 0x00000008
17202 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
17203 +#define YAFFS_TRACE_ERASE 0x00000020
17204 +#define YAFFS_TRACE_GC 0x00000040
17205 +#define YAFFS_TRACE_WRITE 0x00000080
17206 +#define YAFFS_TRACE_TRACING 0x00000100
17207 +#define YAFFS_TRACE_DELETION 0x00000200
17208 +#define YAFFS_TRACE_BUFFERS 0x00000400
17209 +#define YAFFS_TRACE_NANDACCESS 0x00000800
17210 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
17211 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
17212 +#define YAFFS_TRACE_MTD 0x00004000
17213 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
17214 +
17215 +#define YAFFS_TRACE_VERIFY 0x00010000
17216 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
17217 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
17218 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
17219 +
17220 +#define YAFFS_TRACE_SYNC 0x00100000
17221 +#define YAFFS_TRACE_BACKGROUND 0x00200000
17222 +#define YAFFS_TRACE_LOCK 0x00400000
17223 +
17224 +#define YAFFS_TRACE_ERROR 0x40000000
17225 +#define YAFFS_TRACE_BUG 0x80000000
17226 +#define YAFFS_TRACE_ALWAYS 0xF0000000
17227 +
17228 +
17229 +#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
17230 +
17231 +#endif
17232 --- /dev/null
17233 +++ b/fs/yaffs2/yaffs_verify.c
17234 @@ -0,0 +1,626 @@
17235 +/*
17236 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17237 + *
17238 + * Copyright (C) 2002-2010 Aleph One Ltd.
17239 + * for Toby Churchill Ltd and Brightstar Engineering
17240 + *
17241 + * Created by Charles Manning <charles@aleph1.co.uk>
17242 + *
17243 + * This program is free software; you can redistribute it and/or modify
17244 + * it under the terms of the GNU General Public License version 2 as
17245 + * published by the Free Software Foundation.
17246 + */
17247 +
17248 +
17249 +#include "yaffs_verify.h"
17250 +#include "yaffs_trace.h"
17251 +#include "yaffs_bitmap.h"
17252 +#include "yaffs_getblockinfo.h"
17253 +#include "yaffs_nand.h"
17254 +
17255 +int yaffs_SkipVerification(yaffs_Device *dev)
17256 +{
17257 + dev=dev;
17258 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
17259 +}
17260 +
17261 +static int yaffs_SkipFullVerification(yaffs_Device *dev)
17262 +{
17263 + dev=dev;
17264 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
17265 +}
17266 +
17267 +static int yaffs_SkipNANDVerification(yaffs_Device *dev)
17268 +{
17269 + dev=dev;
17270 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
17271 +}
17272 +
17273 +
17274 +static const char *blockStateName[] = {
17275 +"Unknown",
17276 +"Needs scanning",
17277 +"Scanning",
17278 +"Empty",
17279 +"Allocating",
17280 +"Full",
17281 +"Dirty",
17282 +"Checkpoint",
17283 +"Collecting",
17284 +"Dead"
17285 +};
17286 +
17287 +
17288 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17289 +{
17290 + int actuallyUsed;
17291 + int inUse;
17292 +
17293 + if (yaffs_SkipVerification(dev))
17294 + return;
17295 +
17296 + /* Report illegal runtime states */
17297 + if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
17298 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
17299 +
17300 + switch (bi->blockState) {
17301 + case YAFFS_BLOCK_STATE_UNKNOWN:
17302 + case YAFFS_BLOCK_STATE_SCANNING:
17303 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
17304 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
17305 + n, blockStateName[bi->blockState]));
17306 + }
17307 +
17308 + /* Check pages in use and soft deletions are legal */
17309 +
17310 + actuallyUsed = bi->pagesInUse - bi->softDeletions;
17311 +
17312 + if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
17313 + bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
17314 + actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
17315 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
17316 + n, bi->pagesInUse, bi->softDeletions));
17317 +
17318 +
17319 + /* Check chunk bitmap legal */
17320 + inUse = yaffs_CountChunkBits(dev, n);
17321 + if (inUse != bi->pagesInUse)
17322 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
17323 + n, bi->pagesInUse, inUse));
17324 +
17325 +}
17326 +
17327 +
17328 +
17329 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17330 +{
17331 + yaffs_VerifyBlock(dev, bi, n);
17332 +
17333 + /* After collection the block should be in the erased state */
17334 +
17335 + if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
17336 + bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
17337 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
17338 + n, bi->blockState));
17339 + }
17340 +}
17341 +
17342 +void yaffs_VerifyBlocks(yaffs_Device *dev)
17343 +{
17344 + int i;
17345 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
17346 + int nIllegalBlockStates = 0;
17347 +
17348 + if (yaffs_SkipVerification(dev))
17349 + return;
17350 +
17351 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
17352 +
17353 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
17354 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
17355 + yaffs_VerifyBlock(dev, bi, i);
17356 +
17357 + if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
17358 + nBlocksPerState[bi->blockState]++;
17359 + else
17360 + nIllegalBlockStates++;
17361 + }
17362 +
17363 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17364 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
17365 +
17366 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
17367 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
17368 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
17369 +
17370 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
17371 + T(YAFFS_TRACE_VERIFY,
17372 + (TSTR("%s %d blocks"TENDSTR),
17373 + blockStateName[i], nBlocksPerState[i]));
17374 +
17375 + if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
17376 + T(YAFFS_TRACE_VERIFY,
17377 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
17378 + dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
17379 +
17380 + if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
17381 + T(YAFFS_TRACE_VERIFY,
17382 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
17383 + dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
17384 +
17385 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
17386 + T(YAFFS_TRACE_VERIFY,
17387 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
17388 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
17389 +
17390 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17391 +
17392 +}
17393 +
17394 +/*
17395 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
17396 + * case those tests will not be performed.
17397 + */
17398 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
17399 +{
17400 + if (obj && yaffs_SkipVerification(obj->myDev))
17401 + return;
17402 +
17403 + if (!(tags && obj && oh)) {
17404 + T(YAFFS_TRACE_VERIFY,
17405 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
17406 + tags, obj, oh));
17407 + return;
17408 + }
17409 +
17410 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
17411 + oh->type > YAFFS_OBJECT_TYPE_MAX)
17412 + T(YAFFS_TRACE_VERIFY,
17413 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
17414 + tags->objectId, oh->type));
17415 +
17416 + if (tags->objectId != obj->objectId)
17417 + T(YAFFS_TRACE_VERIFY,
17418 + (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
17419 + tags->objectId, obj->objectId));
17420 +
17421 +
17422 + /*
17423 + * Check that the object's parent ids match if parentCheck requested.
17424 + *
17425 + * Tests do not apply to the root object.
17426 + */
17427 +
17428 + if (parentCheck && tags->objectId > 1 && !obj->parent)
17429 + T(YAFFS_TRACE_VERIFY,
17430 + (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
17431 + tags->objectId, oh->parentObjectId));
17432 +
17433 + if (parentCheck && obj->parent &&
17434 + oh->parentObjectId != obj->parent->objectId &&
17435 + (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
17436 + obj->parent->objectId != YAFFS_OBJECTID_DELETED))
17437 + T(YAFFS_TRACE_VERIFY,
17438 + (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
17439 + tags->objectId, oh->parentObjectId, obj->parent->objectId));
17440 +
17441 + if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
17442 + T(YAFFS_TRACE_VERIFY,
17443 + (TSTR("Obj %d header name is NULL"TENDSTR),
17444 + obj->objectId));
17445 +
17446 + if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
17447 + T(YAFFS_TRACE_VERIFY,
17448 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
17449 + obj->objectId));
17450 +}
17451 +
17452 +
17453 +#if 0
17454 +/* Not being used, but don't want to throw away yet */
17455 +int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
17456 + __u32 level, int chunkOffset)
17457 +{
17458 + int i;
17459 + yaffs_Device *dev = obj->myDev;
17460 + int ok = 1;
17461 +
17462 + if (tn) {
17463 + if (level > 0) {
17464 +
17465 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
17466 + if (tn->internal[i]) {
17467 + ok = yaffs_VerifyTnodeWorker(obj,
17468 + tn->internal[i],
17469 + level - 1,
17470 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
17471 + }
17472 + }
17473 + } else if (level == 0) {
17474 + yaffs_ExtendedTags tags;
17475 + __u32 objectId = obj->objectId;
17476 +
17477 + chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
17478 +
17479 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
17480 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17481 +
17482 + if (theChunk > 0) {
17483 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
17484 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17485 + if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
17486 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17487 + objectId, chunkOffset, theChunk,
17488 + tags.objectId, tags.chunkId));
17489 + }
17490 + }
17491 + chunkOffset++;
17492 + }
17493 + }
17494 + }
17495 +
17496 + return ok;
17497 +
17498 +}
17499 +
17500 +#endif
17501 +
17502 +void yaffs_VerifyFile(yaffs_Object *obj)
17503 +{
17504 + int requiredTallness;
17505 + int actualTallness;
17506 + __u32 lastChunk;
17507 + __u32 x;
17508 + __u32 i;
17509 + yaffs_Device *dev;
17510 + yaffs_ExtendedTags tags;
17511 + yaffs_Tnode *tn;
17512 + __u32 objectId;
17513 +
17514 + if (!obj)
17515 + return;
17516 +
17517 + if (yaffs_SkipVerification(obj->myDev))
17518 + return;
17519 +
17520 + dev = obj->myDev;
17521 + objectId = obj->objectId;
17522 +
17523 + /* Check file size is consistent with tnode depth */
17524 + lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
17525 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
17526 + requiredTallness = 0;
17527 + while (x > 0) {
17528 + x >>= YAFFS_TNODES_INTERNAL_BITS;
17529 + requiredTallness++;
17530 + }
17531 +
17532 + actualTallness = obj->variant.fileVariant.topLevel;
17533 +
17534 + /* Check that the chunks in the tnode tree are all correct.
17535 + * We do this by scanning through the tnode tree and
17536 + * checking the tags for every chunk match.
17537 + */
17538 +
17539 + if (yaffs_SkipNANDVerification(dev))
17540 + return;
17541 +
17542 + for (i = 1; i <= lastChunk; i++) {
17543 + tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
17544 +
17545 + if (tn) {
17546 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17547 + if (theChunk > 0) {
17548 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
17549 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17550 + if (tags.objectId != objectId || tags.chunkId != i) {
17551 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17552 + objectId, i, theChunk,
17553 + tags.objectId, tags.chunkId));
17554 + }
17555 + }
17556 + }
17557 + }
17558 +}
17559 +
17560 +
17561 +void yaffs_VerifyHardLink(yaffs_Object *obj)
17562 +{
17563 + if (obj && yaffs_SkipVerification(obj->myDev))
17564 + return;
17565 +
17566 + /* Verify sane equivalent object */
17567 +}
17568 +
17569 +void yaffs_VerifySymlink(yaffs_Object *obj)
17570 +{
17571 + if (obj && yaffs_SkipVerification(obj->myDev))
17572 + return;
17573 +
17574 + /* Verify symlink string */
17575 +}
17576 +
17577 +void yaffs_VerifySpecial(yaffs_Object *obj)
17578 +{
17579 + if (obj && yaffs_SkipVerification(obj->myDev))
17580 + return;
17581 +}
17582 +
17583 +void yaffs_VerifyObject(yaffs_Object *obj)
17584 +{
17585 + yaffs_Device *dev;
17586 +
17587 + __u32 chunkMin;
17588 + __u32 chunkMax;
17589 +
17590 + __u32 chunkIdOk;
17591 + __u32 chunkInRange;
17592 + __u32 chunkShouldNotBeDeleted;
17593 + __u32 chunkValid;
17594 +
17595 + if (!obj)
17596 + return;
17597 +
17598 + if (obj->beingCreated)
17599 + return;
17600 +
17601 + dev = obj->myDev;
17602 +
17603 + if (yaffs_SkipVerification(dev))
17604 + return;
17605 +
17606 + /* Check sane object header chunk */
17607 +
17608 + chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
17609 + chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
17610 +
17611 + chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
17612 + chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
17613 + chunkValid = chunkInRange &&
17614 + yaffs_CheckChunkBit(dev,
17615 + obj->hdrChunk / dev->param.nChunksPerBlock,
17616 + obj->hdrChunk % dev->param.nChunksPerBlock);
17617 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
17618 +
17619 + if (!obj->fake &&
17620 + (!chunkIdOk || chunkShouldNotBeDeleted)) {
17621 + T(YAFFS_TRACE_VERIFY,
17622 + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
17623 + obj->objectId, obj->hdrChunk,
17624 + chunkIdOk ? "" : ",out of range",
17625 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
17626 + }
17627 +
17628 + if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
17629 + yaffs_ExtendedTags tags;
17630 + yaffs_ObjectHeader *oh;
17631 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
17632 +
17633 + oh = (yaffs_ObjectHeader *)buffer;
17634 +
17635 + yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
17636 + &tags);
17637 +
17638 + yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
17639 +
17640 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
17641 + }
17642 +
17643 + /* Verify it has a parent */
17644 + if (obj && !obj->fake &&
17645 + (!obj->parent || obj->parent->myDev != dev)) {
17646 + T(YAFFS_TRACE_VERIFY,
17647 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
17648 + obj->objectId, obj->parent));
17649 + }
17650 +
17651 + /* Verify parent is a directory */
17652 + if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17653 + T(YAFFS_TRACE_VERIFY,
17654 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
17655 + obj->objectId, obj->parent->variantType));
17656 + }
17657 +
17658 + switch (obj->variantType) {
17659 + case YAFFS_OBJECT_TYPE_FILE:
17660 + yaffs_VerifyFile(obj);
17661 + break;
17662 + case YAFFS_OBJECT_TYPE_SYMLINK:
17663 + yaffs_VerifySymlink(obj);
17664 + break;
17665 + case YAFFS_OBJECT_TYPE_DIRECTORY:
17666 + yaffs_VerifyDirectory(obj);
17667 + break;
17668 + case YAFFS_OBJECT_TYPE_HARDLINK:
17669 + yaffs_VerifyHardLink(obj);
17670 + break;
17671 + case YAFFS_OBJECT_TYPE_SPECIAL:
17672 + yaffs_VerifySpecial(obj);
17673 + break;
17674 + case YAFFS_OBJECT_TYPE_UNKNOWN:
17675 + default:
17676 + T(YAFFS_TRACE_VERIFY,
17677 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
17678 + obj->objectId, obj->variantType));
17679 + break;
17680 + }
17681 +}
17682 +
17683 +void yaffs_VerifyObjects(yaffs_Device *dev)
17684 +{
17685 + yaffs_Object *obj;
17686 + int i;
17687 + struct ylist_head *lh;
17688 +
17689 + if (yaffs_SkipVerification(dev))
17690 + return;
17691 +
17692 + /* Iterate through the objects in each hash entry */
17693 +
17694 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
17695 + ylist_for_each(lh, &dev->objectBucket[i].list) {
17696 + if (lh) {
17697 + obj = ylist_entry(lh, yaffs_Object, hashLink);
17698 + yaffs_VerifyObject(obj);
17699 + }
17700 + }
17701 + }
17702 +}
17703 +
17704 +
17705 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
17706 +{
17707 + struct ylist_head *lh;
17708 + yaffs_Object *listObj;
17709 +
17710 + int count = 0;
17711 +
17712 + if (!obj) {
17713 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
17714 + YBUG();
17715 + return;
17716 + }
17717 +
17718 + if (yaffs_SkipVerification(obj->myDev))
17719 + return;
17720 +
17721 + if (!obj->parent) {
17722 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
17723 + YBUG();
17724 + return;
17725 + }
17726 +
17727 + if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17728 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
17729 + YBUG();
17730 + }
17731 +
17732 + /* Iterate through the objects in each hash entry */
17733 +
17734 + ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
17735 + if (lh) {
17736 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17737 + yaffs_VerifyObject(listObj);
17738 + if (obj == listObj)
17739 + count++;
17740 + }
17741 + }
17742 +
17743 + if (count != 1) {
17744 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
17745 + YBUG();
17746 + }
17747 +}
17748 +
17749 +void yaffs_VerifyDirectory(yaffs_Object *directory)
17750 +{
17751 + struct ylist_head *lh;
17752 + yaffs_Object *listObj;
17753 +
17754 + if (!directory) {
17755 + YBUG();
17756 + return;
17757 + }
17758 +
17759 + if (yaffs_SkipFullVerification(directory->myDev))
17760 + return;
17761 +
17762 + if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17763 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
17764 + YBUG();
17765 + }
17766 +
17767 + /* Iterate through the objects in each hash entry */
17768 +
17769 + ylist_for_each(lh, &directory->variant.directoryVariant.children) {
17770 + if (lh) {
17771 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17772 + if (listObj->parent != directory) {
17773 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
17774 + YBUG();
17775 + }
17776 + yaffs_VerifyObjectInDirectory(listObj);
17777 + }
17778 + }
17779 +}
17780 +
17781 +static int yaffs_freeVerificationFailures;
17782 +
17783 +void yaffs_VerifyFreeChunks(yaffs_Device *dev)
17784 +{
17785 + int counted;
17786 + int difference;
17787 +
17788 + if (yaffs_SkipVerification(dev))
17789 + return;
17790 +
17791 + counted = yaffs_CountFreeChunks(dev);
17792 +
17793 + difference = dev->nFreeChunks - counted;
17794 +
17795 + if (difference) {
17796 + T(YAFFS_TRACE_ALWAYS,
17797 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
17798 + dev->nFreeChunks, counted, difference));
17799 + yaffs_freeVerificationFailures++;
17800 + }
17801 +}
17802 +
17803 +int yaffs_VerifyFileSanity(yaffs_Object *in)
17804 +{
17805 +#if 0
17806 + int chunk;
17807 + int nChunks;
17808 + int fSize;
17809 + int failed = 0;
17810 + int objId;
17811 + yaffs_Tnode *tn;
17812 + yaffs_Tags localTags;
17813 + yaffs_Tags *tags = &localTags;
17814 + int theChunk;
17815 + int chunkDeleted;
17816 +
17817 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
17818 + return YAFFS_FAIL;
17819 +
17820 + objId = in->objectId;
17821 + fSize = in->variant.fileVariant.fileSize;
17822 + nChunks =
17823 + (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
17824 +
17825 + for (chunk = 1; chunk <= nChunks; chunk++) {
17826 + tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
17827 + chunk);
17828 +
17829 + if (tn) {
17830 +
17831 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
17832 +
17833 + if (yaffs_CheckChunkBits
17834 + (dev, theChunk / dev->param.nChunksPerBlock,
17835 + theChunk % dev->param.nChunksPerBlock)) {
17836 +
17837 + yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
17838 + tags,
17839 + &chunkDeleted);
17840 + if (yaffs_TagsMatch
17841 + (tags, in->objectId, chunk, chunkDeleted)) {
17842 + /* found it; */
17843 +
17844 + }
17845 + } else {
17846 +
17847 + failed = 1;
17848 + }
17849 +
17850 + } else {
17851 + /* T(("No level 0 found for %d\n", chunk)); */
17852 + }
17853 + }
17854 +
17855 + return failed ? YAFFS_FAIL : YAFFS_OK;
17856 +#else
17857 + in=in;
17858 + return YAFFS_OK;
17859 +#endif
17860 +}
17861 --- /dev/null
17862 +++ b/fs/yaffs2/yaffs_verify.h
17863 @@ -0,0 +1,39 @@
17864 +/*
17865 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17866 + *
17867 + * Copyright (C) 2002-2010 Aleph One Ltd.
17868 + * for Toby Churchill Ltd and Brightstar Engineering
17869 + *
17870 + * Created by Charles Manning <charles@aleph1.co.uk>
17871 + *
17872 + * This program is free software; you can redistribute it and/or modify
17873 + * it under the terms of the GNU General Public License version 2 as
17874 + * published by the Free Software Foundation.
17875 + */
17876 +
17877 +#ifndef __YAFFS_VERIFY_H__
17878 +#define __YAFFS_VERIFY_H__
17879 +
17880 +#include "yaffs_guts.h"
17881 +
17882 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17883 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17884 +void yaffs_VerifyBlocks(yaffs_Device *dev);
17885 +
17886 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck);
17887 +void yaffs_VerifyFile(yaffs_Object *obj);
17888 +void yaffs_VerifyHardLink(yaffs_Object *obj);
17889 +void yaffs_VerifySymlink(yaffs_Object *obj);
17890 +void yaffs_VerifySpecial(yaffs_Object *obj);
17891 +void yaffs_VerifyObject(yaffs_Object *obj);
17892 +void yaffs_VerifyObjects(yaffs_Device *dev);
17893 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj);
17894 +void yaffs_VerifyDirectory(yaffs_Object *directory);
17895 +void yaffs_VerifyFreeChunks(yaffs_Device *dev);
17896 +
17897 +int yaffs_VerifyFileSanity(yaffs_Object *obj);
17898 +
17899 +int yaffs_SkipVerification(yaffs_Device *dev);
17900 +
17901 +#endif
17902 +
17903 --- /dev/null
17904 +++ b/fs/yaffs2/yaffs_vfs_glue.c
17905 @@ -0,0 +1,3577 @@
17906 +/*
17907 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17908 + *
17909 + * Copyright (C) 2002-2010 Aleph One Ltd.
17910 + * for Toby Churchill Ltd and Brightstar Engineering
17911 + *
17912 + * Created by Charles Manning <charles@aleph1.co.uk>
17913 + * Acknowledgements:
17914 + * Luc van OostenRyck for numerous patches.
17915 + * Nick Bane for numerous patches.
17916 + * Nick Bane for 2.5/2.6 integration.
17917 + * Andras Toth for mknod rdev issue.
17918 + * Michael Fischer for finding the problem with inode inconsistency.
17919 + * Some code bodily lifted from JFFS
17920 + *
17921 + * This program is free software; you can redistribute it and/or modify
17922 + * it under the terms of the GNU General Public License version 2 as
17923 + * published by the Free Software Foundation.
17924 + */
17925 +
17926 +/*
17927 + *
17928 + * This is the file system front-end to YAFFS that hooks it up to
17929 + * the VFS.
17930 + *
17931 + * Special notes:
17932 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
17933 + * this superblock
17934 + * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
17935 + * superblock
17936 + * >> inode->u.generic_ip points to the associated yaffs_Object.
17937 + */
17938 +
17939 +/*
17940 + * There are two variants of the VFS glue code. This variant should compile
17941 + * for any version of Linux.
17942 + */
17943 +#include <linux/version.h>
17944 +
17945 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
17946 +#define YAFFS_COMPILE_BACKGROUND
17947 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
17948 +#define YAFFS_COMPILE_FREEZER
17949 +#endif
17950 +#endif
17951 +
17952 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
17953 +#define YAFFS_COMPILE_EXPORTFS
17954 +#endif
17955 +
17956 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
17957 +#define YAFFS_USE_SETATTR_COPY
17958 +#define YAFFS_USE_TRUNCATE_SETSIZE
17959 +#endif
17960 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
17961 +#define YAFFS_HAS_EVICT_INODE
17962 +#endif
17963 +
17964 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
17965 +#define YAFFS_NEW_FOLLOW_LINK 1
17966 +#else
17967 +#define YAFFS_NEW_FOLLOW_LINK 0
17968 +#endif
17969 +
17970 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
17971 +#include <linux/config.h>
17972 +#endif
17973 +
17974 +#include <linux/kernel.h>
17975 +#include <linux/module.h>
17976 +#include <linux/slab.h>
17977 +#include <linux/init.h>
17978 +#include <linux/fs.h>
17979 +#include <linux/proc_fs.h>
17980 +#include <linux/smp_lock.h>
17981 +#include <linux/pagemap.h>
17982 +#include <linux/mtd/mtd.h>
17983 +#include <linux/interrupt.h>
17984 +#include <linux/string.h>
17985 +#include <linux/ctype.h>
17986 +
17987 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
17988 +#include <linux/namei.h>
17989 +#endif
17990 +
17991 +#ifdef YAFFS_COMPILE_EXPORTFS
17992 +#include <linux/exportfs.h>
17993 +#endif
17994 +
17995 +#ifdef YAFFS_COMPILE_BACKGROUND
17996 +#include <linux/kthread.h>
17997 +#include <linux/delay.h>
17998 +#endif
17999 +#ifdef YAFFS_COMPILE_FREEZER
18000 +#include <linux/freezer.h>
18001 +#endif
18002 +
18003 +#include <asm/div64.h>
18004 +
18005 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18006 +
18007 +#include <linux/statfs.h>
18008 +
18009 +#define UnlockPage(p) unlock_page(p)
18010 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
18011 +
18012 +/* FIXME: use sb->s_id instead ? */
18013 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
18014 +
18015 +#else
18016 +
18017 +#include <linux/locks.h>
18018 +#define BDEVNAME_SIZE 0
18019 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
18020 +
18021 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
18022 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
18023 +#define __user
18024 +#endif
18025 +
18026 +#endif
18027 +
18028 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
18029 +#define YPROC_ROOT (&proc_root)
18030 +#else
18031 +#define YPROC_ROOT NULL
18032 +#endif
18033 +
18034 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
18035 +#define Y_INIT_TIMER(a) init_timer(a)
18036 +#else
18037 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
18038 +#endif
18039 +
18040 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18041 +#define WRITE_SIZE_STR "writesize"
18042 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
18043 +#else
18044 +#define WRITE_SIZE_STR "oobblock"
18045 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
18046 +#endif
18047 +
18048 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
18049 +#define YAFFS_USE_WRITE_BEGIN_END 1
18050 +#else
18051 +#define YAFFS_USE_WRITE_BEGIN_END 0
18052 +#endif
18053 +
18054 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
18055 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
18056 +{
18057 + uint64_t result = partition_size;
18058 + do_div(result, block_size);
18059 + return (uint32_t)result;
18060 +}
18061 +#else
18062 +#define YCALCBLOCKS(s, b) ((s)/(b))
18063 +#endif
18064 +
18065 +#include <linux/uaccess.h>
18066 +#include <linux/mtd/mtd.h>
18067 +
18068 +#include "yportenv.h"
18069 +#include "yaffs_trace.h"
18070 +#include "yaffs_guts.h"
18071 +
18072 +#include "yaffs_linux.h"
18073 +
18074 +#include "yaffs_mtdif.h"
18075 +#include "yaffs_mtdif1.h"
18076 +#include "yaffs_mtdif2.h"
18077 +
18078 +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
18079 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
18080 +unsigned int yaffs_auto_checkpoint = 1;
18081 +unsigned int yaffs_gc_control = 1;
18082 +unsigned int yaffs_bg_enable = 1;
18083 +
18084 +/* Module Parameters */
18085 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18086 +module_param(yaffs_traceMask, uint, 0644);
18087 +module_param(yaffs_wr_attempts, uint, 0644);
18088 +module_param(yaffs_auto_checkpoint, uint, 0644);
18089 +module_param(yaffs_gc_control, uint, 0644);
18090 +module_param(yaffs_bg_enable, uint, 0644);
18091 +#else
18092 +MODULE_PARM(yaffs_traceMask, "i");
18093 +MODULE_PARM(yaffs_wr_attempts, "i");
18094 +MODULE_PARM(yaffs_auto_checkpoint, "i");
18095 +MODULE_PARM(yaffs_gc_control, "i");
18096 +#endif
18097 +
18098 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
18099 +/* use iget and read_inode */
18100 +#define Y_IGET(sb, inum) iget((sb), (inum))
18101 +static void yaffs_read_inode(struct inode *inode);
18102 +
18103 +#else
18104 +/* Call local equivalent */
18105 +#define YAFFS_USE_OWN_IGET
18106 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
18107 +
18108 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
18109 +#endif
18110 +
18111 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18112 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
18113 +#else
18114 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
18115 +#endif
18116 +
18117 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
18118 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
18119 +
18120 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18121 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
18122 +#else
18123 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
18124 +#endif
18125 +
18126 +
18127 +#define update_dir_time(dir) do {\
18128 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
18129 + } while(0)
18130 +
18131 +static void yaffs_put_super(struct super_block *sb);
18132 +
18133 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
18134 + loff_t *pos);
18135 +static ssize_t yaffs_hold_space(struct file *f);
18136 +static void yaffs_release_space(struct file *f);
18137 +
18138 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18139 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
18140 +#else
18141 +static int yaffs_file_flush(struct file *file);
18142 +#endif
18143 +
18144 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
18145 +static int yaffs_sync_object(struct file *file, int datasync);
18146 +#else
18147 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
18148 + int datasync);
18149 +#endif
18150 +
18151 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
18152 +
18153 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18154 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
18155 + struct nameidata *n);
18156 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18157 + struct nameidata *n);
18158 +#else
18159 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
18160 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
18161 +#endif
18162 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
18163 + struct dentry *dentry);
18164 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
18165 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
18166 + const char *symname);
18167 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
18168 +
18169 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18170 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18171 + dev_t dev);
18172 +#else
18173 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18174 + int dev);
18175 +#endif
18176 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
18177 + struct inode *new_dir, struct dentry *new_dentry);
18178 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
18179 +
18180 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18181 +static int yaffs_sync_fs(struct super_block *sb, int wait);
18182 +static void yaffs_write_super(struct super_block *sb);
18183 +#else
18184 +static int yaffs_sync_fs(struct super_block *sb);
18185 +static int yaffs_write_super(struct super_block *sb);
18186 +#endif
18187 +
18188 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18189 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
18190 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18191 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
18192 +#else
18193 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
18194 +#endif
18195 +
18196 +#ifdef YAFFS_HAS_PUT_INODE
18197 +static void yaffs_put_inode(struct inode *inode);
18198 +#endif
18199 +
18200 +#ifdef YAFFS_HAS_EVICT_INODE
18201 +static void yaffs_evict_inode(struct inode *);
18202 +#else
18203 +static void yaffs_delete_inode(struct inode *);
18204 +static void yaffs_clear_inode(struct inode *);
18205 +#endif
18206 +
18207 +static int yaffs_readpage(struct file *file, struct page *page);
18208 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18209 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
18210 +#else
18211 +static int yaffs_writepage(struct page *page);
18212 +#endif
18213 +
18214 +#ifdef CONFIG_YAFFS_XATTR
18215 +int yaffs_setxattr(struct dentry *dentry, const char *name,
18216 + const void *value, size_t size, int flags);
18217 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
18218 + size_t size);
18219 +int yaffs_removexattr(struct dentry *dentry, const char *name);
18220 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
18221 +#endif
18222 +
18223 +
18224 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
18225 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
18226 + loff_t pos, unsigned len, unsigned flags,
18227 + struct page **pagep, void **fsdata);
18228 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
18229 + loff_t pos, unsigned len, unsigned copied,
18230 + struct page *pg, void *fsdadata);
18231 +#else
18232 +static int yaffs_prepare_write(struct file *f, struct page *pg,
18233 + unsigned offset, unsigned to);
18234 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
18235 + unsigned to);
18236 +
18237 +#endif
18238 +
18239 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18240 + int buflen);
18241 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18242 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
18243 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18244 +#else
18245 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18246 +#endif
18247 +
18248 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
18249 +
18250 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
18251 +
18252 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
18253 +
18254 +
18255 +static struct address_space_operations yaffs_file_address_operations = {
18256 + .readpage = yaffs_readpage,
18257 + .writepage = yaffs_writepage,
18258 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
18259 + .write_begin = yaffs_write_begin,
18260 + .write_end = yaffs_write_end,
18261 +#else
18262 + .prepare_write = yaffs_prepare_write,
18263 + .commit_write = yaffs_commit_write,
18264 +#endif
18265 +};
18266 +
18267 +
18268 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
18269 +static const struct file_operations yaffs_file_operations = {
18270 + .read = do_sync_read,
18271 + .write = do_sync_write,
18272 + .aio_read = generic_file_aio_read,
18273 + .aio_write = generic_file_aio_write,
18274 + .mmap = generic_file_mmap,
18275 + .flush = yaffs_file_flush,
18276 + .fsync = yaffs_sync_object,
18277 + .splice_read = generic_file_splice_read,
18278 + .splice_write = generic_file_splice_write,
18279 + .llseek = generic_file_llseek,
18280 +};
18281 +
18282 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18283 +
18284 +static const struct file_operations yaffs_file_operations = {
18285 + .read = do_sync_read,
18286 + .write = do_sync_write,
18287 + .aio_read = generic_file_aio_read,
18288 + .aio_write = generic_file_aio_write,
18289 + .mmap = generic_file_mmap,
18290 + .flush = yaffs_file_flush,
18291 + .fsync = yaffs_sync_object,
18292 + .sendfile = generic_file_sendfile,
18293 +};
18294 +
18295 +#else
18296 +
18297 +static const struct file_operations yaffs_file_operations = {
18298 + .read = generic_file_read,
18299 + .write = generic_file_write,
18300 + .mmap = generic_file_mmap,
18301 + .flush = yaffs_file_flush,
18302 + .fsync = yaffs_sync_object,
18303 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18304 + .sendfile = generic_file_sendfile,
18305 +#endif
18306 +};
18307 +#endif
18308 +
18309 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
18310 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
18311 +{
18312 + void * kaddr = kmap_atomic(page, KM_USER0);
18313 + memset(kaddr + start, 0, end - start);
18314 + kunmap_atomic(kaddr, KM_USER0);
18315 + flush_dcache_page(page);
18316 +}
18317 +#endif
18318 +
18319 +
18320 +static const struct inode_operations yaffs_file_inode_operations = {
18321 + .setattr = yaffs_setattr,
18322 +#ifdef CONFIG_YAFFS_XATTR
18323 + .setxattr = yaffs_setxattr,
18324 + .getxattr = yaffs_getxattr,
18325 + .listxattr = yaffs_listxattr,
18326 + .removexattr = yaffs_removexattr,
18327 +#endif
18328 +};
18329 +
18330 +static const struct inode_operations yaffs_symlink_inode_operations = {
18331 + .readlink = yaffs_readlink,
18332 + .follow_link = yaffs_follow_link,
18333 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18334 + .put_link = yaffs_put_link,
18335 +#endif
18336 + .setattr = yaffs_setattr,
18337 +#ifdef CONFIG_YAFFS_XATTR
18338 + .setxattr = yaffs_setxattr,
18339 + .getxattr = yaffs_getxattr,
18340 + .listxattr = yaffs_listxattr,
18341 + .removexattr = yaffs_removexattr,
18342 +#endif
18343 +};
18344 +
18345 +static const struct inode_operations yaffs_dir_inode_operations = {
18346 + .create = yaffs_create,
18347 + .lookup = yaffs_lookup,
18348 + .link = yaffs_link,
18349 + .unlink = yaffs_unlink,
18350 + .symlink = yaffs_symlink,
18351 + .mkdir = yaffs_mkdir,
18352 + .rmdir = yaffs_unlink,
18353 + .mknod = yaffs_mknod,
18354 + .rename = yaffs_rename,
18355 + .setattr = yaffs_setattr,
18356 +#ifdef CONFIG_YAFFS_XATTR
18357 + .setxattr = yaffs_setxattr,
18358 + .getxattr = yaffs_getxattr,
18359 + .listxattr = yaffs_listxattr,
18360 + .removexattr = yaffs_removexattr,
18361 +#endif
18362 +};
18363 +
18364 +static const struct file_operations yaffs_dir_operations = {
18365 + .read = generic_read_dir,
18366 + .readdir = yaffs_readdir,
18367 + .fsync = yaffs_sync_object,
18368 + .llseek = yaffs_dir_llseek,
18369 +};
18370 +
18371 +static const struct super_operations yaffs_super_ops = {
18372 + .statfs = yaffs_statfs,
18373 +
18374 +#ifndef YAFFS_USE_OWN_IGET
18375 + .read_inode = yaffs_read_inode,
18376 +#endif
18377 +#ifdef YAFFS_HAS_PUT_INODE
18378 + .put_inode = yaffs_put_inode,
18379 +#endif
18380 + .put_super = yaffs_put_super,
18381 +#ifdef YAFFS_HAS_EVICT_INODE
18382 + .evict_inode = yaffs_evict_inode,
18383 +#else
18384 + .delete_inode = yaffs_delete_inode,
18385 + .clear_inode = yaffs_clear_inode,
18386 +#endif
18387 + .sync_fs = yaffs_sync_fs,
18388 + .write_super = yaffs_write_super,
18389 +};
18390 +
18391 +
18392 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
18393 +{
18394 +#ifdef YAFFS_USE_SETATTR_COPY
18395 + setattr_copy(inode,attr);
18396 + return 0;
18397 +#else
18398 + return inode_setattr(inode, attr);
18399 +#endif
18400 +
18401 +}
18402 +
18403 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
18404 +{
18405 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
18406 + truncate_setsize(inode,newsize);
18407 + return 0;
18408 +#else
18409 + truncate_inode_pages(&inode->i_data,newsize);
18410 + return 0;
18411 +#endif
18412 +
18413 +}
18414 +
18415 +static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
18416 +{
18417 + return yaffs_gc_control;
18418 +}
18419 +
18420 +static void yaffs_GrossLock(yaffs_Device *dev)
18421 +{
18422 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
18423 + down(&(yaffs_DeviceToLC(dev)->grossLock));
18424 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
18425 +}
18426 +
18427 +static void yaffs_GrossUnlock(yaffs_Device *dev)
18428 +{
18429 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
18430 + up(&(yaffs_DeviceToLC(dev)->grossLock));
18431 +}
18432 +
18433 +#ifdef YAFFS_COMPILE_EXPORTFS
18434 +
18435 +static struct inode *
18436 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
18437 +{
18438 + return Y_IGET(sb, ino);
18439 +}
18440 +
18441 +static struct dentry *
18442 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18443 +{
18444 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
18445 +}
18446 +
18447 +static struct dentry *
18448 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18449 +{
18450 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
18451 +}
18452 +
18453 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
18454 +{
18455 +
18456 + struct super_block *sb = dentry->d_inode->i_sb;
18457 + struct dentry *parent = ERR_PTR(-ENOENT);
18458 + struct inode *inode;
18459 + unsigned long parent_ino;
18460 + yaffs_Object *d_obj;
18461 + yaffs_Object *parent_obj;
18462 +
18463 + d_obj = yaffs_InodeToObject(dentry->d_inode);
18464 +
18465 + if (d_obj) {
18466 + parent_obj = d_obj->parent;
18467 + if (parent_obj) {
18468 + parent_ino = yaffs_GetObjectInode(parent_obj);
18469 + inode = Y_IGET(sb, parent_ino);
18470 +
18471 + if (IS_ERR(inode)) {
18472 + parent = ERR_CAST(inode);
18473 + } else {
18474 + parent = d_obtain_alias(inode);
18475 + if (!IS_ERR(parent)) {
18476 + parent = ERR_PTR(-ENOMEM);
18477 + iput(inode);
18478 + }
18479 + }
18480 + }
18481 + }
18482 +
18483 + return parent;
18484 +}
18485 +
18486 +/* Just declare a zero structure as a NULL value implies
18487 + * using the default functions of exportfs.
18488 + */
18489 +
18490 +static struct export_operations yaffs_export_ops =
18491 +{
18492 + .fh_to_dentry = yaffs2_fh_to_dentry,
18493 + .fh_to_parent = yaffs2_fh_to_parent,
18494 + .get_parent = yaffs2_get_parent,
18495 +} ;
18496 +
18497 +#endif
18498 +
18499 +/*-----------------------------------------------------------------*/
18500 +/* Directory search context allows us to unlock access to yaffs during
18501 + * filldir without causing problems with the directory being modified.
18502 + * This is similar to the tried and tested mechanism used in yaffs direct.
18503 + *
18504 + * A search context iterates along a doubly linked list of siblings in the
18505 + * directory. If the iterating object is deleted then this would corrupt
18506 + * the list iteration, likely causing a crash. The search context avoids
18507 + * this by using the removeObjectCallback to move the search context to the
18508 + * next object before the object is deleted.
18509 + *
18510 + * Many readdirs (and thus seach conexts) may be alive simulateously so
18511 + * each yaffs_Device has a list of these.
18512 + *
18513 + * A seach context lives for the duration of a readdir.
18514 + *
18515 + * All these functions must be called while yaffs is locked.
18516 + */
18517 +
18518 +struct yaffs_SearchContext {
18519 + yaffs_Device *dev;
18520 + yaffs_Object *dirObj;
18521 + yaffs_Object *nextReturn;
18522 + struct ylist_head others;
18523 +};
18524 +
18525 +/*
18526 + * yaffs_NewSearch() creates a new search context, initialises it and
18527 + * adds it to the device's search context list.
18528 + *
18529 + * Called at start of readdir.
18530 + */
18531 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
18532 +{
18533 + yaffs_Device *dev = dir->myDev;
18534 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
18535 + if(sc){
18536 + sc->dirObj = dir;
18537 + sc->dev = dev;
18538 + if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18539 + sc->nextReturn = NULL;
18540 + else
18541 + sc->nextReturn = ylist_entry(
18542 + dir->variant.directoryVariant.children.next,
18543 + yaffs_Object,siblings);
18544 + YINIT_LIST_HEAD(&sc->others);
18545 + ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
18546 + }
18547 + return sc;
18548 +}
18549 +
18550 +/*
18551 + * yaffs_EndSearch() disposes of a search context and cleans up.
18552 + */
18553 +static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
18554 +{
18555 + if(sc){
18556 + ylist_del(&sc->others);
18557 + YFREE(sc);
18558 + }
18559 +}
18560 +
18561 +/*
18562 + * yaffs_SearchAdvance() moves a search context to the next object.
18563 + * Called when the search iterates or when an object removal causes
18564 + * the search context to be moved to the next object.
18565 + */
18566 +static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
18567 +{
18568 + if(!sc)
18569 + return;
18570 +
18571 + if( sc->nextReturn == NULL ||
18572 + ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18573 + sc->nextReturn = NULL;
18574 + else {
18575 + struct ylist_head *next = sc->nextReturn->siblings.next;
18576 +
18577 + if( next == &sc->dirObj->variant.directoryVariant.children)
18578 + sc->nextReturn = NULL; /* end of list */
18579 + else
18580 + sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
18581 + }
18582 +}
18583 +
18584 +/*
18585 + * yaffs_RemoveObjectCallback() is called when an object is unlinked.
18586 + * We check open search contexts and advance any which are currently
18587 + * on the object being iterated.
18588 + */
18589 +static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
18590 +{
18591 +
18592 + struct ylist_head *i;
18593 + struct yaffs_SearchContext *sc;
18594 + struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
18595 +
18596 +
18597 + /* Iterate through the directory search contexts.
18598 + * If any are currently on the object being removed, then advance
18599 + * the search context to the next object to prevent a hanging pointer.
18600 + */
18601 + ylist_for_each(i, search_contexts) {
18602 + if (i) {
18603 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
18604 + if(sc->nextReturn == obj)
18605 + yaffs_SearchAdvance(sc);
18606 + }
18607 + }
18608 +
18609 +}
18610 +
18611 +
18612 +/*-----------------------------------------------------------------*/
18613 +
18614 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18615 + int buflen)
18616 +{
18617 + unsigned char *alias;
18618 + int ret;
18619 +
18620 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18621 +
18622 + yaffs_GrossLock(dev);
18623 +
18624 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18625 +
18626 + yaffs_GrossUnlock(dev);
18627 +
18628 + if (!alias)
18629 + return -ENOMEM;
18630 +
18631 + ret = vfs_readlink(dentry, buffer, buflen, alias);
18632 + kfree(alias);
18633 + return ret;
18634 +}
18635 +
18636 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18637 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18638 +#else
18639 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18640 +#endif
18641 +{
18642 + unsigned char *alias;
18643 + int ret;
18644 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18645 +
18646 + yaffs_GrossLock(dev);
18647 +
18648 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18649 + yaffs_GrossUnlock(dev);
18650 +
18651 + if (!alias) {
18652 + ret = -ENOMEM;
18653 + goto out;
18654 + }
18655 +
18656 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18657 + nd_set_link(nd, alias);
18658 + ret = (int)alias;
18659 +out:
18660 + return ERR_PTR(ret);
18661 +#else
18662 + ret = vfs_follow_link(nd, alias);
18663 + kfree(alias);
18664 +out:
18665 + return ret;
18666 +#endif
18667 +}
18668 +
18669 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18670 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
18671 + kfree(alias);
18672 +}
18673 +#endif
18674 +
18675 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
18676 + yaffs_Object *obj);
18677 +
18678 +/*
18679 + * Lookup is used to find objects in the fs
18680 + */
18681 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18682 +
18683 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18684 + struct nameidata *n)
18685 +#else
18686 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
18687 +#endif
18688 +{
18689 + yaffs_Object *obj;
18690 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
18691 +
18692 + yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
18693 +
18694 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18695 + yaffs_GrossLock(dev);
18696 +
18697 + T(YAFFS_TRACE_OS,
18698 + (TSTR("yaffs_lookup for %d:%s\n"),
18699 + yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
18700 +
18701 + obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
18702 + dentry->d_name.name);
18703 +
18704 + obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
18705 +
18706 + /* Can't hold gross lock when calling yaffs_get_inode() */
18707 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18708 + yaffs_GrossUnlock(dev);
18709 +
18710 + if (obj) {
18711 + T(YAFFS_TRACE_OS,
18712 + (TSTR("yaffs_lookup found %d\n"), obj->objectId));
18713 +
18714 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
18715 +
18716 + if (inode) {
18717 + T(YAFFS_TRACE_OS,
18718 + (TSTR("yaffs_loookup dentry \n")));
18719 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
18720 + * d_add even if NULL inode */
18721 +#if 0
18722 + /*dget(dentry); // try to solve directory bug */
18723 + d_add(dentry, inode);
18724 +
18725 + /* return dentry; */
18726 + return NULL;
18727 +#endif
18728 + }
18729 +
18730 + } else {
18731 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
18732 +
18733 + }
18734 +
18735 +/* added NCB for 2.5/6 compatability - forces add even if inode is
18736 + * NULL which creates dentry hash */
18737 + d_add(dentry, inode);
18738 +
18739 + return NULL;
18740 +}
18741 +
18742 +
18743 +#ifdef YAFFS_HAS_PUT_INODE
18744 +
18745 +/* For now put inode is just for debugging
18746 + * Put inode is called when the inode **structure** is put.
18747 + */
18748 +static void yaffs_put_inode(struct inode *inode)
18749 +{
18750 + T(YAFFS_TRACE_OS,
18751 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
18752 + atomic_read(&inode->i_count)));
18753 +
18754 +}
18755 +#endif
18756 +
18757 +
18758 +static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj)
18759 +{
18760 + /* Clear the association between the inode and
18761 + * the yaffs_Object.
18762 + */
18763 + obj->myInode = NULL;
18764 + yaffs_InodeToObjectLV(inode) = NULL;
18765 +
18766 + /* If the object freeing was deferred, then the real
18767 + * free happens now.
18768 + * This should fix the inode inconsistency problem.
18769 + */
18770 + yaffs_HandleDeferedFree(obj);
18771 +}
18772 +
18773 +#ifdef YAFFS_HAS_EVICT_INODE
18774 +/* yaffs_evict_inode combines into one operation what was previously done in
18775 + * yaffs_clear_inode() and yaffs_delete_inode()
18776 + *
18777 + */
18778 +static void yaffs_evict_inode( struct inode *inode)
18779 +{
18780 + yaffs_Object *obj;
18781 + yaffs_Device *dev;
18782 + int deleteme = 0;
18783 +
18784 + obj = yaffs_InodeToObject(inode);
18785 +
18786 + T(YAFFS_TRACE_OS,
18787 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18788 + atomic_read(&inode->i_count),
18789 + obj ? "object exists" : "null object"));
18790 +
18791 + if (!inode->i_nlink && !is_bad_inode(inode))
18792 + deleteme = 1;
18793 + truncate_inode_pages(&inode->i_data,0);
18794 + end_writeback(inode);
18795 +
18796 + if(deleteme && obj){
18797 + dev = obj->myDev;
18798 + yaffs_GrossLock(dev);
18799 + yaffs_DeleteObject(obj);
18800 + yaffs_GrossUnlock(dev);
18801 + }
18802 + if (obj) {
18803 + dev = obj->myDev;
18804 + yaffs_GrossLock(dev);
18805 + yaffs_UnstitchObject(inode,obj);
18806 + yaffs_GrossUnlock(dev);
18807 + }
18808 +
18809 +
18810 +}
18811 +#else
18812 +
18813 +/* clear is called to tell the fs to release any per-inode data it holds.
18814 + * The object might still exist on disk and is just being thrown out of the cache
18815 + * or else the object has actually been deleted and we're being called via
18816 + * the chain
18817 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
18818 + */
18819 +
18820 +static void yaffs_clear_inode(struct inode *inode)
18821 +{
18822 + yaffs_Object *obj;
18823 + yaffs_Device *dev;
18824 +
18825 + obj = yaffs_InodeToObject(inode);
18826 +
18827 + T(YAFFS_TRACE_OS,
18828 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18829 + atomic_read(&inode->i_count),
18830 + obj ? "object exists" : "null object"));
18831 +
18832 + if (obj) {
18833 + dev = obj->myDev;
18834 + yaffs_GrossLock(dev);
18835 + yaffs_UnstitchObject(inode,obj);
18836 + yaffs_GrossUnlock(dev);
18837 + }
18838 +
18839 +}
18840 +
18841 +/* delete is called when the link count is zero and the inode
18842 + * is put (ie. nobody wants to know about it anymore, time to
18843 + * delete the file).
18844 + * NB Must call clear_inode()
18845 + */
18846 +static void yaffs_delete_inode(struct inode *inode)
18847 +{
18848 + yaffs_Object *obj = yaffs_InodeToObject(inode);
18849 + yaffs_Device *dev;
18850 +
18851 + T(YAFFS_TRACE_OS,
18852 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18853 + atomic_read(&inode->i_count),
18854 + obj ? "object exists" : "null object"));
18855 +
18856 + if (obj) {
18857 + dev = obj->myDev;
18858 + yaffs_GrossLock(dev);
18859 + yaffs_DeleteObject(obj);
18860 + yaffs_GrossUnlock(dev);
18861 + }
18862 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
18863 + truncate_inode_pages(&inode->i_data, 0);
18864 +#endif
18865 + clear_inode(inode);
18866 +}
18867 +#endif
18868 +
18869 +
18870 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18871 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
18872 +#else
18873 +static int yaffs_file_flush(struct file *file)
18874 +#endif
18875 +{
18876 + yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
18877 +
18878 + yaffs_Device *dev = obj->myDev;
18879 +
18880 + T(YAFFS_TRACE_OS,
18881 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId,
18882 + obj->dirty ? "dirty" : "clean"));
18883 +
18884 + yaffs_GrossLock(dev);
18885 +
18886 + yaffs_FlushFile(obj, 1, 0);
18887 +
18888 + yaffs_GrossUnlock(dev);
18889 +
18890 + return 0;
18891 +}
18892 +
18893 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
18894 +{
18895 + /* Lifted from jffs2 */
18896 +
18897 + yaffs_Object *obj;
18898 + unsigned char *pg_buf;
18899 + int ret;
18900 +
18901 + yaffs_Device *dev;
18902 +
18903 + T(YAFFS_TRACE_OS,
18904 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
18905 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
18906 + (unsigned)PAGE_CACHE_SIZE));
18907 +
18908 + obj = yaffs_DentryToObject(f->f_dentry);
18909 +
18910 + dev = obj->myDev;
18911 +
18912 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18913 + BUG_ON(!PageLocked(pg));
18914 +#else
18915 + if (!PageLocked(pg))
18916 + PAGE_BUG(pg);
18917 +#endif
18918 +
18919 + pg_buf = kmap(pg);
18920 + /* FIXME: Can kmap fail? */
18921 +
18922 + yaffs_GrossLock(dev);
18923 +
18924 + ret = yaffs_ReadDataFromFile(obj, pg_buf,
18925 + pg->index << PAGE_CACHE_SHIFT,
18926 + PAGE_CACHE_SIZE);
18927 +
18928 + yaffs_GrossUnlock(dev);
18929 +
18930 + if (ret >= 0)
18931 + ret = 0;
18932 +
18933 + if (ret) {
18934 + ClearPageUptodate(pg);
18935 + SetPageError(pg);
18936 + } else {
18937 + SetPageUptodate(pg);
18938 + ClearPageError(pg);
18939 + }
18940 +
18941 + flush_dcache_page(pg);
18942 + kunmap(pg);
18943 +
18944 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
18945 + return ret;
18946 +}
18947 +
18948 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
18949 +{
18950 + int ret = yaffs_readpage_nolock(f, pg);
18951 + UnlockPage(pg);
18952 + return ret;
18953 +}
18954 +
18955 +static int yaffs_readpage(struct file *f, struct page *pg)
18956 +{
18957 + int ret;
18958 +
18959 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
18960 + ret=yaffs_readpage_unlock(f, pg);
18961 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
18962 + return ret;
18963 +}
18964 +
18965 +/* writepage inspired by/stolen from smbfs */
18966 +
18967 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18968 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
18969 +#else
18970 +static int yaffs_writepage(struct page *page)
18971 +#endif
18972 +{
18973 + yaffs_Device *dev;
18974 + struct address_space *mapping = page->mapping;
18975 + struct inode *inode;
18976 + unsigned long end_index;
18977 + char *buffer;
18978 + yaffs_Object *obj;
18979 + int nWritten = 0;
18980 + unsigned nBytes;
18981 + loff_t i_size;
18982 +
18983 + if (!mapping)
18984 + BUG();
18985 + inode = mapping->host;
18986 + if (!inode)
18987 + BUG();
18988 + i_size = i_size_read(inode);
18989 +
18990 + end_index = i_size >> PAGE_CACHE_SHIFT;
18991 +
18992 + if(page->index < end_index)
18993 + nBytes = PAGE_CACHE_SIZE;
18994 + else {
18995 + nBytes = i_size & (PAGE_CACHE_SIZE -1);
18996 +
18997 + if (page->index > end_index || !nBytes) {
18998 + T(YAFFS_TRACE_OS,
18999 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
19000 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
19001 + (unsigned)inode->i_size));
19002 + T(YAFFS_TRACE_OS,
19003 + (TSTR(" -> don't care!!\n")));
19004 +
19005 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
19006 + set_page_writeback(page);
19007 + unlock_page(page);
19008 + end_page_writeback(page);
19009 + return 0;
19010 + }
19011 + }
19012 +
19013 + if(nBytes != PAGE_CACHE_SIZE)
19014 + zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
19015 +
19016 + get_page(page);
19017 +
19018 + buffer = kmap(page);
19019 +
19020 + obj = yaffs_InodeToObject(inode);
19021 + dev = obj->myDev;
19022 + yaffs_GrossLock(dev);
19023 +
19024 + T(YAFFS_TRACE_OS,
19025 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
19026 + (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
19027 + T(YAFFS_TRACE_OS,
19028 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
19029 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19030 +
19031 + nWritten = yaffs_WriteDataToFile(obj, buffer,
19032 + page->index << PAGE_CACHE_SHIFT, nBytes, 0);
19033 +
19034 + yaffs_MarkSuperBlockDirty(dev);
19035 +
19036 + T(YAFFS_TRACE_OS,
19037 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
19038 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19039 +
19040 + yaffs_GrossUnlock(dev);
19041 +
19042 + kunmap(page);
19043 + set_page_writeback(page);
19044 + unlock_page(page);
19045 + end_page_writeback(page);
19046 + put_page(page);
19047 +
19048 + return (nWritten == nBytes) ? 0 : -ENOSPC;
19049 +}
19050 +
19051 +
19052 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19053 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
19054 + loff_t pos, unsigned len, unsigned flags,
19055 + struct page **pagep, void **fsdata)
19056 +{
19057 + struct page *pg = NULL;
19058 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
19059 +
19060 + int ret = 0;
19061 + int space_held = 0;
19062 +
19063 + /* Get a page */
19064 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
19065 + pg = grab_cache_page_write_begin(mapping, index, flags);
19066 +#else
19067 + pg = __grab_cache_page(mapping, index);
19068 +#endif
19069 +
19070 + *pagep = pg;
19071 + if (!pg) {
19072 + ret = -ENOMEM;
19073 + goto out;
19074 + }
19075 + T(YAFFS_TRACE_OS,
19076 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
19077 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
19078 +
19079 + /* Get fs space */
19080 + space_held = yaffs_hold_space(filp);
19081 +
19082 + if (!space_held) {
19083 + ret = -ENOSPC;
19084 + goto out;
19085 + }
19086 +
19087 + /* Update page if required */
19088 +
19089 + if (!Page_Uptodate(pg))
19090 + ret = yaffs_readpage_nolock(filp, pg);
19091 +
19092 + if (ret)
19093 + goto out;
19094 +
19095 + /* Happy path return */
19096 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
19097 +
19098 + return 0;
19099 +
19100 +out:
19101 + T(YAFFS_TRACE_OS,
19102 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
19103 + if (space_held)
19104 + yaffs_release_space(filp);
19105 + if (pg) {
19106 + unlock_page(pg);
19107 + page_cache_release(pg);
19108 + }
19109 + return ret;
19110 +}
19111 +
19112 +#else
19113 +
19114 +static int yaffs_prepare_write(struct file *f, struct page *pg,
19115 + unsigned offset, unsigned to)
19116 +{
19117 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
19118 +
19119 + if (!Page_Uptodate(pg))
19120 + return yaffs_readpage_nolock(f, pg);
19121 + return 0;
19122 +}
19123 +#endif
19124 +
19125 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19126 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
19127 + loff_t pos, unsigned len, unsigned copied,
19128 + struct page *pg, void *fsdadata)
19129 +{
19130 + int ret = 0;
19131 + void *addr, *kva;
19132 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
19133 +
19134 + kva = kmap(pg);
19135 + addr = kva + offset_into_page;
19136 +
19137 + T(YAFFS_TRACE_OS,
19138 + ("yaffs_write_end addr %p pos %x nBytes %d\n",
19139 + addr,(unsigned)pos, copied));
19140 +
19141 + ret = yaffs_file_write(filp, addr, copied, &pos);
19142 +
19143 + if (ret != copied) {
19144 + T(YAFFS_TRACE_OS,
19145 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
19146 + ret, copied));
19147 + SetPageError(pg);
19148 + } else {
19149 + /* Nothing */
19150 + }
19151 +
19152 + kunmap(pg);
19153 +
19154 + yaffs_release_space(filp);
19155 + unlock_page(pg);
19156 + page_cache_release(pg);
19157 + return ret;
19158 +}
19159 +#else
19160 +
19161 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
19162 + unsigned to)
19163 +{
19164 + void *addr, *kva;
19165 +
19166 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
19167 + int nBytes = to - offset;
19168 + int nWritten;
19169 +
19170 + unsigned spos = pos;
19171 + unsigned saddr;
19172 +
19173 + kva = kmap(pg);
19174 + addr = kva + offset;
19175 +
19176 + saddr = (unsigned) addr;
19177 +
19178 + T(YAFFS_TRACE_OS,
19179 + (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"),
19180 + saddr, spos, nBytes));
19181 +
19182 + nWritten = yaffs_file_write(f, addr, nBytes, &pos);
19183 +
19184 + if (nWritten != nBytes) {
19185 + T(YAFFS_TRACE_OS,
19186 + (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"),
19187 + nWritten, nBytes));
19188 + SetPageError(pg);
19189 + } else {
19190 + /* Nothing */
19191 + }
19192 +
19193 + kunmap(pg);
19194 +
19195 + T(YAFFS_TRACE_OS,
19196 + (TSTR("yaffs_commit_write returning %d\n"),
19197 + nWritten == nBytes ? 0 : nWritten));
19198 +
19199 + return nWritten == nBytes ? 0 : nWritten;
19200 +}
19201 +#endif
19202 +
19203 +
19204 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
19205 +{
19206 + if (inode && obj) {
19207 +
19208 +
19209 + /* Check mode against the variant type and attempt to repair if broken. */
19210 + __u32 mode = obj->yst_mode;
19211 + switch (obj->variantType) {
19212 + case YAFFS_OBJECT_TYPE_FILE:
19213 + if (!S_ISREG(mode)) {
19214 + obj->yst_mode &= ~S_IFMT;
19215 + obj->yst_mode |= S_IFREG;
19216 + }
19217 +
19218 + break;
19219 + case YAFFS_OBJECT_TYPE_SYMLINK:
19220 + if (!S_ISLNK(mode)) {
19221 + obj->yst_mode &= ~S_IFMT;
19222 + obj->yst_mode |= S_IFLNK;
19223 + }
19224 +
19225 + break;
19226 + case YAFFS_OBJECT_TYPE_DIRECTORY:
19227 + if (!S_ISDIR(mode)) {
19228 + obj->yst_mode &= ~S_IFMT;
19229 + obj->yst_mode |= S_IFDIR;
19230 + }
19231 +
19232 + break;
19233 + case YAFFS_OBJECT_TYPE_UNKNOWN:
19234 + case YAFFS_OBJECT_TYPE_HARDLINK:
19235 + case YAFFS_OBJECT_TYPE_SPECIAL:
19236 + default:
19237 + /* TODO? */
19238 + break;
19239 + }
19240 +
19241 + inode->i_flags |= S_NOATIME;
19242 +
19243 + inode->i_ino = obj->objectId;
19244 + inode->i_mode = obj->yst_mode;
19245 + inode->i_uid = obj->yst_uid;
19246 + inode->i_gid = obj->yst_gid;
19247 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
19248 + inode->i_blksize = inode->i_sb->s_blocksize;
19249 +#endif
19250 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19251 +
19252 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
19253 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
19254 + inode->i_atime.tv_nsec = 0;
19255 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
19256 + inode->i_mtime.tv_nsec = 0;
19257 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
19258 + inode->i_ctime.tv_nsec = 0;
19259 +#else
19260 + inode->i_rdev = obj->yst_rdev;
19261 + inode->i_atime = obj->yst_atime;
19262 + inode->i_mtime = obj->yst_mtime;
19263 + inode->i_ctime = obj->yst_ctime;
19264 +#endif
19265 + inode->i_size = yaffs_GetObjectFileLength(obj);
19266 + inode->i_blocks = (inode->i_size + 511) >> 9;
19267 +
19268 + inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19269 +
19270 + T(YAFFS_TRACE_OS,
19271 + (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"),
19272 + inode->i_mode, inode->i_uid, inode->i_gid,
19273 + (int)inode->i_size, atomic_read(&inode->i_count)));
19274 +
19275 + switch (obj->yst_mode & S_IFMT) {
19276 + default: /* fifo, device or socket */
19277 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19278 + init_special_inode(inode, obj->yst_mode,
19279 + old_decode_dev(obj->yst_rdev));
19280 +#else
19281 + init_special_inode(inode, obj->yst_mode,
19282 + (dev_t) (obj->yst_rdev));
19283 +#endif
19284 + break;
19285 + case S_IFREG: /* file */
19286 + inode->i_op = &yaffs_file_inode_operations;
19287 + inode->i_fop = &yaffs_file_operations;
19288 + inode->i_mapping->a_ops =
19289 + &yaffs_file_address_operations;
19290 + break;
19291 + case S_IFDIR: /* directory */
19292 + inode->i_op = &yaffs_dir_inode_operations;
19293 + inode->i_fop = &yaffs_dir_operations;
19294 + break;
19295 + case S_IFLNK: /* symlink */
19296 + inode->i_op = &yaffs_symlink_inode_operations;
19297 + break;
19298 + }
19299 +
19300 + yaffs_InodeToObjectLV(inode) = obj;
19301 +
19302 + obj->myInode = inode;
19303 +
19304 + } else {
19305 + T(YAFFS_TRACE_OS,
19306 + (TSTR("yaffs_FileInode invalid parameters\n")));
19307 + }
19308 +
19309 +}
19310 +
19311 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
19312 + yaffs_Object *obj)
19313 +{
19314 + struct inode *inode;
19315 +
19316 + if (!sb) {
19317 + T(YAFFS_TRACE_OS,
19318 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
19319 + return NULL;
19320 +
19321 + }
19322 +
19323 + if (!obj) {
19324 + T(YAFFS_TRACE_OS,
19325 + (TSTR("yaffs_get_inode for NULL object!!\n")));
19326 + return NULL;
19327 +
19328 + }
19329 +
19330 + T(YAFFS_TRACE_OS,
19331 + (TSTR("yaffs_get_inode for object %d\n"), obj->objectId));
19332 +
19333 + inode = Y_IGET(sb, obj->objectId);
19334 + if (IS_ERR(inode))
19335 + return NULL;
19336 +
19337 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
19338 + /* iget also increments the inode's i_count */
19339 + /* NB You can't be holding grossLock or deadlock will happen! */
19340 +
19341 + return inode;
19342 +}
19343 +
19344 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
19345 + loff_t *pos)
19346 +{
19347 + yaffs_Object *obj;
19348 + int nWritten, ipos;
19349 + struct inode *inode;
19350 + yaffs_Device *dev;
19351 +
19352 + obj = yaffs_DentryToObject(f->f_dentry);
19353 +
19354 + dev = obj->myDev;
19355 +
19356 + yaffs_GrossLock(dev);
19357 +
19358 + inode = f->f_dentry->d_inode;
19359 +
19360 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
19361 + ipos = inode->i_size;
19362 + else
19363 + ipos = *pos;
19364 +
19365 + if (!obj)
19366 + T(YAFFS_TRACE_OS,
19367 + (TSTR("yaffs_file_write: hey obj is null!\n")));
19368 + else
19369 + T(YAFFS_TRACE_OS,
19370 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
19371 + "to object %d at %d(%x)\n"),
19372 + (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
19373 +
19374 + nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
19375 +
19376 + yaffs_MarkSuperBlockDirty(dev);
19377 +
19378 + T(YAFFS_TRACE_OS,
19379 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
19380 + (unsigned )n,(unsigned)n));
19381 +
19382 + if (nWritten > 0) {
19383 + ipos += nWritten;
19384 + *pos = ipos;
19385 + if (ipos > inode->i_size) {
19386 + inode->i_size = ipos;
19387 + inode->i_blocks = (ipos + 511) >> 9;
19388 +
19389 + T(YAFFS_TRACE_OS,
19390 + (TSTR("yaffs_file_write size updated to %d bytes, "
19391 + "%d blocks\n"),
19392 + ipos, (int)(inode->i_blocks)));
19393 + }
19394 +
19395 + }
19396 + yaffs_GrossUnlock(dev);
19397 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
19398 +}
19399 +
19400 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
19401 +/* For now we just assume few parallel writes and check against a small number. */
19402 +/* Todo: need to do this with a counter to handle parallel reads better */
19403 +
19404 +static ssize_t yaffs_hold_space(struct file *f)
19405 +{
19406 + yaffs_Object *obj;
19407 + yaffs_Device *dev;
19408 +
19409 + int nFreeChunks;
19410 +
19411 +
19412 + obj = yaffs_DentryToObject(f->f_dentry);
19413 +
19414 + dev = obj->myDev;
19415 +
19416 + yaffs_GrossLock(dev);
19417 +
19418 + nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
19419 +
19420 + yaffs_GrossUnlock(dev);
19421 +
19422 + return (nFreeChunks > 20) ? 1 : 0;
19423 +}
19424 +
19425 +static void yaffs_release_space(struct file *f)
19426 +{
19427 + yaffs_Object *obj;
19428 + yaffs_Device *dev;
19429 +
19430 +
19431 + obj = yaffs_DentryToObject(f->f_dentry);
19432 +
19433 + dev = obj->myDev;
19434 +
19435 + yaffs_GrossLock(dev);
19436 +
19437 +
19438 + yaffs_GrossUnlock(dev);
19439 +}
19440 +
19441 +
19442 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
19443 +{
19444 + long long retval;
19445 +
19446 + lock_kernel();
19447 +
19448 + switch (origin){
19449 + case 2:
19450 + offset += i_size_read(file->f_path.dentry->d_inode);
19451 + break;
19452 + case 1:
19453 + offset += file->f_pos;
19454 + }
19455 + retval = -EINVAL;
19456 +
19457 + if (offset >= 0){
19458 + if (offset != file->f_pos)
19459 + file->f_pos = offset;
19460 +
19461 + retval = offset;
19462 + }
19463 + unlock_kernel();
19464 + return retval;
19465 +}
19466 +
19467 +
19468 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
19469 +{
19470 + yaffs_Object *obj;
19471 + yaffs_Device *dev;
19472 + struct yaffs_SearchContext *sc;
19473 + struct inode *inode = f->f_dentry->d_inode;
19474 + unsigned long offset, curoffs;
19475 + yaffs_Object *l;
19476 + int retVal = 0;
19477 +
19478 + char name[YAFFS_MAX_NAME_LENGTH + 1];
19479 +
19480 + obj = yaffs_DentryToObject(f->f_dentry);
19481 + dev = obj->myDev;
19482 +
19483 + yaffs_GrossLock(dev);
19484 +
19485 + yaffs_DeviceToLC(dev)->readdirProcess = current;
19486 +
19487 + offset = f->f_pos;
19488 +
19489 + sc = yaffs_NewSearch(obj);
19490 + if(!sc){
19491 + retVal = -ENOMEM;
19492 + goto out;
19493 + }
19494 +
19495 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
19496 +
19497 + if (offset == 0) {
19498 + T(YAFFS_TRACE_OS,
19499 + (TSTR("yaffs_readdir: entry . ino %d \n"),
19500 + (int)inode->i_ino));
19501 + yaffs_GrossUnlock(dev);
19502 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
19503 + yaffs_GrossLock(dev);
19504 + goto out;
19505 + }
19506 + yaffs_GrossLock(dev);
19507 + offset++;
19508 + f->f_pos++;
19509 + }
19510 + if (offset == 1) {
19511 + T(YAFFS_TRACE_OS,
19512 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
19513 + (int)f->f_dentry->d_parent->d_inode->i_ino));
19514 + yaffs_GrossUnlock(dev);
19515 + if (filldir(dirent, "..", 2, offset,
19516 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
19517 + yaffs_GrossLock(dev);
19518 + goto out;
19519 + }
19520 + yaffs_GrossLock(dev);
19521 + offset++;
19522 + f->f_pos++;
19523 + }
19524 +
19525 + curoffs = 1;
19526 +
19527 + /* If the directory has changed since the open or last call to
19528 + readdir, rewind to after the 2 canned entries. */
19529 + if (f->f_version != inode->i_version) {
19530 + offset = 2;
19531 + f->f_pos = offset;
19532 + f->f_version = inode->i_version;
19533 + }
19534 +
19535 + while(sc->nextReturn){
19536 + curoffs++;
19537 + l = sc->nextReturn;
19538 + if (curoffs >= offset) {
19539 + int this_inode = yaffs_GetObjectInode(l);
19540 + int this_type = yaffs_GetObjectType(l);
19541 +
19542 + yaffs_GetObjectName(l, name,
19543 + YAFFS_MAX_NAME_LENGTH + 1);
19544 + T(YAFFS_TRACE_OS,
19545 + (TSTR("yaffs_readdir: %s inode %d\n"),
19546 + name, yaffs_GetObjectInode(l)));
19547 +
19548 + yaffs_GrossUnlock(dev);
19549 +
19550 + if (filldir(dirent,
19551 + name,
19552 + strlen(name),
19553 + offset,
19554 + this_inode,
19555 + this_type) < 0){
19556 + yaffs_GrossLock(dev);
19557 + goto out;
19558 + }
19559 +
19560 + yaffs_GrossLock(dev);
19561 +
19562 + offset++;
19563 + f->f_pos++;
19564 + }
19565 + yaffs_SearchAdvance(sc);
19566 + }
19567 +
19568 +out:
19569 + yaffs_EndSearch(sc);
19570 + yaffs_DeviceToLC(dev)->readdirProcess = NULL;
19571 + yaffs_GrossUnlock(dev);
19572 +
19573 + return retVal;
19574 +}
19575 +
19576 +
19577 +
19578 +/*
19579 + * File creation. Allocate an inode, and we're done..
19580 + */
19581 +
19582 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
19583 +#define YCRED(x) x
19584 +#else
19585 +#define YCRED(x) (x->cred)
19586 +#endif
19587 +
19588 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19589 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19590 + dev_t rdev)
19591 +#else
19592 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19593 + int rdev)
19594 +#endif
19595 +{
19596 + struct inode *inode;
19597 +
19598 + yaffs_Object *obj = NULL;
19599 + yaffs_Device *dev;
19600 +
19601 + yaffs_Object *parent = yaffs_InodeToObject(dir);
19602 +
19603 + int error = -ENOSPC;
19604 + uid_t uid = YCRED(current)->fsuid;
19605 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19606 +
19607 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
19608 + mode |= S_ISGID;
19609 +
19610 + if (parent) {
19611 + T(YAFFS_TRACE_OS,
19612 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
19613 + parent->objectId, parent->variantType));
19614 + } else {
19615 + T(YAFFS_TRACE_OS,
19616 + (TSTR("yaffs_mknod: could not get parent object\n")));
19617 + return -EPERM;
19618 + }
19619 +
19620 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
19621 + "mode %x dev %x\n"),
19622 + dentry->d_name.name, mode, rdev));
19623 +
19624 + dev = parent->myDev;
19625 +
19626 + yaffs_GrossLock(dev);
19627 +
19628 + switch (mode & S_IFMT) {
19629 + default:
19630 + /* Special (socket, fifo, device...) */
19631 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
19632 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19633 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19634 + gid, old_encode_dev(rdev));
19635 +#else
19636 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19637 + gid, rdev);
19638 +#endif
19639 + break;
19640 + case S_IFREG: /* file */
19641 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
19642 + obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
19643 + gid);
19644 + break;
19645 + case S_IFDIR: /* directory */
19646 + T(YAFFS_TRACE_OS,
19647 + (TSTR("yaffs_mknod: making directory\n")));
19648 + obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
19649 + uid, gid);
19650 + break;
19651 + case S_IFLNK: /* symlink */
19652 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
19653 + obj = NULL; /* Do we ever get here? */
19654 + break;
19655 + }
19656 +
19657 + /* Can not call yaffs_get_inode() with gross lock held */
19658 + yaffs_GrossUnlock(dev);
19659 +
19660 + if (obj) {
19661 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
19662 + d_instantiate(dentry, inode);
19663 + update_dir_time(dir);
19664 + T(YAFFS_TRACE_OS,
19665 + (TSTR("yaffs_mknod created object %d count = %d\n"),
19666 + obj->objectId, atomic_read(&inode->i_count)));
19667 + error = 0;
19668 + yaffs_FillInodeFromObject(dir,parent);
19669 + } else {
19670 + T(YAFFS_TRACE_OS,
19671 + (TSTR("yaffs_mknod failed making object\n")));
19672 + error = -ENOMEM;
19673 + }
19674 +
19675 + return error;
19676 +}
19677 +
19678 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
19679 +{
19680 + int retVal;
19681 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
19682 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
19683 + return retVal;
19684 +}
19685 +
19686 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19687 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
19688 + struct nameidata *n)
19689 +#else
19690 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
19691 +#endif
19692 +{
19693 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
19694 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
19695 +}
19696 +
19697 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
19698 +{
19699 + int retVal;
19700 +
19701 + yaffs_Device *dev;
19702 + yaffs_Object *obj;
19703 +
19704 + T(YAFFS_TRACE_OS,
19705 + (TSTR("yaffs_unlink %d:%s\n"),
19706 + (int)(dir->i_ino),
19707 + dentry->d_name.name));
19708 + obj = yaffs_InodeToObject(dir);
19709 + dev = obj->myDev;
19710 +
19711 + yaffs_GrossLock(dev);
19712 +
19713 + retVal = yaffs_Unlink(obj, dentry->d_name.name);
19714 +
19715 + if (retVal == YAFFS_OK) {
19716 + dentry->d_inode->i_nlink--;
19717 + dir->i_version++;
19718 + yaffs_GrossUnlock(dev);
19719 + mark_inode_dirty(dentry->d_inode);
19720 + update_dir_time(dir);
19721 + return 0;
19722 + }
19723 + yaffs_GrossUnlock(dev);
19724 + return -ENOTEMPTY;
19725 +}
19726 +
19727 +/*
19728 + * Create a link...
19729 + */
19730 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
19731 + struct dentry *dentry)
19732 +{
19733 + struct inode *inode = old_dentry->d_inode;
19734 + yaffs_Object *obj = NULL;
19735 + yaffs_Object *link = NULL;
19736 + yaffs_Device *dev;
19737 +
19738 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
19739 +
19740 + obj = yaffs_InodeToObject(inode);
19741 + dev = obj->myDev;
19742 +
19743 + yaffs_GrossLock(dev);
19744 +
19745 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
19746 + link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
19747 + obj);
19748 +
19749 + if (link) {
19750 + old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19751 + d_instantiate(dentry, old_dentry->d_inode);
19752 + atomic_inc(&old_dentry->d_inode->i_count);
19753 + T(YAFFS_TRACE_OS,
19754 + (TSTR("yaffs_link link count %d i_count %d\n"),
19755 + old_dentry->d_inode->i_nlink,
19756 + atomic_read(&old_dentry->d_inode->i_count)));
19757 + }
19758 +
19759 + yaffs_GrossUnlock(dev);
19760 +
19761 + if (link){
19762 + update_dir_time(dir);
19763 + return 0;
19764 + }
19765 +
19766 + return -EPERM;
19767 +}
19768 +
19769 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
19770 + const char *symname)
19771 +{
19772 + yaffs_Object *obj;
19773 + yaffs_Device *dev;
19774 + uid_t uid = YCRED(current)->fsuid;
19775 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19776 +
19777 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
19778 +
19779 + dev = yaffs_InodeToObject(dir)->myDev;
19780 + yaffs_GrossLock(dev);
19781 + obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
19782 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
19783 + yaffs_GrossUnlock(dev);
19784 +
19785 + if (obj) {
19786 + struct inode *inode;
19787 +
19788 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
19789 + d_instantiate(dentry, inode);
19790 + update_dir_time(dir);
19791 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
19792 + return 0;
19793 + } else {
19794 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
19795 + }
19796 +
19797 + return -ENOMEM;
19798 +}
19799 +
19800 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19801 +static int yaffs_sync_object(struct file *file, int datasync)
19802 +#else
19803 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
19804 + int datasync)
19805 +#endif
19806 +{
19807 +
19808 + yaffs_Object *obj;
19809 + yaffs_Device *dev;
19810 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19811 + struct dentry *dentry = file->f_path.dentry;
19812 +#endif
19813 +
19814 + obj = yaffs_DentryToObject(dentry);
19815 +
19816 + dev = obj->myDev;
19817 +
19818 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
19819 + (TSTR("yaffs_sync_object\n")));
19820 + yaffs_GrossLock(dev);
19821 + yaffs_FlushFile(obj, 1, datasync);
19822 + yaffs_GrossUnlock(dev);
19823 + return 0;
19824 +}
19825 +
19826 +/*
19827 + * The VFS layer already does all the dentry stuff for rename.
19828 + *
19829 + * NB: POSIX says you can rename an object over an old object of the same name
19830 + */
19831 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
19832 + struct inode *new_dir, struct dentry *new_dentry)
19833 +{
19834 + yaffs_Device *dev;
19835 + int retVal = YAFFS_FAIL;
19836 + yaffs_Object *target;
19837 +
19838 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
19839 + dev = yaffs_InodeToObject(old_dir)->myDev;
19840 +
19841 + yaffs_GrossLock(dev);
19842 +
19843 + /* Check if the target is an existing directory that is not empty. */
19844 + target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
19845 + new_dentry->d_name.name);
19846 +
19847 +
19848 +
19849 + if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
19850 + !ylist_empty(&target->variant.directoryVariant.children)) {
19851 +
19852 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
19853 +
19854 + retVal = YAFFS_FAIL;
19855 + } else {
19856 + /* Now does unlinking internally using shadowing mechanism */
19857 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n")));
19858 +
19859 + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
19860 + old_dentry->d_name.name,
19861 + yaffs_InodeToObject(new_dir),
19862 + new_dentry->d_name.name);
19863 + }
19864 + yaffs_GrossUnlock(dev);
19865 +
19866 + if (retVal == YAFFS_OK) {
19867 + if (target) {
19868 + new_dentry->d_inode->i_nlink--;
19869 + mark_inode_dirty(new_dentry->d_inode);
19870 + }
19871 +
19872 + update_dir_time(old_dir);
19873 + if(old_dir != new_dir)
19874 + update_dir_time(new_dir);
19875 + return 0;
19876 + } else {
19877 + return -ENOTEMPTY;
19878 + }
19879 +}
19880 +
19881 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
19882 +{
19883 + struct inode *inode = dentry->d_inode;
19884 + int error = 0;
19885 + yaffs_Device *dev;
19886 +
19887 + T(YAFFS_TRACE_OS,
19888 + (TSTR("yaffs_setattr of object %d\n"),
19889 + yaffs_InodeToObject(inode)->objectId));
19890 +
19891 + /* Fail if a requested resize >= 2GB */
19892 + if (attr->ia_valid & ATTR_SIZE &&
19893 + (attr->ia_size >> 31))
19894 + error = -EINVAL;
19895 +
19896 + if (error == 0)
19897 + error = inode_change_ok(inode, attr);
19898 + if (error == 0) {
19899 + int result;
19900 + if (!error){
19901 + error = yaffs_vfs_setattr(inode, attr);
19902 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
19903 + if (attr->ia_valid & ATTR_SIZE){
19904 + yaffs_vfs_setsize(inode,attr->ia_size);
19905 + inode->i_blocks = (inode->i_size + 511) >> 9;
19906 + }
19907 + }
19908 + dev = yaffs_InodeToObject(inode)->myDev;
19909 + if (attr->ia_valid & ATTR_SIZE){
19910 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
19911 + (int)(attr->ia_size),(int)(attr->ia_size)));
19912 + }
19913 + yaffs_GrossLock(dev);
19914 + result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
19915 + if(result == YAFFS_OK) {
19916 + error = 0;
19917 + } else {
19918 + error = -EPERM;
19919 + }
19920 + yaffs_GrossUnlock(dev);
19921 +
19922 + }
19923 +
19924 + T(YAFFS_TRACE_OS,
19925 + (TSTR("yaffs_setattr done returning %d\n"),error));
19926 +
19927 + return error;
19928 +}
19929 +
19930 +#ifdef CONFIG_YAFFS_XATTR
19931 +int yaffs_setxattr(struct dentry *dentry, const char *name,
19932 + const void *value, size_t size, int flags)
19933 +{
19934 + struct inode *inode = dentry->d_inode;
19935 + int error = 0;
19936 + yaffs_Device *dev;
19937 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19938 +
19939 + T(YAFFS_TRACE_OS,
19940 + (TSTR("yaffs_setxattr of object %d\n"),
19941 + obj->objectId));
19942 +
19943 +
19944 + if (error == 0) {
19945 + int result;
19946 + dev = obj->myDev;
19947 + yaffs_GrossLock(dev);
19948 + result = yaffs_SetXAttribute(obj, name, value, size, flags);
19949 + if(result == YAFFS_OK)
19950 + error = 0;
19951 + else if(result < 0)
19952 + error = result;
19953 + yaffs_GrossUnlock(dev);
19954 +
19955 + }
19956 + T(YAFFS_TRACE_OS,
19957 + (TSTR("yaffs_setxattr done returning %d\n"),error));
19958 +
19959 + return error;
19960 +}
19961 +
19962 +
19963 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
19964 + size_t size)
19965 +{
19966 + struct inode *inode = dentry->d_inode;
19967 + int error = 0;
19968 + yaffs_Device *dev;
19969 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19970 +
19971 + T(YAFFS_TRACE_OS,
19972 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
19973 + name, obj->objectId));
19974 +
19975 + if (error == 0) {
19976 + dev = obj->myDev;
19977 + yaffs_GrossLock(dev);
19978 + error = yaffs_GetXAttribute(obj, name, buff, size);
19979 + yaffs_GrossUnlock(dev);
19980 +
19981 + }
19982 + T(YAFFS_TRACE_OS,
19983 + (TSTR("yaffs_getxattr done returning %d\n"),error));
19984 +
19985 + return error;
19986 +}
19987 +
19988 +int yaffs_removexattr(struct dentry *dentry, const char *name)
19989 +{
19990 + struct inode *inode = dentry->d_inode;
19991 + int error = 0;
19992 + yaffs_Device *dev;
19993 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19994 +
19995 + T(YAFFS_TRACE_OS,
19996 + (TSTR("yaffs_removexattr of object %d\n"),
19997 + obj->objectId));
19998 +
19999 +
20000 + if (error == 0) {
20001 + int result;
20002 + dev = obj->myDev;
20003 + yaffs_GrossLock(dev);
20004 + result = yaffs_RemoveXAttribute(obj, name);
20005 + if(result == YAFFS_OK)
20006 + error = 0;
20007 + else if(result < 0)
20008 + error = result;
20009 + yaffs_GrossUnlock(dev);
20010 +
20011 + }
20012 + T(YAFFS_TRACE_OS,
20013 + (TSTR("yaffs_removexattr done returning %d\n"),error));
20014 +
20015 + return error;
20016 +}
20017 +
20018 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
20019 +{
20020 + struct inode *inode = dentry->d_inode;
20021 + int error = 0;
20022 + yaffs_Device *dev;
20023 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20024 +
20025 + T(YAFFS_TRACE_OS,
20026 + (TSTR("yaffs_listxattr of object %d\n"),
20027 + obj->objectId));
20028 +
20029 +
20030 + if (error == 0) {
20031 + dev = obj->myDev;
20032 + yaffs_GrossLock(dev);
20033 + error = yaffs_ListXAttributes(obj, buff, size);
20034 + yaffs_GrossUnlock(dev);
20035 +
20036 + }
20037 + T(YAFFS_TRACE_OS,
20038 + (TSTR("yaffs_listxattr done returning %d\n"),error));
20039 +
20040 + return error;
20041 +}
20042 +
20043 +#endif
20044 +
20045 +
20046 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20047 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
20048 +{
20049 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
20050 + struct super_block *sb = dentry->d_sb;
20051 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20052 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
20053 +{
20054 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20055 +#else
20056 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
20057 +{
20058 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20059 +#endif
20060 +
20061 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
20062 +
20063 + yaffs_GrossLock(dev);
20064 +
20065 + buf->f_type = YAFFS_MAGIC;
20066 + buf->f_bsize = sb->s_blocksize;
20067 + buf->f_namelen = 255;
20068 +
20069 + if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
20070 + /* Do this if chunk size is not a power of 2 */
20071 +
20072 + uint64_t bytesInDev;
20073 + uint64_t bytesFree;
20074 +
20075 + bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) *
20076 + ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk));
20077 +
20078 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
20079 + buf->f_blocks = bytesInDev;
20080 +
20081 + bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
20082 + ((uint64_t)(dev->nDataBytesPerChunk));
20083 +
20084 + do_div(bytesFree, sb->s_blocksize);
20085 +
20086 + buf->f_bfree = bytesFree;
20087 +
20088 + } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
20089 +
20090 + buf->f_blocks =
20091 + (dev->param.endBlock - dev->param.startBlock + 1) *
20092 + dev->param.nChunksPerBlock /
20093 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20094 + buf->f_bfree =
20095 + yaffs_GetNumberOfFreeChunks(dev) /
20096 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20097 + } else {
20098 + buf->f_blocks =
20099 + (dev->param.endBlock - dev->param.startBlock + 1) *
20100 + dev->param.nChunksPerBlock *
20101 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20102 +
20103 + buf->f_bfree =
20104 + yaffs_GetNumberOfFreeChunks(dev) *
20105 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20106 + }
20107 +
20108 + buf->f_files = 0;
20109 + buf->f_ffree = 0;
20110 + buf->f_bavail = buf->f_bfree;
20111 +
20112 + yaffs_GrossUnlock(dev);
20113 + return 0;
20114 +}
20115 +
20116 +
20117 +
20118 +static void yaffs_FlushInodes(struct super_block *sb)
20119 +{
20120 + struct inode *iptr;
20121 + yaffs_Object *obj;
20122 +
20123 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
20124 + obj = yaffs_InodeToObject(iptr);
20125 + if(obj){
20126 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
20127 + obj->objectId));
20128 + yaffs_FlushFile(obj,1,0);
20129 + }
20130 + }
20131 +}
20132 +
20133 +
20134 +static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
20135 +{
20136 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20137 + if(!dev)
20138 + return;
20139 +
20140 + yaffs_FlushInodes(sb);
20141 + yaffs_UpdateDirtyDirectories(dev);
20142 + yaffs_FlushEntireDeviceCache(dev);
20143 + if(do_checkpoint)
20144 + yaffs_CheckpointSave(dev);
20145 +}
20146 +
20147 +
20148 +static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
20149 +{
20150 + unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
20151 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20152 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
20153 +
20154 + if(erasedChunks < dev->nFreeChunks)
20155 + scatteredFree = (dev->nFreeChunks - erasedChunks);
20156 +
20157 + if(!context->bgRunning)
20158 + return 0;
20159 + else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
20160 + return 0;
20161 + else if(erasedChunks > dev->nFreeChunks/2)
20162 + return 0;
20163 + else if(erasedChunks > dev->nFreeChunks/4)
20164 + return 1;
20165 + else
20166 + return 2;
20167 +}
20168 +
20169 +static int yaffs_do_sync_fs(struct super_block *sb,
20170 + int request_checkpoint)
20171 +{
20172 +
20173 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20174 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
20175 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
20176 + int do_checkpoint;
20177 +
20178 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20179 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
20180 + gc_urgent,
20181 + sb->s_dirt ? "dirty" : "clean",
20182 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
20183 + oneshot_checkpoint ? " one-shot" : "" ));
20184 +
20185 + yaffs_GrossLock(dev);
20186 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
20187 + oneshot_checkpoint) &&
20188 + !dev->isCheckpointed;
20189 +
20190 + if (sb->s_dirt || do_checkpoint) {
20191 + yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
20192 + sb->s_dirt = 0;
20193 + if(oneshot_checkpoint)
20194 + yaffs_auto_checkpoint &= ~4;
20195 + }
20196 + yaffs_GrossUnlock(dev);
20197 +
20198 + return 0;
20199 +}
20200 +
20201 +/*
20202 + * yaffs background thread functions .
20203 + * yaffs_BackgroundThread() the thread function
20204 + * yaffs_BackgroundStart() launches the background thread.
20205 + * yaffs_BackgroundStop() cleans up the background thread.
20206 + *
20207 + * NB:
20208 + * The thread should only run after the yaffs is initialised
20209 + * The thread should be stopped before yaffs is unmounted.
20210 + * The thread should not do any writing while the fs is in read only.
20211 + */
20212 +
20213 +#ifdef YAFFS_COMPILE_BACKGROUND
20214 +
20215 +void yaffs_background_waker(unsigned long data)
20216 +{
20217 + wake_up_process((struct task_struct *)data);
20218 +}
20219 +
20220 +static int yaffs_BackgroundThread(void *data)
20221 +{
20222 + yaffs_Device *dev = (yaffs_Device *)data;
20223 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20224 + unsigned long now = jiffies;
20225 + unsigned long next_dir_update = now;
20226 + unsigned long next_gc = now;
20227 + unsigned long expires;
20228 + unsigned int urgency;
20229 +
20230 + int gcResult;
20231 + struct timer_list timer;
20232 +
20233 + T(YAFFS_TRACE_BACKGROUND,
20234 + (TSTR("yaffs_background starting for dev %p\n"),
20235 + (void *)dev));
20236 +
20237 +#ifdef YAFFS_COMPILE_FREEZER
20238 + set_freezable();
20239 +#endif
20240 + while(context->bgRunning){
20241 + T(YAFFS_TRACE_BACKGROUND,
20242 + (TSTR("yaffs_background\n")));
20243 +
20244 + if(kthread_should_stop())
20245 + break;
20246 +
20247 +#ifdef YAFFS_COMPILE_FREEZER
20248 + if(try_to_freeze())
20249 + continue;
20250 +#endif
20251 + yaffs_GrossLock(dev);
20252 +
20253 + now = jiffies;
20254 +
20255 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
20256 + yaffs_UpdateDirtyDirectories(dev);
20257 + next_dir_update = now + HZ;
20258 + }
20259 +
20260 + if(time_after(now,next_gc) && yaffs_bg_enable){
20261 + if(!dev->isCheckpointed){
20262 + urgency = yaffs_bg_gc_urgency(dev);
20263 + gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
20264 + if(urgency > 1)
20265 + next_gc = now + HZ/20+1;
20266 + else if(urgency > 0)
20267 + next_gc = now + HZ/10+1;
20268 + else
20269 + next_gc = now + HZ * 2;
20270 + } else /*
20271 + * gc not running so set to next_dir_update
20272 + * to cut down on wake ups
20273 + */
20274 + next_gc = next_dir_update;
20275 + }
20276 + yaffs_GrossUnlock(dev);
20277 +#if 1
20278 + expires = next_dir_update;
20279 + if (time_before(next_gc,expires))
20280 + expires = next_gc;
20281 + if(time_before(expires,now))
20282 + expires = now + HZ;
20283 +
20284 + Y_INIT_TIMER(&timer);
20285 + timer.expires = expires+1;
20286 + timer.data = (unsigned long) current;
20287 + timer.function = yaffs_background_waker;
20288 +
20289 + set_current_state(TASK_INTERRUPTIBLE);
20290 + add_timer(&timer);
20291 + schedule();
20292 + del_timer_sync(&timer);
20293 +#else
20294 + msleep(10);
20295 +#endif
20296 + }
20297 +
20298 + return 0;
20299 +}
20300 +
20301 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20302 +{
20303 + int retval = 0;
20304 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20305 +
20306 + if(dev->readOnly)
20307 + return -1;
20308 +
20309 + context->bgRunning = 1;
20310 +
20311 + context->bgThread = kthread_run(yaffs_BackgroundThread,
20312 + (void *)dev,"yaffs-bg-%d",context->mount_id);
20313 +
20314 + if(IS_ERR(context->bgThread)){
20315 + retval = PTR_ERR(context->bgThread);
20316 + context->bgThread = NULL;
20317 + context->bgRunning = 0;
20318 + }
20319 + return retval;
20320 +}
20321 +
20322 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20323 +{
20324 + struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
20325 +
20326 + ctxt->bgRunning = 0;
20327 +
20328 + if( ctxt->bgThread){
20329 + kthread_stop(ctxt->bgThread);
20330 + ctxt->bgThread = NULL;
20331 + }
20332 +}
20333 +#else
20334 +static int yaffs_BackgroundThread(void *data)
20335 +{
20336 + return 0;
20337 +}
20338 +
20339 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20340 +{
20341 + return 0;
20342 +}
20343 +
20344 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20345 +{
20346 +}
20347 +#endif
20348 +
20349 +
20350 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20351 +static void yaffs_write_super(struct super_block *sb)
20352 +#else
20353 +static int yaffs_write_super(struct super_block *sb)
20354 +#endif
20355 +{
20356 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
20357 +
20358 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20359 + (TSTR("yaffs_write_super%s\n"),
20360 + request_checkpoint ? " checkpt" : ""));
20361 +
20362 + yaffs_do_sync_fs(sb, request_checkpoint);
20363 +
20364 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
20365 + return 0;
20366 +#endif
20367 +}
20368 +
20369 +
20370 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20371 +static int yaffs_sync_fs(struct super_block *sb, int wait)
20372 +#else
20373 +static int yaffs_sync_fs(struct super_block *sb)
20374 +#endif
20375 +{
20376 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
20377 +
20378 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
20379 + (TSTR("yaffs_sync_fs%s\n"),
20380 + request_checkpoint ? " checkpt" : ""));
20381 +
20382 + yaffs_do_sync_fs(sb, request_checkpoint);
20383 +
20384 + return 0;
20385 +}
20386 +
20387 +#ifdef YAFFS_USE_OWN_IGET
20388 +
20389 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
20390 +{
20391 + struct inode *inode;
20392 + yaffs_Object *obj;
20393 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20394 +
20395 + T(YAFFS_TRACE_OS,
20396 + (TSTR("yaffs_iget for %lu\n"), ino));
20397 +
20398 + inode = iget_locked(sb, ino);
20399 + if (!inode)
20400 + return ERR_PTR(-ENOMEM);
20401 + if (!(inode->i_state & I_NEW))
20402 + return inode;
20403 +
20404 + /* NB This is called as a side effect of other functions, but
20405 + * we had to release the lock to prevent deadlocks, so
20406 + * need to lock again.
20407 + */
20408 +
20409 + yaffs_GrossLock(dev);
20410 +
20411 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20412 +
20413 + yaffs_FillInodeFromObject(inode, obj);
20414 +
20415 + yaffs_GrossUnlock(dev);
20416 +
20417 + unlock_new_inode(inode);
20418 + return inode;
20419 +}
20420 +
20421 +#else
20422 +
20423 +static void yaffs_read_inode(struct inode *inode)
20424 +{
20425 + /* NB This is called as a side effect of other functions, but
20426 + * we had to release the lock to prevent deadlocks, so
20427 + * need to lock again.
20428 + */
20429 +
20430 + yaffs_Object *obj;
20431 + yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
20432 +
20433 + T(YAFFS_TRACE_OS,
20434 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
20435 +
20436 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20437 + yaffs_GrossLock(dev);
20438 +
20439 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20440 +
20441 + yaffs_FillInodeFromObject(inode, obj);
20442 +
20443 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20444 + yaffs_GrossUnlock(dev);
20445 +}
20446 +
20447 +#endif
20448 +
20449 +static YLIST_HEAD(yaffs_context_list);
20450 +struct semaphore yaffs_context_lock;
20451 +
20452 +static void yaffs_put_super(struct super_block *sb)
20453 +{
20454 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20455 +
20456 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
20457 +
20458 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20459 + (TSTR("Shutting down yaffs background thread\n")));
20460 + yaffs_BackgroundStop(dev);
20461 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20462 + (TSTR("yaffs background thread shut down\n")));
20463 +
20464 + yaffs_GrossLock(dev);
20465 +
20466 + yaffs_FlushSuperBlock(sb,1);
20467 +
20468 + if (yaffs_DeviceToLC(dev)->putSuperFunc)
20469 + yaffs_DeviceToLC(dev)->putSuperFunc(sb);
20470 +
20471 +
20472 + yaffs_Deinitialise(dev);
20473 +
20474 + yaffs_GrossUnlock(dev);
20475 +
20476 + down(&yaffs_context_lock);
20477 + ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
20478 + up(&yaffs_context_lock);
20479 +
20480 + if (yaffs_DeviceToLC(dev)->spareBuffer) {
20481 + YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
20482 + yaffs_DeviceToLC(dev)->spareBuffer = NULL;
20483 + }
20484 +
20485 + kfree(dev);
20486 +}
20487 +
20488 +
20489 +static void yaffs_MTDPutSuper(struct super_block *sb)
20490 +{
20491 + struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
20492 +
20493 + if (mtd->sync)
20494 + mtd->sync(mtd);
20495 +
20496 + put_mtd_device(mtd);
20497 +}
20498 +
20499 +
20500 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
20501 +{
20502 + struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
20503 +
20504 + T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
20505 + if (sb)
20506 + sb->s_dirt = 1;
20507 +}
20508 +
20509 +typedef struct {
20510 + int inband_tags;
20511 + int skip_checkpoint_read;
20512 + int skip_checkpoint_write;
20513 + int no_cache;
20514 + int tags_ecc_on;
20515 + int tags_ecc_overridden;
20516 + int lazy_loading_enabled;
20517 + int lazy_loading_overridden;
20518 + int empty_lost_and_found;
20519 + int empty_lost_and_found_overridden;
20520 +} yaffs_options;
20521 +
20522 +#define MAX_OPT_LEN 30
20523 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
20524 +{
20525 + char cur_opt[MAX_OPT_LEN + 1];
20526 + int p;
20527 + int error = 0;
20528 +
20529 + /* Parse through the options which is a comma seperated list */
20530 +
20531 + while (options_str && *options_str && !error) {
20532 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
20533 + p = 0;
20534 +
20535 + while(*options_str == ',')
20536 + options_str++;
20537 +
20538 + while (*options_str && *options_str != ',') {
20539 + if (p < MAX_OPT_LEN) {
20540 + cur_opt[p] = *options_str;
20541 + p++;
20542 + }
20543 + options_str++;
20544 + }
20545 +
20546 + if (!strcmp(cur_opt, "inband-tags"))
20547 + options->inband_tags = 1;
20548 + else if (!strcmp(cur_opt, "tags-ecc-off")){
20549 + options->tags_ecc_on = 0;
20550 + options->tags_ecc_overridden=1;
20551 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
20552 + options->tags_ecc_on = 1;
20553 + options->tags_ecc_overridden = 1;
20554 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
20555 + options->lazy_loading_enabled = 0;
20556 + options->lazy_loading_overridden=1;
20557 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
20558 + options->lazy_loading_enabled = 1;
20559 + options->lazy_loading_overridden = 1;
20560 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
20561 + options->empty_lost_and_found = 0;
20562 + options->empty_lost_and_found_overridden=1;
20563 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
20564 + options->empty_lost_and_found = 1;
20565 + options->empty_lost_and_found_overridden=1;
20566 + } else if (!strcmp(cur_opt, "no-cache"))
20567 + options->no_cache = 1;
20568 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
20569 + options->skip_checkpoint_read = 1;
20570 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
20571 + options->skip_checkpoint_write = 1;
20572 + else if (!strcmp(cur_opt, "no-checkpoint")) {
20573 + options->skip_checkpoint_read = 1;
20574 + options->skip_checkpoint_write = 1;
20575 + } else {
20576 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
20577 + cur_opt);
20578 + error = 1;
20579 + }
20580 + }
20581 +
20582 + return error;
20583 +}
20584 +
20585 +static struct super_block *yaffs_internal_read_super(int yaffsVersion,
20586 + struct super_block *sb,
20587 + void *data, int silent)
20588 +{
20589 + int nBlocks;
20590 + struct inode *inode = NULL;
20591 + struct dentry *root;
20592 + yaffs_Device *dev = 0;
20593 + char devname_buf[BDEVNAME_SIZE + 1];
20594 + struct mtd_info *mtd;
20595 + int err;
20596 + char *data_str = (char *)data;
20597 + struct yaffs_LinuxContext *context = NULL;
20598 + yaffs_DeviceParam *param;
20599 +
20600 + int readOnly = 0;
20601 +
20602 + yaffs_options options;
20603 +
20604 + unsigned mount_id;
20605 + int found;
20606 + struct yaffs_LinuxContext *context_iterator;
20607 + struct ylist_head *l;
20608 +
20609 + sb->s_magic = YAFFS_MAGIC;
20610 + sb->s_op = &yaffs_super_ops;
20611 + sb->s_flags |= MS_NOATIME;
20612 +
20613 + readOnly =((sb->s_flags & MS_RDONLY) != 0);
20614 +
20615 +
20616 +#ifdef YAFFS_COMPILE_EXPORTFS
20617 + sb->s_export_op = &yaffs_export_ops;
20618 +#endif
20619 +
20620 + if (!sb)
20621 + printk(KERN_INFO "yaffs: sb is NULL\n");
20622 + else if (!sb->s_dev)
20623 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
20624 + else if (!yaffs_devname(sb, devname_buf))
20625 + printk(KERN_INFO "yaffs: devname is NULL\n");
20626 + else
20627 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
20628 + sb->s_dev,
20629 + yaffs_devname(sb, devname_buf),
20630 + readOnly ? "ro" : "rw");
20631 +
20632 + if (!data_str)
20633 + data_str = "";
20634 +
20635 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
20636 +
20637 + memset(&options, 0, sizeof(options));
20638 +
20639 + if (yaffs_parse_options(&options, data_str)) {
20640 + /* Option parsing failed */
20641 + return NULL;
20642 + }
20643 +
20644 +
20645 + sb->s_blocksize = PAGE_CACHE_SIZE;
20646 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
20647 +
20648 + T(YAFFS_TRACE_OS,
20649 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
20650 + T(YAFFS_TRACE_OS,
20651 + (TSTR("yaffs_read_super: block size %d\n"),
20652 + (int)(sb->s_blocksize)));
20653 +
20654 + T(YAFFS_TRACE_ALWAYS,
20655 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
20656 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
20657 + yaffs_devname(sb, devname_buf)));
20658 +
20659 + /* Check it's an mtd device..... */
20660 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
20661 + return NULL; /* This isn't an mtd device */
20662 +
20663 + /* Get the device */
20664 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
20665 + if (!mtd) {
20666 + T(YAFFS_TRACE_ALWAYS,
20667 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
20668 + MINOR(sb->s_dev)));
20669 + return NULL;
20670 + }
20671 + /* Check it's NAND */
20672 + if (mtd->type != MTD_NANDFLASH) {
20673 + T(YAFFS_TRACE_ALWAYS,
20674 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
20675 + mtd->type));
20676 + return NULL;
20677 + }
20678 +
20679 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
20680 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
20681 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
20682 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
20683 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
20684 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
20685 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
20686 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
20687 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
20688 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
20689 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
20690 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
20691 +#else
20692 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
20693 +#endif
20694 +
20695 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
20696 +
20697 + if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
20698 + T(YAFFS_TRACE_ALWAYS,
20699 + (TSTR("yaffs: auto selecting yaffs2\n")));
20700 + yaffsVersion = 2;
20701 + }
20702 +
20703 + /* Added NCB 26/5/2006 for completeness */
20704 + if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
20705 + T(YAFFS_TRACE_ALWAYS,
20706 + (TSTR("yaffs: auto selecting yaffs1\n")));
20707 + yaffsVersion = 1;
20708 + }
20709 +
20710 +#endif
20711 +
20712 + if (yaffsVersion == 2) {
20713 + /* Check for version 2 style functions */
20714 + if (!mtd->erase ||
20715 + !mtd->block_isbad ||
20716 + !mtd->block_markbad ||
20717 + !mtd->read ||
20718 + !mtd->write ||
20719 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20720 + !mtd->read_oob || !mtd->write_oob) {
20721 +#else
20722 + !mtd->write_ecc ||
20723 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20724 +#endif
20725 + T(YAFFS_TRACE_ALWAYS,
20726 + (TSTR("yaffs: MTD device does not support required "
20727 + "functions\n")));
20728 + return NULL;
20729 + }
20730 +
20731 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
20732 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
20733 + !options.inband_tags) {
20734 + T(YAFFS_TRACE_ALWAYS,
20735 + (TSTR("yaffs: MTD device does not have the "
20736 + "right page sizes\n")));
20737 + return NULL;
20738 + }
20739 + } else {
20740 + /* Check for V1 style functions */
20741 + if (!mtd->erase ||
20742 + !mtd->read ||
20743 + !mtd->write ||
20744 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20745 + !mtd->read_oob || !mtd->write_oob) {
20746 +#else
20747 + !mtd->write_ecc ||
20748 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20749 +#endif
20750 + T(YAFFS_TRACE_ALWAYS,
20751 + (TSTR("yaffs: MTD device does not support required "
20752 + "functions\n")));
20753 + return NULL;
20754 + }
20755 +
20756 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
20757 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
20758 + T(YAFFS_TRACE_ALWAYS,
20759 + (TSTR("yaffs: MTD device does not support have the "
20760 + "right page sizes\n")));
20761 + return NULL;
20762 + }
20763 + }
20764 +
20765 + /* OK, so if we got here, we have an MTD that's NAND and looks
20766 + * like it has the right capabilities
20767 + * Set the yaffs_Device up for mtd
20768 + */
20769 +
20770 + if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
20771 + readOnly = 1;
20772 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
20773 + sb->s_flags |= MS_RDONLY;
20774 + }
20775 +
20776 + dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
20777 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
20778 +
20779 + if(!dev || !context ){
20780 + if(dev)
20781 + kfree(dev);
20782 + if(context)
20783 + kfree(context);
20784 + dev = NULL;
20785 + context = NULL;
20786 + }
20787 +
20788 + if (!dev) {
20789 + /* Deep shit could not allocate device structure */
20790 + T(YAFFS_TRACE_ALWAYS,
20791 + (TSTR("yaffs_read_super: Failed trying to allocate "
20792 + "yaffs_Device. \n")));
20793 + return NULL;
20794 + }
20795 + memset(dev, 0, sizeof(yaffs_Device));
20796 + param = &(dev->param);
20797 +
20798 + memset(context,0,sizeof(struct yaffs_LinuxContext));
20799 + dev->osContext = context;
20800 + YINIT_LIST_HEAD(&(context->contextList));
20801 + context->dev = dev;
20802 + context->superBlock = sb;
20803 +
20804 + dev->readOnly = readOnly;
20805 +
20806 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20807 + sb->s_fs_info = dev;
20808 +#else
20809 + sb->u.generic_sbp = dev;
20810 +#endif
20811 +
20812 + dev->driverContext = mtd;
20813 + param->name = mtd->name;
20814 +
20815 + /* Set up the memory size parameters.... */
20816 +
20817 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
20818 +
20819 + param->startBlock = 0;
20820 + param->endBlock = nBlocks - 1;
20821 + param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
20822 + param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
20823 + param->nReservedBlocks = 5;
20824 + param->nShortOpCaches = (options.no_cache) ? 0 : 10;
20825 + param->inbandTags = options.inband_tags;
20826 +
20827 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
20828 + param->disableLazyLoad = 1;
20829 +#endif
20830 +#ifdef CONFIG_YAFFS_XATTR
20831 + param->enableXattr = 1;
20832 +#endif
20833 + if(options.lazy_loading_overridden)
20834 + param->disableLazyLoad = !options.lazy_loading_enabled;
20835 +
20836 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
20837 + param->noTagsECC = 1;
20838 +#endif
20839 +
20840 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
20841 +#else
20842 + param->deferDirectoryUpdate = 1;
20843 +#endif
20844 +
20845 + if(options.tags_ecc_overridden)
20846 + param->noTagsECC = !options.tags_ecc_on;
20847 +
20848 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
20849 + param->emptyLostAndFound = 1;
20850 +#endif
20851 +
20852 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
20853 + param->refreshPeriod = 0;
20854 +#else
20855 + param->refreshPeriod = 500;
20856 +#endif
20857 +
20858 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
20859 + param->alwaysCheckErased = 1;
20860 +#endif
20861 +
20862 + if(options.empty_lost_and_found_overridden)
20863 + param->emptyLostAndFound = options.empty_lost_and_found;
20864 +
20865 + /* ... and the functions. */
20866 + if (yaffsVersion == 2) {
20867 + param->writeChunkWithTagsToNAND =
20868 + nandmtd2_WriteChunkWithTagsToNAND;
20869 + param->readChunkWithTagsFromNAND =
20870 + nandmtd2_ReadChunkWithTagsFromNAND;
20871 + param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
20872 + param->queryNANDBlock = nandmtd2_QueryNANDBlock;
20873 + yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
20874 + param->isYaffs2 = 1;
20875 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20876 + param->totalBytesPerChunk = mtd->writesize;
20877 + param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
20878 +#else
20879 + param->totalBytesPerChunk = mtd->oobblock;
20880 + param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
20881 +#endif
20882 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
20883 +
20884 + param->startBlock = 0;
20885 + param->endBlock = nBlocks - 1;
20886 + } else {
20887 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20888 + /* use the MTD interface in yaffs_mtdif1.c */
20889 + param->writeChunkWithTagsToNAND =
20890 + nandmtd1_WriteChunkWithTagsToNAND;
20891 + param->readChunkWithTagsFromNAND =
20892 + nandmtd1_ReadChunkWithTagsFromNAND;
20893 + param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
20894 + param->queryNANDBlock = nandmtd1_QueryNANDBlock;
20895 +#else
20896 + param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
20897 + param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
20898 +#endif
20899 + param->isYaffs2 = 0;
20900 + }
20901 + /* ... and common functions */
20902 + param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
20903 + param->initialiseNAND = nandmtd_InitialiseNAND;
20904 +
20905 + yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
20906 +
20907 + param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
20908 + param->gcControl = yaffs_gc_control_callback;
20909 +
20910 + yaffs_DeviceToLC(dev)->superBlock= sb;
20911 +
20912 +
20913 +#ifndef CONFIG_YAFFS_DOES_ECC
20914 + param->useNANDECC = 1;
20915 +#endif
20916 +
20917 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
20918 + param->wideTnodesDisabled = 1;
20919 +#endif
20920 +
20921 + param->skipCheckpointRead = options.skip_checkpoint_read;
20922 + param->skipCheckpointWrite = options.skip_checkpoint_write;
20923 +
20924 + down(&yaffs_context_lock);
20925 + /* Get a mount id */
20926 + found = 0;
20927 + for(mount_id=0; ! found; mount_id++){
20928 + found = 1;
20929 + ylist_for_each(l,&yaffs_context_list){
20930 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
20931 + if(context_iterator->mount_id == mount_id)
20932 + found = 0;
20933 + }
20934 + }
20935 + context->mount_id = mount_id;
20936 +
20937 + ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
20938 + up(&yaffs_context_lock);
20939 +
20940 + /* Directory search handling...*/
20941 + YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
20942 + param->removeObjectCallback = yaffs_RemoveObjectCallback;
20943 +
20944 + init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
20945 +
20946 + yaffs_GrossLock(dev);
20947 +
20948 + err = yaffs_GutsInitialise(dev);
20949 +
20950 + T(YAFFS_TRACE_OS,
20951 + (TSTR("yaffs_read_super: guts initialised %s\n"),
20952 + (err == YAFFS_OK) ? "OK" : "FAILED"));
20953 +
20954 + if(err == YAFFS_OK)
20955 + yaffs_BackgroundStart(dev);
20956 +
20957 + if(!context->bgThread)
20958 + param->deferDirectoryUpdate = 0;
20959 +
20960 +
20961 + /* Release lock before yaffs_get_inode() */
20962 + yaffs_GrossUnlock(dev);
20963 +
20964 + /* Create root inode */
20965 + if (err == YAFFS_OK)
20966 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
20967 + yaffs_Root(dev));
20968 +
20969 + if (!inode)
20970 + return NULL;
20971 +
20972 + inode->i_op = &yaffs_dir_inode_operations;
20973 + inode->i_fop = &yaffs_dir_operations;
20974 +
20975 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
20976 +
20977 + root = d_alloc_root(inode);
20978 +
20979 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
20980 +
20981 + if (!root) {
20982 + iput(inode);
20983 + return NULL;
20984 + }
20985 + sb->s_root = root;
20986 + sb->s_dirt = !dev->isCheckpointed;
20987 + T(YAFFS_TRACE_ALWAYS,
20988 + (TSTR("yaffs_read_super: isCheckpointed %d\n"),
20989 + dev->isCheckpointed));
20990 +
20991 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
20992 + return sb;
20993 +}
20994 +
20995 +
20996 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20997 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
20998 + int silent)
20999 +{
21000 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
21001 +}
21002 +
21003 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21004 +static int yaffs_read_super(struct file_system_type *fs,
21005 + int flags, const char *dev_name,
21006 + void *data, struct vfsmount *mnt)
21007 +{
21008 +
21009 + return get_sb_bdev(fs, flags, dev_name, data,
21010 + yaffs_internal_read_super_mtd, mnt);
21011 +}
21012 +#else
21013 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
21014 + int flags, const char *dev_name,
21015 + void *data)
21016 +{
21017 +
21018 + return get_sb_bdev(fs, flags, dev_name, data,
21019 + yaffs_internal_read_super_mtd);
21020 +}
21021 +#endif
21022 +
21023 +static struct file_system_type yaffs_fs_type = {
21024 + .owner = THIS_MODULE,
21025 + .name = "yaffs",
21026 + .get_sb = yaffs_read_super,
21027 + .kill_sb = kill_block_super,
21028 + .fs_flags = FS_REQUIRES_DEV,
21029 +};
21030 +#else
21031 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
21032 + int silent)
21033 +{
21034 + return yaffs_internal_read_super(1, sb, data, silent);
21035 +}
21036 +
21037 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
21038 + FS_REQUIRES_DEV);
21039 +#endif
21040 +
21041 +
21042 +#ifdef CONFIG_YAFFS_YAFFS2
21043 +
21044 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21045 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
21046 + int silent)
21047 +{
21048 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
21049 +}
21050 +
21051 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21052 +static int yaffs2_read_super(struct file_system_type *fs,
21053 + int flags, const char *dev_name, void *data,
21054 + struct vfsmount *mnt)
21055 +{
21056 + return get_sb_bdev(fs, flags, dev_name, data,
21057 + yaffs2_internal_read_super_mtd, mnt);
21058 +}
21059 +#else
21060 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
21061 + int flags, const char *dev_name,
21062 + void *data)
21063 +{
21064 +
21065 + return get_sb_bdev(fs, flags, dev_name, data,
21066 + yaffs2_internal_read_super_mtd);
21067 +}
21068 +#endif
21069 +
21070 +static struct file_system_type yaffs2_fs_type = {
21071 + .owner = THIS_MODULE,
21072 + .name = "yaffs2",
21073 + .get_sb = yaffs2_read_super,
21074 + .kill_sb = kill_block_super,
21075 + .fs_flags = FS_REQUIRES_DEV,
21076 +};
21077 +#else
21078 +static struct super_block *yaffs2_read_super(struct super_block *sb,
21079 + void *data, int silent)
21080 +{
21081 + return yaffs_internal_read_super(2, sb, data, silent);
21082 +}
21083 +
21084 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
21085 + FS_REQUIRES_DEV);
21086 +#endif
21087 +
21088 +#endif /* CONFIG_YAFFS_YAFFS2 */
21089 +
21090 +static struct proc_dir_entry *my_proc_entry;
21091 +static struct proc_dir_entry *debug_proc_entry;
21092 +
21093 +static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
21094 +{
21095 + buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
21096 + buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
21097 + buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
21098 + buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
21099 + buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
21100 + buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
21101 + buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
21102 + buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
21103 + buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
21104 + buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
21105 + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
21106 + buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks);
21107 + buf += sprintf(buf, "alwaysCheckErased.. %d\n", dev->param.alwaysCheckErased);
21108 +
21109 + buf += sprintf(buf, "\n");
21110 +
21111 + return buf;
21112 +}
21113 +
21114 +
21115 +static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
21116 +{
21117 + buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
21118 + buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
21119 + buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
21120 + buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
21121 + buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
21122 + buf += sprintf(buf, "\n");
21123 + buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
21124 + buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
21125 + buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
21126 + buf += sprintf(buf, "\n");
21127 + buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
21128 + buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
21129 + buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
21130 + buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
21131 + buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
21132 + buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
21133 + buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
21134 + buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks);
21135 + buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
21136 + buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
21137 + buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
21138 + buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
21139 + buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed);
21140 + buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed);
21141 + buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed);
21142 + buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits);
21143 + buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles);
21144 + buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles);
21145 + buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount);
21146 + buf +=
21147 + sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions);
21148 +
21149 + return buf;
21150 +}
21151 +
21152 +static int yaffs_proc_read(char *page,
21153 + char **start,
21154 + off_t offset, int count, int *eof, void *data)
21155 +{
21156 + struct ylist_head *item;
21157 + char *buf = page;
21158 + int step = offset;
21159 + int n = 0;
21160 +
21161 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
21162 + * We use 'offset' (*ppos) to indicate where we are in devList.
21163 + * This also assumes the user has posted a read buffer large
21164 + * enough to hold the complete output; but that's life in /proc.
21165 + */
21166 +
21167 + *(int *)start = 1;
21168 +
21169 + /* Print header first */
21170 + if (step == 0)
21171 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
21172 + else if (step == 1)
21173 + buf += sprintf(buf,"\n");
21174 + else {
21175 + step-=2;
21176 +
21177 + down(&yaffs_context_lock);
21178 +
21179 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21180 + ylist_for_each(item, &yaffs_context_list) {
21181 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21182 + yaffs_Device *dev = dc->dev;
21183 +
21184 + if (n < (step & ~1)) {
21185 + n+=2;
21186 + continue;
21187 + }
21188 + if((step & 1)==0){
21189 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
21190 + buf = yaffs_dump_dev_part0(buf, dev);
21191 + } else
21192 + buf = yaffs_dump_dev_part1(buf, dev);
21193 +
21194 + break;
21195 + }
21196 + up(&yaffs_context_lock);
21197 + }
21198 +
21199 + return buf - page < count ? buf - page : count;
21200 +}
21201 +
21202 +static int yaffs_stats_proc_read(char *page,
21203 + char **start,
21204 + off_t offset, int count, int *eof, void *data)
21205 +{
21206 + struct ylist_head *item;
21207 + char *buf = page;
21208 + int n = 0;
21209 +
21210 + down(&yaffs_context_lock);
21211 +
21212 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21213 + ylist_for_each(item, &yaffs_context_list) {
21214 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21215 + yaffs_Device *dev = dc->dev;
21216 +
21217 + int erasedChunks;
21218 +
21219 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
21220 +
21221 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
21222 + n, dev->nFreeChunks, erasedChunks,
21223 + dev->backgroundGCs, dev->oldestDirtyGCs,
21224 + dev->nObjects, dev->nTnodes);
21225 + }
21226 + up(&yaffs_context_lock);
21227 +
21228 +
21229 + return buf - page < count ? buf - page : count;
21230 +}
21231 +
21232 +/**
21233 + * Set the verbosity of the warnings and error messages.
21234 + *
21235 + * Note that the names can only be a..z or _ with the current code.
21236 + */
21237 +
21238 +static struct {
21239 + char *mask_name;
21240 + unsigned mask_bitfield;
21241 +} mask_flags[] = {
21242 + {"allocate", YAFFS_TRACE_ALLOCATE},
21243 + {"always", YAFFS_TRACE_ALWAYS},
21244 + {"background", YAFFS_TRACE_BACKGROUND},
21245 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
21246 + {"buffers", YAFFS_TRACE_BUFFERS},
21247 + {"bug", YAFFS_TRACE_BUG},
21248 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
21249 + {"deletion", YAFFS_TRACE_DELETION},
21250 + {"erase", YAFFS_TRACE_ERASE},
21251 + {"error", YAFFS_TRACE_ERROR},
21252 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
21253 + {"gc", YAFFS_TRACE_GC},
21254 + {"lock", YAFFS_TRACE_LOCK},
21255 + {"mtd", YAFFS_TRACE_MTD},
21256 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
21257 + {"os", YAFFS_TRACE_OS},
21258 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
21259 + {"scan", YAFFS_TRACE_SCAN},
21260 + {"tracing", YAFFS_TRACE_TRACING},
21261 + {"sync", YAFFS_TRACE_SYNC},
21262 + {"write", YAFFS_TRACE_WRITE},
21263 +
21264 + {"verify", YAFFS_TRACE_VERIFY},
21265 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
21266 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
21267 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
21268 +
21269 + {"all", 0xffffffff},
21270 + {"none", 0},
21271 + {NULL, 0},
21272 +};
21273 +
21274 +#define MAX_MASK_NAME_LENGTH 40
21275 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
21276 + unsigned long count, void *data)
21277 +{
21278 + unsigned rg = 0, mask_bitfield;
21279 + char *end;
21280 + char *mask_name;
21281 + const char *x;
21282 + char substring[MAX_MASK_NAME_LENGTH + 1];
21283 + int i;
21284 + int done = 0;
21285 + int add, len = 0;
21286 + int pos = 0;
21287 +
21288 + rg = yaffs_traceMask;
21289 +
21290 + while (!done && (pos < count)) {
21291 + done = 1;
21292 + while ((pos < count) && isspace(buf[pos]))
21293 + pos++;
21294 +
21295 + switch (buf[pos]) {
21296 + case '+':
21297 + case '-':
21298 + case '=':
21299 + add = buf[pos];
21300 + pos++;
21301 + break;
21302 +
21303 + default:
21304 + add = ' ';
21305 + break;
21306 + }
21307 + mask_name = NULL;
21308 +
21309 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
21310 +
21311 + if (end > buf + pos) {
21312 + mask_name = "numeral";
21313 + len = end - (buf + pos);
21314 + pos += len;
21315 + done = 0;
21316 + } else {
21317 + for (x = buf + pos, i = 0;
21318 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
21319 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
21320 + substring[i] = *x;
21321 + substring[i] = '\0';
21322 +
21323 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21324 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
21325 + mask_name = mask_flags[i].mask_name;
21326 + mask_bitfield = mask_flags[i].mask_bitfield;
21327 + done = 0;
21328 + break;
21329 + }
21330 + }
21331 + }
21332 +
21333 + if (mask_name != NULL) {
21334 + done = 0;
21335 + switch (add) {
21336 + case '-':
21337 + rg &= ~mask_bitfield;
21338 + break;
21339 + case '+':
21340 + rg |= mask_bitfield;
21341 + break;
21342 + case '=':
21343 + rg = mask_bitfield;
21344 + break;
21345 + default:
21346 + rg |= mask_bitfield;
21347 + break;
21348 + }
21349 + }
21350 + }
21351 +
21352 + yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
21353 +
21354 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
21355 +
21356 + if (rg & YAFFS_TRACE_ALWAYS) {
21357 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21358 + char flag;
21359 + flag = ((rg & mask_flags[i].mask_bitfield) ==
21360 + mask_flags[i].mask_bitfield) ? '+' : '-';
21361 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
21362 + }
21363 + }
21364 +
21365 + return count;
21366 +}
21367 +
21368 +
21369 +static int yaffs_proc_write(struct file *file, const char *buf,
21370 + unsigned long count, void *data)
21371 +{
21372 + return yaffs_proc_write_trace_options(file, buf, count, data);
21373 +}
21374 +
21375 +/* Stuff to handle installation of file systems */
21376 +struct file_system_to_install {
21377 + struct file_system_type *fst;
21378 + int installed;
21379 +};
21380 +
21381 +static struct file_system_to_install fs_to_install[] = {
21382 + {&yaffs_fs_type, 0},
21383 + {&yaffs2_fs_type, 0},
21384 + {NULL, 0}
21385 +};
21386 +
21387 +static int __init init_yaffs_fs(void)
21388 +{
21389 + int error = 0;
21390 + struct file_system_to_install *fsinst;
21391 +
21392 + T(YAFFS_TRACE_ALWAYS,
21393 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
21394 +
21395 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
21396 + T(YAFFS_TRACE_ALWAYS,
21397 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
21398 +#endif
21399 +
21400 +
21401 +
21402 +
21403 + init_MUTEX(&yaffs_context_lock);
21404 +
21405 + /* Install the proc_fs entries */
21406 + my_proc_entry = create_proc_entry("yaffs",
21407 + S_IRUGO | S_IFREG,
21408 + YPROC_ROOT);
21409 +
21410 + if (my_proc_entry) {
21411 + my_proc_entry->write_proc = yaffs_proc_write;
21412 + my_proc_entry->read_proc = yaffs_proc_read;
21413 + my_proc_entry->data = NULL;
21414 + } else
21415 + return -ENOMEM;
21416 +
21417 + debug_proc_entry = create_proc_entry("yaffs_stats",
21418 + S_IRUGO | S_IFREG,
21419 + YPROC_ROOT);
21420 +
21421 + if (debug_proc_entry) {
21422 + debug_proc_entry->write_proc = NULL;
21423 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
21424 + debug_proc_entry->data = NULL;
21425 + } else
21426 + return -ENOMEM;
21427 +
21428 + /* Now add the file system entries */
21429 +
21430 + fsinst = fs_to_install;
21431 +
21432 + while (fsinst->fst && !error) {
21433 + error = register_filesystem(fsinst->fst);
21434 + if (!error)
21435 + fsinst->installed = 1;
21436 + fsinst++;
21437 + }
21438 +
21439 + /* Any errors? uninstall */
21440 + if (error) {
21441 + fsinst = fs_to_install;
21442 +
21443 + while (fsinst->fst) {
21444 + if (fsinst->installed) {
21445 + unregister_filesystem(fsinst->fst);
21446 + fsinst->installed = 0;
21447 + }
21448 + fsinst++;
21449 + }
21450 + }
21451 +
21452 + return error;
21453 +}
21454 +
21455 +static void __exit exit_yaffs_fs(void)
21456 +{
21457 +
21458 + struct file_system_to_install *fsinst;
21459 +
21460 + T(YAFFS_TRACE_ALWAYS,
21461 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
21462 +
21463 + remove_proc_entry("yaffs", YPROC_ROOT);
21464 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
21465 +
21466 + fsinst = fs_to_install;
21467 +
21468 + while (fsinst->fst) {
21469 + if (fsinst->installed) {
21470 + unregister_filesystem(fsinst->fst);
21471 + fsinst->installed = 0;
21472 + }
21473 + fsinst++;
21474 + }
21475 +}
21476 +
21477 +module_init(init_yaffs_fs)
21478 +module_exit(exit_yaffs_fs)
21479 +
21480 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
21481 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
21482 +MODULE_LICENSE("GPL");
21483 --- /dev/null
21484 +++ b/fs/yaffs2/yaffs_yaffs1.c
21485 @@ -0,0 +1,465 @@
21486 +/*
21487 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21488 + *
21489 + * Copyright (C) 2002-2010 Aleph One Ltd.
21490 + * for Toby Churchill Ltd and Brightstar Engineering
21491 + *
21492 + * Created by Charles Manning <charles@aleph1.co.uk>
21493 + *
21494 + * This program is free software; you can redistribute it and/or modify
21495 + * it under the terms of the GNU General Public License version 2 as
21496 + * published by the Free Software Foundation.
21497 + */
21498 +#include "yaffs_yaffs1.h"
21499 +#include "yportenv.h"
21500 +#include "yaffs_trace.h"
21501 +#include "yaffs_bitmap.h"
21502 +#include "yaffs_getblockinfo.h"
21503 +#include "yaffs_nand.h"
21504 +
21505 +
21506 +int yaffs1_Scan(yaffs_Device *dev)
21507 +{
21508 + yaffs_ExtendedTags tags;
21509 + int blk;
21510 + int blockIterator;
21511 + int startIterator;
21512 + int endIterator;
21513 + int result;
21514 +
21515 + int chunk;
21516 + int c;
21517 + int deleted;
21518 + yaffs_BlockState state;
21519 + yaffs_Object *hardList = NULL;
21520 + yaffs_BlockInfo *bi;
21521 + __u32 sequenceNumber;
21522 + yaffs_ObjectHeader *oh;
21523 + yaffs_Object *in;
21524 + yaffs_Object *parent;
21525 +
21526 + int alloc_failed = 0;
21527 +
21528 + struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
21529 +
21530 +
21531 + __u8 *chunkData;
21532 +
21533 +
21534 +
21535 + T(YAFFS_TRACE_SCAN,
21536 + (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
21537 + dev->internalStartBlock, dev->internalEndBlock));
21538 +
21539 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
21540 +
21541 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
21542 +
21543 + /* Scan all the blocks to determine their state */
21544 + bi = dev->blockInfo;
21545 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
21546 + yaffs_ClearChunkBits(dev, blk);
21547 + bi->pagesInUse = 0;
21548 + bi->softDeletions = 0;
21549 +
21550 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
21551 +
21552 + bi->blockState = state;
21553 + bi->sequenceNumber = sequenceNumber;
21554 +
21555 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
21556 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
21557 +
21558 + T(YAFFS_TRACE_SCAN_DEBUG,
21559 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
21560 + state, sequenceNumber));
21561 +
21562 + if (state == YAFFS_BLOCK_STATE_DEAD) {
21563 + T(YAFFS_TRACE_BAD_BLOCKS,
21564 + (TSTR("block %d is bad" TENDSTR), blk));
21565 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
21566 + T(YAFFS_TRACE_SCAN_DEBUG,
21567 + (TSTR("Block empty " TENDSTR)));
21568 + dev->nErasedBlocks++;
21569 + dev->nFreeChunks += dev->param.nChunksPerBlock;
21570 + }
21571 + bi++;
21572 + }
21573 +
21574 + startIterator = dev->internalStartBlock;
21575 + endIterator = dev->internalEndBlock;
21576 +
21577 + /* For each block.... */
21578 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
21579 + blockIterator++) {
21580 +
21581 + YYIELD();
21582 +
21583 + YYIELD();
21584 +
21585 + blk = blockIterator;
21586 +
21587 + bi = yaffs_GetBlockInfo(dev, blk);
21588 + state = bi->blockState;
21589 +
21590 + deleted = 0;
21591 +
21592 + /* For each chunk in each block that needs scanning....*/
21593 + for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&
21594 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
21595 + /* Read the tags and decide what to do */
21596 + chunk = blk * dev->param.nChunksPerBlock + c;
21597 +
21598 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
21599 + &tags);
21600 +
21601 + /* Let's have a good look at this chunk... */
21602 +
21603 + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
21604 + /* YAFFS1 only...
21605 + * A deleted chunk
21606 + */
21607 + deleted++;
21608 + dev->nFreeChunks++;
21609 + /*T((" %d %d deleted\n",blk,c)); */
21610 + } else if (!tags.chunkUsed) {
21611 + /* An unassigned chunk in the block
21612 + * This means that either the block is empty or
21613 + * this is the one being allocated from
21614 + */
21615 +
21616 + if (c == 0) {
21617 + /* We're looking at the first chunk in the block so the block is unused */
21618 + state = YAFFS_BLOCK_STATE_EMPTY;
21619 + dev->nErasedBlocks++;
21620 + } else {
21621 + /* this is the block being allocated from */
21622 + T(YAFFS_TRACE_SCAN,
21623 + (TSTR
21624 + (" Allocating from %d %d" TENDSTR),
21625 + blk, c));
21626 + state = YAFFS_BLOCK_STATE_ALLOCATING;
21627 + dev->allocationBlock = blk;
21628 + dev->allocationPage = c;
21629 + dev->allocationBlockFinder = blk;
21630 + /* Set block finder here to encourage the allocator to go forth from here. */
21631 +
21632 + }
21633 +
21634 + dev->nFreeChunks += (dev->param.nChunksPerBlock - c);
21635 + } else if (tags.chunkId > 0) {
21636 + /* chunkId > 0 so it is a data chunk... */
21637 + unsigned int endpos;
21638 +
21639 + yaffs_SetChunkBit(dev, blk, c);
21640 + bi->pagesInUse++;
21641 +
21642 + in = yaffs_FindOrCreateObjectByNumber(dev,
21643 + tags.
21644 + objectId,
21645 + YAFFS_OBJECT_TYPE_FILE);
21646 + /* PutChunkIntoFile checks for a clash (two data chunks with
21647 + * the same chunkId).
21648 + */
21649 +
21650 + if (!in)
21651 + alloc_failed = 1;
21652 +
21653 + if (in) {
21654 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
21655 + alloc_failed = 1;
21656 + }
21657 +
21658 + endpos =
21659 + (tags.chunkId - 1) * dev->nDataBytesPerChunk +
21660 + tags.byteCount;
21661 + if (in &&
21662 + in->variantType == YAFFS_OBJECT_TYPE_FILE
21663 + && in->variant.fileVariant.scannedFileSize <
21664 + endpos) {
21665 + in->variant.fileVariant.
21666 + scannedFileSize = endpos;
21667 + if (!dev->param.useHeaderFileSize) {
21668 + in->variant.fileVariant.
21669 + fileSize =
21670 + in->variant.fileVariant.
21671 + scannedFileSize;
21672 + }
21673 +
21674 + }
21675 + /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
21676 + } else {
21677 + /* chunkId == 0, so it is an ObjectHeader.
21678 + * Thus, we read in the object header and make the object
21679 + */
21680 + yaffs_SetChunkBit(dev, blk, c);
21681 + bi->pagesInUse++;
21682 +
21683 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
21684 + chunkData,
21685 + NULL);
21686 +
21687 + oh = (yaffs_ObjectHeader *) chunkData;
21688 +
21689 + in = yaffs_FindObjectByNumber(dev,
21690 + tags.objectId);
21691 + if (in && in->variantType != oh->type) {
21692 + /* This should not happen, but somehow
21693 + * Wev'e ended up with an objectId that has been reused but not yet
21694 + * deleted, and worse still it has changed type. Delete the old object.
21695 + */
21696 +
21697 + yaffs_DeleteObject(in);
21698 +
21699 + in = 0;
21700 + }
21701 +
21702 + in = yaffs_FindOrCreateObjectByNumber(dev,
21703 + tags.
21704 + objectId,
21705 + oh->type);
21706 +
21707 + if (!in)
21708 + alloc_failed = 1;
21709 +
21710 + if (in && oh->shadowsObject > 0) {
21711 +
21712 + struct yaffs_ShadowFixerStruct *fixer;
21713 + fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
21714 + if (fixer) {
21715 + fixer->next = shadowFixerList;
21716 + shadowFixerList = fixer;
21717 + fixer->objectId = tags.objectId;
21718 + fixer->shadowedId = oh->shadowsObject;
21719 + T(YAFFS_TRACE_SCAN,
21720 + (TSTR
21721 + (" Shadow fixer: %d shadows %d" TENDSTR),
21722 + fixer->objectId, fixer->shadowedId));
21723 +
21724 + }
21725 +
21726 + }
21727 +
21728 + if (in && in->valid) {
21729 + /* We have already filled this one. We have a duplicate and need to resolve it. */
21730 +
21731 + unsigned existingSerial = in->serial;
21732 + unsigned newSerial = tags.serialNumber;
21733 +
21734 + if (((existingSerial + 1) & 3) == newSerial) {
21735 + /* Use new one - destroy the exisiting one */
21736 + yaffs_DeleteChunk(dev,
21737 + in->hdrChunk,
21738 + 1, __LINE__);
21739 + in->valid = 0;
21740 + } else {
21741 + /* Use existing - destroy this one. */
21742 + yaffs_DeleteChunk(dev, chunk, 1,
21743 + __LINE__);
21744 + }
21745 + }
21746 +
21747 + if (in && !in->valid &&
21748 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
21749 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
21750 + /* We only load some info, don't fiddle with directory structure */
21751 + in->valid = 1;
21752 + in->variantType = oh->type;
21753 +
21754 + in->yst_mode = oh->yst_mode;
21755 +#ifdef CONFIG_YAFFS_WINCE
21756 + in->win_atime[0] = oh->win_atime[0];
21757 + in->win_ctime[0] = oh->win_ctime[0];
21758 + in->win_mtime[0] = oh->win_mtime[0];
21759 + in->win_atime[1] = oh->win_atime[1];
21760 + in->win_ctime[1] = oh->win_ctime[1];
21761 + in->win_mtime[1] = oh->win_mtime[1];
21762 +#else
21763 + in->yst_uid = oh->yst_uid;
21764 + in->yst_gid = oh->yst_gid;
21765 + in->yst_atime = oh->yst_atime;
21766 + in->yst_mtime = oh->yst_mtime;
21767 + in->yst_ctime = oh->yst_ctime;
21768 + in->yst_rdev = oh->yst_rdev;
21769 +#endif
21770 + in->hdrChunk = chunk;
21771 + in->serial = tags.serialNumber;
21772 +
21773 + } else if (in && !in->valid) {
21774 + /* we need to load this info */
21775 +
21776 + in->valid = 1;
21777 + in->variantType = oh->type;
21778 +
21779 + in->yst_mode = oh->yst_mode;
21780 +#ifdef CONFIG_YAFFS_WINCE
21781 + in->win_atime[0] = oh->win_atime[0];
21782 + in->win_ctime[0] = oh->win_ctime[0];
21783 + in->win_mtime[0] = oh->win_mtime[0];
21784 + in->win_atime[1] = oh->win_atime[1];
21785 + in->win_ctime[1] = oh->win_ctime[1];
21786 + in->win_mtime[1] = oh->win_mtime[1];
21787 +#else
21788 + in->yst_uid = oh->yst_uid;
21789 + in->yst_gid = oh->yst_gid;
21790 + in->yst_atime = oh->yst_atime;
21791 + in->yst_mtime = oh->yst_mtime;
21792 + in->yst_ctime = oh->yst_ctime;
21793 + in->yst_rdev = oh->yst_rdev;
21794 +#endif
21795 + in->hdrChunk = chunk;
21796 + in->serial = tags.serialNumber;
21797 +
21798 + yaffs_SetObjectNameFromOH(in, oh);
21799 + in->dirty = 0;
21800 +
21801 + /* directory stuff...
21802 + * hook up to parent
21803 + */
21804 +
21805 + parent =
21806 + yaffs_FindOrCreateObjectByNumber
21807 + (dev, oh->parentObjectId,
21808 + YAFFS_OBJECT_TYPE_DIRECTORY);
21809 + if (!parent)
21810 + alloc_failed = 1;
21811 + if (parent && parent->variantType ==
21812 + YAFFS_OBJECT_TYPE_UNKNOWN) {
21813 + /* Set up as a directory */
21814 + parent->variantType =
21815 + YAFFS_OBJECT_TYPE_DIRECTORY;
21816 + YINIT_LIST_HEAD(&parent->variant.
21817 + directoryVariant.
21818 + children);
21819 + } else if (!parent || parent->variantType !=
21820 + YAFFS_OBJECT_TYPE_DIRECTORY) {
21821 + /* Hoosterman, another problem....
21822 + * We're trying to use a non-directory as a directory
21823 + */
21824 +
21825 + T(YAFFS_TRACE_ERROR,
21826 + (TSTR
21827 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
21828 + TENDSTR)));
21829 + parent = dev->lostNFoundDir;
21830 + }
21831 +
21832 + yaffs_AddObjectToDirectory(parent, in);
21833 +
21834 + if (0 && (parent == dev->deletedDir ||
21835 + parent == dev->unlinkedDir)) {
21836 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
21837 + dev->nDeletedFiles++;
21838 + }
21839 + /* Note re hardlinks.
21840 + * Since we might scan a hardlink before its equivalent object is scanned
21841 + * we put them all in a list.
21842 + * After scanning is complete, we should have all the objects, so we run through this
21843 + * list and fix up all the chains.
21844 + */
21845 +
21846 + switch (in->variantType) {
21847 + case YAFFS_OBJECT_TYPE_UNKNOWN:
21848 + /* Todo got a problem */
21849 + break;
21850 + case YAFFS_OBJECT_TYPE_FILE:
21851 + if (dev->param.useHeaderFileSize)
21852 +
21853 + in->variant.fileVariant.
21854 + fileSize =
21855 + oh->fileSize;
21856 +
21857 + break;
21858 + case YAFFS_OBJECT_TYPE_HARDLINK:
21859 + in->variant.hardLinkVariant.
21860 + equivalentObjectId =
21861 + oh->equivalentObjectId;
21862 + in->hardLinks.next =
21863 + (struct ylist_head *)
21864 + hardList;
21865 + hardList = in;
21866 + break;
21867 + case YAFFS_OBJECT_TYPE_DIRECTORY:
21868 + /* Do nothing */
21869 + break;
21870 + case YAFFS_OBJECT_TYPE_SPECIAL:
21871 + /* Do nothing */
21872 + break;
21873 + case YAFFS_OBJECT_TYPE_SYMLINK:
21874 + in->variant.symLinkVariant.alias =
21875 + yaffs_CloneString(oh->alias);
21876 + if (!in->variant.symLinkVariant.alias)
21877 + alloc_failed = 1;
21878 + break;
21879 + }
21880 +
21881 + }
21882 + }
21883 + }
21884 +
21885 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
21886 + /* If we got this far while scanning, then the block is fully allocated.*/
21887 + state = YAFFS_BLOCK_STATE_FULL;
21888 + }
21889 +
21890 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
21891 + /* If the block was partially allocated then treat it as fully allocated.*/
21892 + state = YAFFS_BLOCK_STATE_FULL;
21893 + dev->allocationBlock = -1;
21894 + }
21895 +
21896 + bi->blockState = state;
21897 +
21898 + /* Now let's see if it was dirty */
21899 + if (bi->pagesInUse == 0 &&
21900 + !bi->hasShrinkHeader &&
21901 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
21902 + yaffs_BlockBecameDirty(dev, blk);
21903 + }
21904 +
21905 + }
21906 +
21907 +
21908 + /* Ok, we've done all the scanning.
21909 + * Fix up the hard link chains.
21910 + * We should now have scanned all the objects, now it's time to add these
21911 + * hardlinks.
21912 + */
21913 +
21914 + yaffs_HardlinkFixup(dev, hardList);
21915 +
21916 + /* Fix up any shadowed objects */
21917 + {
21918 + struct yaffs_ShadowFixerStruct *fixer;
21919 + yaffs_Object *obj;
21920 +
21921 + while (shadowFixerList) {
21922 + fixer = shadowFixerList;
21923 + shadowFixerList = fixer->next;
21924 + /* Complete the rename transaction by deleting the shadowed object
21925 + * then setting the object header to unshadowed.
21926 + */
21927 + obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
21928 + if (obj)
21929 + yaffs_DeleteObject(obj);
21930 +
21931 + obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
21932 +
21933 + if (obj)
21934 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
21935 +
21936 + YFREE(fixer);
21937 + }
21938 + }
21939 +
21940 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
21941 +
21942 + if (alloc_failed)
21943 + return YAFFS_FAIL;
21944 +
21945 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
21946 +
21947 +
21948 + return YAFFS_OK;
21949 +}
21950 +
21951 --- /dev/null
21952 +++ b/fs/yaffs2/yaffs_yaffs1.h
21953 @@ -0,0 +1,22 @@
21954 +/*
21955 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
21956 + *
21957 + * Copyright (C) 2002-2010 Aleph One Ltd.
21958 + * for Toby Churchill Ltd and Brightstar Engineering
21959 + *
21960 + * Created by Charles Manning <charles@aleph1.co.uk>
21961 + *
21962 + * This program is free software; you can redistribute it and/or modify
21963 + * it under the terms of the GNU Lesser General Public License version 2.1 as
21964 + * published by the Free Software Foundation.
21965 + *
21966 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
21967 + */
21968 +
21969 +#ifndef __YAFFS_YAFFS1_H__
21970 +#define __YAFFS_YAFFS1_H__
21971 +
21972 +#include "yaffs_guts.h"
21973 +int yaffs1_Scan(yaffs_Device *dev);
21974 +
21975 +#endif
21976 --- /dev/null
21977 +++ b/fs/yaffs2/yaffs_yaffs2.c
21978 @@ -0,0 +1,1540 @@
21979 +/*
21980 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21981 + *
21982 + * Copyright (C) 2002-2010 Aleph One Ltd.
21983 + * for Toby Churchill Ltd and Brightstar Engineering
21984 + *
21985 + * Created by Charles Manning <charles@aleph1.co.uk>
21986 + *
21987 + * This program is free software; you can redistribute it and/or modify
21988 + * it under the terms of the GNU General Public License version 2 as
21989 + * published by the Free Software Foundation.
21990 + */
21991 +
21992 +
21993 +#include "yaffs_guts.h"
21994 +#include "yaffs_trace.h"
21995 +#include "yaffs_yaffs2.h"
21996 +#include "yaffs_checkptrw.h"
21997 +#include "yaffs_bitmap.h"
21998 +#include "yaffs_qsort.h"
21999 +#include "yaffs_nand.h"
22000 +#include "yaffs_getblockinfo.h"
22001 +#include "yaffs_verify.h"
22002 +
22003 +/*
22004 + * Checkpoints are really no benefit on very small partitions.
22005 + *
22006 + * To save space on small partitions don't bother with checkpoints unless
22007 + * the partition is at least this big.
22008 + */
22009 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
22010 +
22011 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
22012 +
22013 +
22014 +/*
22015 + * Oldest Dirty Sequence Number handling.
22016 + */
22017 +
22018 +/* yaffs2_CalcOldestDirtySequence()
22019 + * yaffs2_FindOldestDirtySequence()
22020 + * Calculate the oldest dirty sequence number if we don't know it.
22021 + */
22022 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
22023 +{
22024 + int i;
22025 + unsigned seq;
22026 + unsigned blockNo = 0;
22027 + yaffs_BlockInfo *b;
22028 +
22029 + if(!dev->param.isYaffs2)
22030 + return;
22031 +
22032 + /* Find the oldest dirty sequence number. */
22033 + seq = dev->sequenceNumber + 1;
22034 + b = dev->blockInfo;
22035 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
22036 + if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
22037 + (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock &&
22038 + b->sequenceNumber < seq) {
22039 + seq = b->sequenceNumber;
22040 + blockNo = i;
22041 + }
22042 + b++;
22043 + }
22044 +
22045 + if(blockNo){
22046 + dev->oldestDirtySequence = seq;
22047 + dev->oldestDirtyBlock = blockNo;
22048 + }
22049 +
22050 +}
22051 +
22052 +
22053 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
22054 +{
22055 + if(!dev->param.isYaffs2)
22056 + return;
22057 +
22058 + if(!dev->oldestDirtySequence)
22059 + yaffs2_CalcOldestDirtySequence(dev);
22060 +}
22061 +
22062 +/*
22063 + * yaffs_ClearOldestDirtySequence()
22064 + * Called when a block is erased or marked bad. (ie. when its sequenceNumber
22065 + * becomes invalid). If the value matches the oldest then we clear
22066 + * dev->oldestDirtySequence to force its recomputation.
22067 + */
22068 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
22069 +{
22070 +
22071 + if(!dev->param.isYaffs2)
22072 + return;
22073 +
22074 + if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
22075 + dev->oldestDirtySequence = 0;
22076 + dev->oldestDirtyBlock = 0;
22077 + }
22078 +}
22079 +
22080 +/*
22081 + * yaffs2_UpdateOldestDirtySequence()
22082 + * Update the oldest dirty sequence number whenever we dirty a block.
22083 + * Only do this if the oldestDirtySequence is actually being tracked.
22084 + */
22085 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
22086 +{
22087 + if(!dev->param.isYaffs2)
22088 + return;
22089 +
22090 + if(dev->oldestDirtySequence){
22091 + if(dev->oldestDirtySequence > bi->sequenceNumber){
22092 + dev->oldestDirtySequence = bi->sequenceNumber;
22093 + dev->oldestDirtyBlock = blockNo;
22094 + }
22095 + }
22096 +}
22097 +
22098 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
22099 + yaffs_BlockInfo *bi)
22100 +{
22101 +
22102 + if (!dev->param.isYaffs2)
22103 + return 1; /* disqualification only applies to yaffs2. */
22104 +
22105 + if (!bi->hasShrinkHeader)
22106 + return 1; /* can gc */
22107 +
22108 + yaffs2_FindOldestDirtySequence(dev);
22109 +
22110 + /* Can't do gc of this block if there are any blocks older than this one that have
22111 + * discarded pages.
22112 + */
22113 + return (bi->sequenceNumber <= dev->oldestDirtySequence);
22114 +}
22115 +
22116 +/*
22117 + * yaffs2_FindRefreshBlock()
22118 + * periodically finds the oldest full block by sequence number for refreshing.
22119 + * Only for yaffs2.
22120 + */
22121 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
22122 +{
22123 + __u32 b ;
22124 +
22125 + __u32 oldest = 0;
22126 + __u32 oldestSequence = 0;
22127 +
22128 + yaffs_BlockInfo *bi;
22129 +
22130 + if(!dev->param.isYaffs2)
22131 + return oldest;
22132 +
22133 + /*
22134 + * If refresh period < 10 then refreshing is disabled.
22135 + */
22136 + if(dev->param.refreshPeriod < 10)
22137 + return oldest;
22138 +
22139 + /*
22140 + * Fix broken values.
22141 + */
22142 + if(dev->refreshSkip > dev->param.refreshPeriod)
22143 + dev->refreshSkip = dev->param.refreshPeriod;
22144 +
22145 + if(dev->refreshSkip > 0)
22146 + return oldest;
22147 +
22148 + /*
22149 + * Refresh skip is now zero.
22150 + * We'll do a refresh this time around....
22151 + * Update the refresh skip and find the oldest block.
22152 + */
22153 + dev->refreshSkip = dev->param.refreshPeriod;
22154 + dev->refreshCount++;
22155 + bi = dev->blockInfo;
22156 + for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
22157 +
22158 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
22159 +
22160 + if(oldest < 1 ||
22161 + bi->sequenceNumber < oldestSequence){
22162 + oldest = b;
22163 + oldestSequence = bi->sequenceNumber;
22164 + }
22165 + }
22166 + bi++;
22167 + }
22168 +
22169 + if (oldest > 0) {
22170 + T(YAFFS_TRACE_GC,
22171 + (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
22172 + dev->refreshCount, oldest, oldestSequence));
22173 + }
22174 +
22175 + return oldest;
22176 +}
22177 +
22178 +int yaffs2_CheckpointRequired(yaffs_Device *dev)
22179 +{
22180 + int nblocks;
22181 +
22182 + if(!dev->param.isYaffs2)
22183 + return 0;
22184 +
22185 + nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
22186 +
22187 + return !dev->param.skipCheckpointWrite &&
22188 + !dev->readOnly &&
22189 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
22190 +}
22191 +
22192 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
22193 +{
22194 + int retval;
22195 +
22196 + if(!dev->param.isYaffs2)
22197 + return 0;
22198 +
22199 + if (!dev->nCheckpointBlocksRequired &&
22200 + yaffs2_CheckpointRequired(dev)){
22201 + /* Not a valid value so recalculate */
22202 + int nBytes = 0;
22203 + int nBlocks;
22204 + int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
22205 +
22206 + nBytes += sizeof(yaffs_CheckpointValidity);
22207 + nBytes += sizeof(yaffs_CheckpointDevice);
22208 + nBytes += devBlocks * sizeof(yaffs_BlockInfo);
22209 + nBytes += devBlocks * dev->chunkBitmapStride;
22210 + nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
22211 + nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
22212 + nBytes += sizeof(yaffs_CheckpointValidity);
22213 + nBytes += sizeof(__u32); /* checksum*/
22214 +
22215 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
22216 +
22217 + nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
22218 +
22219 + dev->nCheckpointBlocksRequired = nBlocks;
22220 + }
22221 +
22222 + retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
22223 + if(retval < 0)
22224 + retval = 0;
22225 + return retval;
22226 +}
22227 +
22228 +/*--------------------- Checkpointing --------------------*/
22229 +
22230 +
22231 +static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
22232 +{
22233 + yaffs_CheckpointValidity cp;
22234 +
22235 + memset(&cp, 0, sizeof(cp));
22236 +
22237 + cp.structType = sizeof(cp);
22238 + cp.magic = YAFFS_MAGIC;
22239 + cp.version = YAFFS_CHECKPOINT_VERSION;
22240 + cp.head = (head) ? 1 : 0;
22241 +
22242 + return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
22243 + 1 : 0;
22244 +}
22245 +
22246 +static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
22247 +{
22248 + yaffs_CheckpointValidity cp;
22249 + int ok;
22250 +
22251 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22252 +
22253 + if (ok)
22254 + ok = (cp.structType == sizeof(cp)) &&
22255 + (cp.magic == YAFFS_MAGIC) &&
22256 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
22257 + (cp.head == ((head) ? 1 : 0));
22258 + return ok ? 1 : 0;
22259 +}
22260 +
22261 +static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
22262 + yaffs_Device *dev)
22263 +{
22264 + cp->nErasedBlocks = dev->nErasedBlocks;
22265 + cp->allocationBlock = dev->allocationBlock;
22266 + cp->allocationPage = dev->allocationPage;
22267 + cp->nFreeChunks = dev->nFreeChunks;
22268 +
22269 + cp->nDeletedFiles = dev->nDeletedFiles;
22270 + cp->nUnlinkedFiles = dev->nUnlinkedFiles;
22271 + cp->nBackgroundDeletions = dev->nBackgroundDeletions;
22272 + cp->sequenceNumber = dev->sequenceNumber;
22273 +
22274 +}
22275 +
22276 +static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
22277 + yaffs_CheckpointDevice *cp)
22278 +{
22279 + dev->nErasedBlocks = cp->nErasedBlocks;
22280 + dev->allocationBlock = cp->allocationBlock;
22281 + dev->allocationPage = cp->allocationPage;
22282 + dev->nFreeChunks = cp->nFreeChunks;
22283 +
22284 + dev->nDeletedFiles = cp->nDeletedFiles;
22285 + dev->nUnlinkedFiles = cp->nUnlinkedFiles;
22286 + dev->nBackgroundDeletions = cp->nBackgroundDeletions;
22287 + dev->sequenceNumber = cp->sequenceNumber;
22288 +}
22289 +
22290 +
22291 +static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
22292 +{
22293 + yaffs_CheckpointDevice cp;
22294 + __u32 nBytes;
22295 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22296 +
22297 + int ok;
22298 +
22299 + /* Write device runtime values*/
22300 + yaffs2_DeviceToCheckpointDevice(&cp, dev);
22301 + cp.structType = sizeof(cp);
22302 +
22303 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22304 +
22305 + /* Write block info */
22306 + if (ok) {
22307 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22308 + ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
22309 + }
22310 +
22311 + /* Write chunk bits */
22312 + if (ok) {
22313 + nBytes = nBlocks * dev->chunkBitmapStride;
22314 + ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
22315 + }
22316 + return ok ? 1 : 0;
22317 +
22318 +}
22319 +
22320 +static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
22321 +{
22322 + yaffs_CheckpointDevice cp;
22323 + __u32 nBytes;
22324 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22325 +
22326 + int ok;
22327 +
22328 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22329 + if (!ok)
22330 + return 0;
22331 +
22332 + if (cp.structType != sizeof(cp))
22333 + return 0;
22334 +
22335 +
22336 + yaffs2_CheckpointDeviceToDevice(dev, &cp);
22337 +
22338 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22339 +
22340 + ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
22341 +
22342 + if (!ok)
22343 + return 0;
22344 + nBytes = nBlocks * dev->chunkBitmapStride;
22345 +
22346 + ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
22347 +
22348 + return ok ? 1 : 0;
22349 +}
22350 +
22351 +static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
22352 + yaffs_Object *obj)
22353 +{
22354 +
22355 + cp->objectId = obj->objectId;
22356 + cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
22357 + cp->hdrChunk = obj->hdrChunk;
22358 + cp->variantType = obj->variantType;
22359 + cp->deleted = obj->deleted;
22360 + cp->softDeleted = obj->softDeleted;
22361 + cp->unlinked = obj->unlinked;
22362 + cp->fake = obj->fake;
22363 + cp->renameAllowed = obj->renameAllowed;
22364 + cp->unlinkAllowed = obj->unlinkAllowed;
22365 + cp->serial = obj->serial;
22366 + cp->nDataChunks = obj->nDataChunks;
22367 +
22368 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22369 + cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
22370 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22371 + cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
22372 +}
22373 +
22374 +static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
22375 +{
22376 +
22377 + yaffs_Object *parent;
22378 +
22379 + if (obj->variantType != cp->variantType) {
22380 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
22381 + TCONT("chunk %d does not match existing object type %d")
22382 + TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
22383 + obj->variantType));
22384 + return 0;
22385 + }
22386 +
22387 + obj->objectId = cp->objectId;
22388 +
22389 + if (cp->parentId)
22390 + parent = yaffs_FindOrCreateObjectByNumber(
22391 + obj->myDev,
22392 + cp->parentId,
22393 + YAFFS_OBJECT_TYPE_DIRECTORY);
22394 + else
22395 + parent = NULL;
22396 +
22397 + if (parent) {
22398 + if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
22399 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
22400 + TCONT(" chunk %d Parent type, %d, not directory")
22401 + TENDSTR),
22402 + cp->objectId, cp->parentId, cp->variantType,
22403 + cp->hdrChunk, parent->variantType));
22404 + return 0;
22405 + }
22406 + yaffs_AddObjectToDirectory(parent, obj);
22407 + }
22408 +
22409 + obj->hdrChunk = cp->hdrChunk;
22410 + obj->variantType = cp->variantType;
22411 + obj->deleted = cp->deleted;
22412 + obj->softDeleted = cp->softDeleted;
22413 + obj->unlinked = cp->unlinked;
22414 + obj->fake = cp->fake;
22415 + obj->renameAllowed = cp->renameAllowed;
22416 + obj->unlinkAllowed = cp->unlinkAllowed;
22417 + obj->serial = cp->serial;
22418 + obj->nDataChunks = cp->nDataChunks;
22419 +
22420 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22421 + obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
22422 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22423 + obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
22424 +
22425 + if (obj->hdrChunk > 0)
22426 + obj->lazyLoaded = 1;
22427 + return 1;
22428 +}
22429 +
22430 +
22431 +
22432 +static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
22433 + __u32 level, int chunkOffset)
22434 +{
22435 + int i;
22436 + yaffs_Device *dev = in->myDev;
22437 + int ok = 1;
22438 +
22439 + if (tn) {
22440 + if (level > 0) {
22441 +
22442 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
22443 + if (tn->internal[i]) {
22444 + ok = yaffs2_CheckpointTnodeWorker(in,
22445 + tn->internal[i],
22446 + level - 1,
22447 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
22448 + }
22449 + }
22450 + } else if (level == 0) {
22451 + __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
22452 + ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
22453 + if (ok)
22454 + ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22455 + }
22456 + }
22457 +
22458 + return ok;
22459 +
22460 +}
22461 +
22462 +static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
22463 +{
22464 + __u32 endMarker = ~0;
22465 + int ok = 1;
22466 +
22467 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22468 + ok = yaffs2_CheckpointTnodeWorker(obj,
22469 + obj->variant.fileVariant.top,
22470 + obj->variant.fileVariant.topLevel,
22471 + 0);
22472 + if (ok)
22473 + ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
22474 + sizeof(endMarker));
22475 + }
22476 +
22477 + return ok ? 1 : 0;
22478 +}
22479 +
22480 +static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
22481 +{
22482 + __u32 baseChunk;
22483 + int ok = 1;
22484 + yaffs_Device *dev = obj->myDev;
22485 + yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
22486 + yaffs_Tnode *tn;
22487 + int nread = 0;
22488 +
22489 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22490 +
22491 + while (ok && (~baseChunk)) {
22492 + nread++;
22493 + /* Read level 0 tnode */
22494 +
22495 +
22496 + tn = yaffs_GetTnode(dev);
22497 + if (tn){
22498 + ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22499 + } else
22500 + ok = 0;
22501 +
22502 + if (tn && ok)
22503 + ok = yaffs_AddOrFindLevel0Tnode(dev,
22504 + fileStructPtr,
22505 + baseChunk,
22506 + tn) ? 1 : 0;
22507 +
22508 + if (ok)
22509 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22510 +
22511 + }
22512 +
22513 + T(YAFFS_TRACE_CHECKPOINT, (
22514 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
22515 + nread, baseChunk, ok));
22516 +
22517 + return ok ? 1 : 0;
22518 +}
22519 +
22520 +
22521 +static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
22522 +{
22523 + yaffs_Object *obj;
22524 + yaffs_CheckpointObject cp;
22525 + int i;
22526 + int ok = 1;
22527 + struct ylist_head *lh;
22528 +
22529 +
22530 + /* Iterate through the objects in each hash entry,
22531 + * dumping them to the checkpointing stream.
22532 + */
22533 +
22534 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
22535 + ylist_for_each(lh, &dev->objectBucket[i].list) {
22536 + if (lh) {
22537 + obj = ylist_entry(lh, yaffs_Object, hashLink);
22538 + if (!obj->deferedFree) {
22539 + yaffs2_ObjectToCheckpointObject(&cp, obj);
22540 + cp.structType = sizeof(cp);
22541 +
22542 + T(YAFFS_TRACE_CHECKPOINT, (
22543 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
22544 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
22545 +
22546 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22547 +
22548 + if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22549 + ok = yaffs2_WriteCheckpointTnodes(obj);
22550 + }
22551 + }
22552 + }
22553 + }
22554 +
22555 + /* Dump end of list */
22556 + memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
22557 + cp.structType = sizeof(cp);
22558 +
22559 + if (ok)
22560 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22561 +
22562 + return ok ? 1 : 0;
22563 +}
22564 +
22565 +static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
22566 +{
22567 + yaffs_Object *obj;
22568 + yaffs_CheckpointObject cp;
22569 + int ok = 1;
22570 + int done = 0;
22571 + yaffs_Object *hardList = NULL;
22572 +
22573 + while (ok && !done) {
22574 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22575 + if (cp.structType != sizeof(cp)) {
22576 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
22577 + cp.structType, (int)sizeof(cp), ok));
22578 + ok = 0;
22579 + }
22580 +
22581 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
22582 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
22583 +
22584 + if (ok && cp.objectId == ~0)
22585 + done = 1;
22586 + else if (ok) {
22587 + obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
22588 + if (obj) {
22589 + ok = yaffs2_CheckpointObjectToObject(obj, &cp);
22590 + if (!ok)
22591 + break;
22592 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22593 + ok = yaffs2_ReadCheckpointTnodes(obj);
22594 + } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
22595 + obj->hardLinks.next =
22596 + (struct ylist_head *) hardList;
22597 + hardList = obj;
22598 + }
22599 + } else
22600 + ok = 0;
22601 + }
22602 + }
22603 +
22604 + if (ok)
22605 + yaffs_HardlinkFixup(dev, hardList);
22606 +
22607 + return ok ? 1 : 0;
22608 +}
22609 +
22610 +static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
22611 +{
22612 + __u32 checkpointSum;
22613 + int ok;
22614 +
22615 + yaffs2_GetCheckpointSum(dev, &checkpointSum);
22616 +
22617 + ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
22618 +
22619 + if (!ok)
22620 + return 0;
22621 +
22622 + return 1;
22623 +}
22624 +
22625 +static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
22626 +{
22627 + __u32 checkpointSum0;
22628 + __u32 checkpointSum1;
22629 + int ok;
22630 +
22631 + yaffs2_GetCheckpointSum(dev, &checkpointSum0);
22632 +
22633 + ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
22634 +
22635 + if (!ok)
22636 + return 0;
22637 +
22638 + if (checkpointSum0 != checkpointSum1)
22639 + return 0;
22640 +
22641 + return 1;
22642 +}
22643 +
22644 +
22645 +static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
22646 +{
22647 + int ok = 1;
22648 +
22649 + if (!yaffs2_CheckpointRequired(dev)) {
22650 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
22651 + ok = 0;
22652 + }
22653 +
22654 + if (ok)
22655 + ok = yaffs2_CheckpointOpen(dev, 1);
22656 +
22657 + if (ok) {
22658 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22659 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
22660 + }
22661 + if (ok) {
22662 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
22663 + ok = yaffs2_WriteCheckpointDevice(dev);
22664 + }
22665 + if (ok) {
22666 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
22667 + ok = yaffs2_WriteCheckpointObjects(dev);
22668 + }
22669 + if (ok) {
22670 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22671 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
22672 + }
22673 +
22674 + if (ok)
22675 + ok = yaffs2_WriteCheckpointSum(dev);
22676 +
22677 + if (!yaffs2_CheckpointClose(dev))
22678 + ok = 0;
22679 +
22680 + if (ok)
22681 + dev->isCheckpointed = 1;
22682 + else
22683 + dev->isCheckpointed = 0;
22684 +
22685 + return dev->isCheckpointed;
22686 +}
22687 +
22688 +static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
22689 +{
22690 + int ok = 1;
22691 +
22692 + if(!dev->param.isYaffs2)
22693 + ok = 0;
22694 +
22695 + if (ok && dev->param.skipCheckpointRead) {
22696 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
22697 + ok = 0;
22698 + }
22699 +
22700 + if (ok)
22701 + ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
22702 +
22703 + if (ok) {
22704 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22705 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
22706 + }
22707 + if (ok) {
22708 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
22709 + ok = yaffs2_ReadCheckpointDevice(dev);
22710 + }
22711 + if (ok) {
22712 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
22713 + ok = yaffs2_ReadCheckpointObjects(dev);
22714 + }
22715 + if (ok) {
22716 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22717 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
22718 + }
22719 +
22720 + if (ok) {
22721 + ok = yaffs2_ReadCheckpointSum(dev);
22722 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
22723 + }
22724 +
22725 + if (!yaffs2_CheckpointClose(dev))
22726 + ok = 0;
22727 +
22728 + if (ok)
22729 + dev->isCheckpointed = 1;
22730 + else
22731 + dev->isCheckpointed = 0;
22732 +
22733 + return ok ? 1 : 0;
22734 +
22735 +}
22736 +
22737 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
22738 +{
22739 + if (dev->isCheckpointed ||
22740 + dev->blocksInCheckpoint > 0) {
22741 + dev->isCheckpointed = 0;
22742 + yaffs2_CheckpointInvalidateStream(dev);
22743 + }
22744 + if (dev->param.markSuperBlockDirty)
22745 + dev->param.markSuperBlockDirty(dev);
22746 +}
22747 +
22748 +
22749 +int yaffs_CheckpointSave(yaffs_Device *dev)
22750 +{
22751 +
22752 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22753 +
22754 + yaffs_VerifyObjects(dev);
22755 + yaffs_VerifyBlocks(dev);
22756 + yaffs_VerifyFreeChunks(dev);
22757 +
22758 + if (!dev->isCheckpointed) {
22759 + yaffs2_InvalidateCheckpoint(dev);
22760 + yaffs2_WriteCheckpointData(dev);
22761 + }
22762 +
22763 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22764 +
22765 + return dev->isCheckpointed;
22766 +}
22767 +
22768 +int yaffs2_CheckpointRestore(yaffs_Device *dev)
22769 +{
22770 + int retval;
22771 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22772 +
22773 + retval = yaffs2_ReadCheckpointData(dev);
22774 +
22775 + if (dev->isCheckpointed) {
22776 + yaffs_VerifyObjects(dev);
22777 + yaffs_VerifyBlocks(dev);
22778 + yaffs_VerifyFreeChunks(dev);
22779 + }
22780 +
22781 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22782 +
22783 + return retval;
22784 +}
22785 +
22786 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
22787 +{
22788 + /* if newsSize > oldFileSize.
22789 + * We're going to be writing a hole.
22790 + * If the hole is small then write zeros otherwise write a start of hole marker.
22791 + */
22792 +
22793 +
22794 + loff_t oldFileSize;
22795 + int increase;
22796 + int smallHole ;
22797 + int result = YAFFS_OK;
22798 + yaffs_Device *dev = NULL;
22799 +
22800 + __u8 *localBuffer = NULL;
22801 +
22802 + int smallIncreaseOk = 0;
22803 +
22804 + if(!obj)
22805 + return YAFFS_FAIL;
22806 +
22807 + if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
22808 + return YAFFS_FAIL;
22809 +
22810 + dev = obj->myDev;
22811 +
22812 + /* Bail out if not yaffs2 mode */
22813 + if(!dev->param.isYaffs2)
22814 + return YAFFS_OK;
22815 +
22816 + oldFileSize = obj->variant.fileVariant.fileSize;
22817 +
22818 + if (newSize <= oldFileSize)
22819 + return YAFFS_OK;
22820 +
22821 + increase = newSize - oldFileSize;
22822 +
22823 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
22824 + yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
22825 + smallHole = 1;
22826 + else
22827 + smallHole = 0;
22828 +
22829 + if(smallHole)
22830 + localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
22831 +
22832 + if(localBuffer){
22833 + /* fill hole with zero bytes */
22834 + int pos = oldFileSize;
22835 + int thisWrite;
22836 + int written;
22837 + memset(localBuffer,0,dev->nDataBytesPerChunk);
22838 + smallIncreaseOk = 1;
22839 +
22840 + while(increase > 0 && smallIncreaseOk){
22841 + thisWrite = increase;
22842 + if(thisWrite > dev->nDataBytesPerChunk)
22843 + thisWrite = dev->nDataBytesPerChunk;
22844 + written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
22845 + if(written == thisWrite){
22846 + pos += thisWrite;
22847 + increase -= thisWrite;
22848 + } else
22849 + smallIncreaseOk = 0;
22850 + }
22851 +
22852 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
22853 +
22854 + /* If we were out of space then reverse any chunks we've added */
22855 + if(!smallIncreaseOk)
22856 + yaffs_ResizeDown(obj, oldFileSize);
22857 + }
22858 +
22859 + if (!smallIncreaseOk &&
22860 + obj->parent &&
22861 + obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
22862 + obj->parent->objectId != YAFFS_OBJECTID_DELETED){
22863 + /* Write a hole start header with the old file size */
22864 + yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
22865 + }
22866 +
22867 + return result;
22868 +
22869 +}
22870 +
22871 +
22872 +typedef struct {
22873 + int seq;
22874 + int block;
22875 +} yaffs_BlockIndex;
22876 +
22877 +
22878 +static int yaffs2_ybicmp(const void *a, const void *b)
22879 +{
22880 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
22881 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
22882 + register int ablock = ((yaffs_BlockIndex *)a)->block;
22883 + register int bblock = ((yaffs_BlockIndex *)b)->block;
22884 + if (aseq == bseq)
22885 + return ablock - bblock;
22886 + else
22887 + return aseq - bseq;
22888 +}
22889 +
22890 +int yaffs2_ScanBackwards(yaffs_Device *dev)
22891 +{
22892 + yaffs_ExtendedTags tags;
22893 + int blk;
22894 + int blockIterator;
22895 + int startIterator;
22896 + int endIterator;
22897 + int nBlocksToScan = 0;
22898 +
22899 + int chunk;
22900 + int result;
22901 + int c;
22902 + int deleted;
22903 + yaffs_BlockState state;
22904 + yaffs_Object *hardList = NULL;
22905 + yaffs_BlockInfo *bi;
22906 + __u32 sequenceNumber;
22907 + yaffs_ObjectHeader *oh;
22908 + yaffs_Object *in;
22909 + yaffs_Object *parent;
22910 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
22911 + int itsUnlinked;
22912 + __u8 *chunkData;
22913 +
22914 + int fileSize;
22915 + int isShrink;
22916 + int foundChunksInBlock;
22917 + int equivalentObjectId;
22918 + int alloc_failed = 0;
22919 +
22920 +
22921 + yaffs_BlockIndex *blockIndex = NULL;
22922 + int altBlockIndex = 0;
22923 +
22924 + T(YAFFS_TRACE_SCAN,
22925 + (TSTR
22926 + ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
22927 + TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
22928 +
22929 +
22930 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
22931 +
22932 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
22933 +
22934 + if (!blockIndex) {
22935 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
22936 + altBlockIndex = 1;
22937 + }
22938 +
22939 + if (!blockIndex) {
22940 + T(YAFFS_TRACE_SCAN,
22941 + (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
22942 + return YAFFS_FAIL;
22943 + }
22944 +
22945 + dev->blocksInCheckpoint = 0;
22946 +
22947 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
22948 +
22949 + /* Scan all the blocks to determine their state */
22950 + bi = dev->blockInfo;
22951 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
22952 + yaffs_ClearChunkBits(dev, blk);
22953 + bi->pagesInUse = 0;
22954 + bi->softDeletions = 0;
22955 +
22956 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
22957 +
22958 + bi->blockState = state;
22959 + bi->sequenceNumber = sequenceNumber;
22960 +
22961 + if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
22962 + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
22963 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
22964 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
22965 +
22966 + T(YAFFS_TRACE_SCAN_DEBUG,
22967 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
22968 + state, sequenceNumber));
22969 +
22970 +
22971 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
22972 + dev->blocksInCheckpoint++;
22973 +
22974 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
22975 + T(YAFFS_TRACE_BAD_BLOCKS,
22976 + (TSTR("block %d is bad" TENDSTR), blk));
22977 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
22978 + T(YAFFS_TRACE_SCAN_DEBUG,
22979 + (TSTR("Block empty " TENDSTR)));
22980 + dev->nErasedBlocks++;
22981 + dev->nFreeChunks += dev->param.nChunksPerBlock;
22982 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
22983 +
22984 + /* Determine the highest sequence number */
22985 + if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
22986 + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
22987 +
22988 + blockIndex[nBlocksToScan].seq = sequenceNumber;
22989 + blockIndex[nBlocksToScan].block = blk;
22990 +
22991 + nBlocksToScan++;
22992 +
22993 + if (sequenceNumber >= dev->sequenceNumber)
22994 + dev->sequenceNumber = sequenceNumber;
22995 + } else {
22996 + /* TODO: Nasty sequence number! */
22997 + T(YAFFS_TRACE_SCAN,
22998 + (TSTR
22999 + ("Block scanning block %d has bad sequence number %d"
23000 + TENDSTR), blk, sequenceNumber));
23001 +
23002 + }
23003 + }
23004 + bi++;
23005 + }
23006 +
23007 + T(YAFFS_TRACE_SCAN,
23008 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
23009 +
23010 +
23011 +
23012 + YYIELD();
23013 +
23014 + /* Sort the blocks by sequence number*/
23015 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
23016 +
23017 + YYIELD();
23018 +
23019 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
23020 +
23021 + /* Now scan the blocks looking at the data. */
23022 + startIterator = 0;
23023 + endIterator = nBlocksToScan - 1;
23024 + T(YAFFS_TRACE_SCAN_DEBUG,
23025 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
23026 +
23027 + /* For each block.... backwards */
23028 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
23029 + blockIterator--) {
23030 + /* Cooperative multitasking! This loop can run for so
23031 + long that watchdog timers expire. */
23032 + YYIELD();
23033 +
23034 + /* get the block to scan in the correct order */
23035 + blk = blockIndex[blockIterator].block;
23036 +
23037 + bi = yaffs_GetBlockInfo(dev, blk);
23038 +
23039 +
23040 + state = bi->blockState;
23041 +
23042 + deleted = 0;
23043 +
23044 + /* For each chunk in each block that needs scanning.... */
23045 + foundChunksInBlock = 0;
23046 + for (c = dev->param.nChunksPerBlock - 1;
23047 + !alloc_failed && c >= 0 &&
23048 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23049 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
23050 + /* Scan backwards...
23051 + * Read the tags and decide what to do
23052 + */
23053 +
23054 + chunk = blk * dev->param.nChunksPerBlock + c;
23055 +
23056 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
23057 + &tags);
23058 +
23059 + /* Let's have a good look at this chunk... */
23060 +
23061 + if (!tags.chunkUsed) {
23062 + /* An unassigned chunk in the block.
23063 + * If there are used chunks after this one, then
23064 + * it is a chunk that was skipped due to failing the erased
23065 + * check. Just skip it so that it can be deleted.
23066 + * But, more typically, We get here when this is an unallocated
23067 + * chunk and his means that either the block is empty or
23068 + * this is the one being allocated from
23069 + */
23070 +
23071 + if (foundChunksInBlock) {
23072 + /* This is a chunk that was skipped due to failing the erased check */
23073 + } else if (c == 0) {
23074 + /* We're looking at the first chunk in the block so the block is unused */
23075 + state = YAFFS_BLOCK_STATE_EMPTY;
23076 + dev->nErasedBlocks++;
23077 + } else {
23078 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23079 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
23080 + if (dev->sequenceNumber == bi->sequenceNumber) {
23081 + /* this is the block being allocated from */
23082 +
23083 + T(YAFFS_TRACE_SCAN,
23084 + (TSTR
23085 + (" Allocating from %d %d"
23086 + TENDSTR), blk, c));
23087 +
23088 + state = YAFFS_BLOCK_STATE_ALLOCATING;
23089 + dev->allocationBlock = blk;
23090 + dev->allocationPage = c;
23091 + dev->allocationBlockFinder = blk;
23092 + } else {
23093 + /* This is a partially written block that is not
23094 + * the current allocation block.
23095 + */
23096 +
23097 + T(YAFFS_TRACE_SCAN,
23098 + (TSTR("Partially written block %d detected" TENDSTR),
23099 + blk));
23100 + }
23101 + }
23102 + }
23103 +
23104 + dev->nFreeChunks++;
23105 +
23106 + } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
23107 + T(YAFFS_TRACE_SCAN,
23108 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
23109 + blk, c));
23110 +
23111 + dev->nFreeChunks++;
23112 +
23113 + } else if (tags.objectId > YAFFS_MAX_OBJECT_ID ||
23114 + tags.chunkId > YAFFS_MAX_CHUNK_ID ||
23115 + (tags.chunkId > 0 && tags.byteCount > dev->nDataBytesPerChunk) ||
23116 + tags.sequenceNumber != bi->sequenceNumber ) {
23117 + T(YAFFS_TRACE_SCAN,
23118 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunkId = %d, byteCount = %d, ignored"TENDSTR),
23119 + blk, c,tags.objectId, tags.chunkId, tags.byteCount));
23120 +
23121 + dev->nFreeChunks++;
23122 +
23123 + } else if (tags.chunkId > 0) {
23124 + /* chunkId > 0 so it is a data chunk... */
23125 + unsigned int endpos;
23126 + __u32 chunkBase =
23127 + (tags.chunkId - 1) * dev->nDataBytesPerChunk;
23128 +
23129 + foundChunksInBlock = 1;
23130 +
23131 +
23132 + yaffs_SetChunkBit(dev, blk, c);
23133 + bi->pagesInUse++;
23134 +
23135 + in = yaffs_FindOrCreateObjectByNumber(dev,
23136 + tags.
23137 + objectId,
23138 + YAFFS_OBJECT_TYPE_FILE);
23139 + if (!in) {
23140 + /* Out of memory */
23141 + alloc_failed = 1;
23142 + }
23143 +
23144 + if (in &&
23145 + in->variantType == YAFFS_OBJECT_TYPE_FILE
23146 + && chunkBase < in->variant.fileVariant.shrinkSize) {
23147 + /* This has not been invalidated by a resize */
23148 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
23149 + alloc_failed = 1;
23150 + }
23151 +
23152 + /* File size is calculated by looking at the data chunks if we have not
23153 + * seen an object header yet. Stop this practice once we find an object header.
23154 + */
23155 + endpos = chunkBase + tags.byteCount;
23156 +
23157 + if (!in->valid && /* have not got an object header yet */
23158 + in->variant.fileVariant.scannedFileSize < endpos) {
23159 + in->variant.fileVariant.scannedFileSize = endpos;
23160 + in->variant.fileVariant.fileSize = endpos;
23161 + }
23162 +
23163 + } else if (in) {
23164 + /* This chunk has been invalidated by a resize, or a past file deletion
23165 + * so delete the chunk*/
23166 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23167 +
23168 + }
23169 + } else {
23170 + /* chunkId == 0, so it is an ObjectHeader.
23171 + * Thus, we read in the object header and make the object
23172 + */
23173 + foundChunksInBlock = 1;
23174 +
23175 + yaffs_SetChunkBit(dev, blk, c);
23176 + bi->pagesInUse++;
23177 +
23178 + oh = NULL;
23179 + in = NULL;
23180 +
23181 + if (tags.extraHeaderInfoAvailable) {
23182 + in = yaffs_FindOrCreateObjectByNumber(dev,
23183 + tags.objectId,
23184 + tags.extraObjectType);
23185 + if (!in)
23186 + alloc_failed = 1;
23187 + }
23188 +
23189 + if (!in ||
23190 + (!in->valid && dev->param.disableLazyLoad) ||
23191 + tags.extraShadows ||
23192 + (!in->valid &&
23193 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23194 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
23195 +
23196 + /* If we don't have valid info then we need to read the chunk
23197 + * TODO In future we can probably defer reading the chunk and
23198 + * living with invalid data until needed.
23199 + */
23200 +
23201 + result = yaffs_ReadChunkWithTagsFromNAND(dev,
23202 + chunk,
23203 + chunkData,
23204 + NULL);
23205 +
23206 + oh = (yaffs_ObjectHeader *) chunkData;
23207 +
23208 + if (dev->param.inbandTags) {
23209 + /* Fix up the header if they got corrupted by inband tags */
23210 + oh->shadowsObject = oh->inbandShadowsObject;
23211 + oh->isShrink = oh->inbandIsShrink;
23212 + }
23213 +
23214 + if (!in) {
23215 + in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
23216 + if (!in)
23217 + alloc_failed = 1;
23218 + }
23219 +
23220 + }
23221 +
23222 + if (!in) {
23223 + /* TODO Hoosterman we have a problem! */
23224 + T(YAFFS_TRACE_ERROR,
23225 + (TSTR
23226 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
23227 + TENDSTR), tags.objectId, chunk));
23228 + continue;
23229 + }
23230 +
23231 + if (in->valid) {
23232 + /* We have already filled this one.
23233 + * We have a duplicate that will be discarded, but
23234 + * we first have to suck out resize info if it is a file.
23235 + */
23236 +
23237 + if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
23238 + ((oh &&
23239 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
23240 + (tags.extraHeaderInfoAvailable &&
23241 + tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
23242 + __u32 thisSize =
23243 + (oh) ? oh->fileSize : tags.
23244 + extraFileLength;
23245 + __u32 parentObjectId =
23246 + (oh) ? oh->
23247 + parentObjectId : tags.
23248 + extraParentObjectId;
23249 +
23250 +
23251 + isShrink =
23252 + (oh) ? oh->isShrink : tags.
23253 + extraIsShrinkHeader;
23254 +
23255 + /* If it is deleted (unlinked at start also means deleted)
23256 + * we treat the file size as being zeroed at this point.
23257 + */
23258 + if (parentObjectId ==
23259 + YAFFS_OBJECTID_DELETED
23260 + || parentObjectId ==
23261 + YAFFS_OBJECTID_UNLINKED) {
23262 + thisSize = 0;
23263 + isShrink = 1;
23264 + }
23265 +
23266 + if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
23267 + in->variant.fileVariant.shrinkSize = thisSize;
23268 +
23269 + if (isShrink)
23270 + bi->hasShrinkHeader = 1;
23271 +
23272 + }
23273 + /* Use existing - destroy this one. */
23274 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23275 +
23276 + }
23277 +
23278 + if (!in->valid && in->variantType !=
23279 + (oh ? oh->type : tags.extraObjectType))
23280 + T(YAFFS_TRACE_ERROR, (
23281 + TSTR("yaffs tragedy: Bad object type, "
23282 + TCONT("%d != %d, for object %d at chunk ")
23283 + TCONT("%d during scan")
23284 + TENDSTR), oh ?
23285 + oh->type : tags.extraObjectType,
23286 + in->variantType, tags.objectId,
23287 + chunk));
23288 +
23289 + if (!in->valid &&
23290 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23291 + tags.objectId ==
23292 + YAFFS_OBJECTID_LOSTNFOUND)) {
23293 + /* We only load some info, don't fiddle with directory structure */
23294 + in->valid = 1;
23295 +
23296 + if (oh) {
23297 +
23298 + in->yst_mode = oh->yst_mode;
23299 +#ifdef CONFIG_YAFFS_WINCE
23300 + in->win_atime[0] = oh->win_atime[0];
23301 + in->win_ctime[0] = oh->win_ctime[0];
23302 + in->win_mtime[0] = oh->win_mtime[0];
23303 + in->win_atime[1] = oh->win_atime[1];
23304 + in->win_ctime[1] = oh->win_ctime[1];
23305 + in->win_mtime[1] = oh->win_mtime[1];
23306 +#else
23307 + in->yst_uid = oh->yst_uid;
23308 + in->yst_gid = oh->yst_gid;
23309 + in->yst_atime = oh->yst_atime;
23310 + in->yst_mtime = oh->yst_mtime;
23311 + in->yst_ctime = oh->yst_ctime;
23312 + in->yst_rdev = oh->yst_rdev;
23313 +
23314 + in->lazyLoaded = 0;
23315 +
23316 +#endif
23317 + } else
23318 + in->lazyLoaded = 1;
23319 +
23320 + in->hdrChunk = chunk;
23321 +
23322 + } else if (!in->valid) {
23323 + /* we need to load this info */
23324 +
23325 + in->valid = 1;
23326 + in->hdrChunk = chunk;
23327 +
23328 + if (oh) {
23329 + in->variantType = oh->type;
23330 +
23331 + in->yst_mode = oh->yst_mode;
23332 +#ifdef CONFIG_YAFFS_WINCE
23333 + in->win_atime[0] = oh->win_atime[0];
23334 + in->win_ctime[0] = oh->win_ctime[0];
23335 + in->win_mtime[0] = oh->win_mtime[0];
23336 + in->win_atime[1] = oh->win_atime[1];
23337 + in->win_ctime[1] = oh->win_ctime[1];
23338 + in->win_mtime[1] = oh->win_mtime[1];
23339 +#else
23340 + in->yst_uid = oh->yst_uid;
23341 + in->yst_gid = oh->yst_gid;
23342 + in->yst_atime = oh->yst_atime;
23343 + in->yst_mtime = oh->yst_mtime;
23344 + in->yst_ctime = oh->yst_ctime;
23345 + in->yst_rdev = oh->yst_rdev;
23346 +#endif
23347 +
23348 + if (oh->shadowsObject > 0)
23349 + yaffs_HandleShadowedObject(dev,
23350 + oh->
23351 + shadowsObject,
23352 + 1);
23353 +
23354 +
23355 +
23356 + yaffs_SetObjectNameFromOH(in, oh);
23357 + parent =
23358 + yaffs_FindOrCreateObjectByNumber
23359 + (dev, oh->parentObjectId,
23360 + YAFFS_OBJECT_TYPE_DIRECTORY);
23361 +
23362 + fileSize = oh->fileSize;
23363 + isShrink = oh->isShrink;
23364 + equivalentObjectId = oh->equivalentObjectId;
23365 +
23366 + } else {
23367 + in->variantType = tags.extraObjectType;
23368 + parent =
23369 + yaffs_FindOrCreateObjectByNumber
23370 + (dev, tags.extraParentObjectId,
23371 + YAFFS_OBJECT_TYPE_DIRECTORY);
23372 + fileSize = tags.extraFileLength;
23373 + isShrink = tags.extraIsShrinkHeader;
23374 + equivalentObjectId = tags.extraEquivalentObjectId;
23375 + in->lazyLoaded = 1;
23376 +
23377 + }
23378 + in->dirty = 0;
23379 +
23380 + if (!parent)
23381 + alloc_failed = 1;
23382 +
23383 + /* directory stuff...
23384 + * hook up to parent
23385 + */
23386 +
23387 + if (parent && parent->variantType ==
23388 + YAFFS_OBJECT_TYPE_UNKNOWN) {
23389 + /* Set up as a directory */
23390 + parent->variantType =
23391 + YAFFS_OBJECT_TYPE_DIRECTORY;
23392 + YINIT_LIST_HEAD(&parent->variant.
23393 + directoryVariant.
23394 + children);
23395 + } else if (!parent || parent->variantType !=
23396 + YAFFS_OBJECT_TYPE_DIRECTORY) {
23397 + /* Hoosterman, another problem....
23398 + * We're trying to use a non-directory as a directory
23399 + */
23400 +
23401 + T(YAFFS_TRACE_ERROR,
23402 + (TSTR
23403 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
23404 + TENDSTR)));
23405 + parent = dev->lostNFoundDir;
23406 + }
23407 +
23408 + yaffs_AddObjectToDirectory(parent, in);
23409 +
23410 + itsUnlinked = (parent == dev->deletedDir) ||
23411 + (parent == dev->unlinkedDir);
23412 +
23413 + if (isShrink) {
23414 + /* Mark the block as having a shrinkHeader */
23415 + bi->hasShrinkHeader = 1;
23416 + }
23417 +
23418 + /* Note re hardlinks.
23419 + * Since we might scan a hardlink before its equivalent object is scanned
23420 + * we put them all in a list.
23421 + * After scanning is complete, we should have all the objects, so we run
23422 + * through this list and fix up all the chains.
23423 + */
23424 +
23425 + switch (in->variantType) {
23426 + case YAFFS_OBJECT_TYPE_UNKNOWN:
23427 + /* Todo got a problem */
23428 + break;
23429 + case YAFFS_OBJECT_TYPE_FILE:
23430 +
23431 + if (in->variant.fileVariant.
23432 + scannedFileSize < fileSize) {
23433 + /* This covers the case where the file size is greater
23434 + * than where the data is
23435 + * This will happen if the file is resized to be larger
23436 + * than its current data extents.
23437 + */
23438 + in->variant.fileVariant.fileSize = fileSize;
23439 + in->variant.fileVariant.scannedFileSize = fileSize;
23440 + }
23441 +
23442 + if (in->variant.fileVariant.shrinkSize > fileSize)
23443 + in->variant.fileVariant.shrinkSize = fileSize;
23444 +
23445 +
23446 + break;
23447 + case YAFFS_OBJECT_TYPE_HARDLINK:
23448 + if (!itsUnlinked) {
23449 + in->variant.hardLinkVariant.equivalentObjectId =
23450 + equivalentObjectId;
23451 + in->hardLinks.next =
23452 + (struct ylist_head *) hardList;
23453 + hardList = in;
23454 + }
23455 + break;
23456 + case YAFFS_OBJECT_TYPE_DIRECTORY:
23457 + /* Do nothing */
23458 + break;
23459 + case YAFFS_OBJECT_TYPE_SPECIAL:
23460 + /* Do nothing */
23461 + break;
23462 + case YAFFS_OBJECT_TYPE_SYMLINK:
23463 + if (oh) {
23464 + in->variant.symLinkVariant.alias =
23465 + yaffs_CloneString(oh->alias);
23466 + if (!in->variant.symLinkVariant.alias)
23467 + alloc_failed = 1;
23468 + }
23469 + break;
23470 + }
23471 +
23472 + }
23473 +
23474 + }
23475 +
23476 + } /* End of scanning for each chunk */
23477 +
23478 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
23479 + /* If we got this far while scanning, then the block is fully allocated. */
23480 + state = YAFFS_BLOCK_STATE_FULL;
23481 + }
23482 +
23483 +
23484 + bi->blockState = state;
23485 +
23486 + /* Now let's see if it was dirty */
23487 + if (bi->pagesInUse == 0 &&
23488 + !bi->hasShrinkHeader &&
23489 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
23490 + yaffs_BlockBecameDirty(dev, blk);
23491 + }
23492 +
23493 + }
23494 +
23495 + yaffs_SkipRestOfBlock(dev);
23496 +
23497 + if (altBlockIndex)
23498 + YFREE_ALT(blockIndex);
23499 + else
23500 + YFREE(blockIndex);
23501 +
23502 + /* Ok, we've done all the scanning.
23503 + * Fix up the hard link chains.
23504 + * We should now have scanned all the objects, now it's time to add these
23505 + * hardlinks.
23506 + */
23507 + yaffs_HardlinkFixup(dev, hardList);
23508 +
23509 +
23510 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
23511 +
23512 + if (alloc_failed)
23513 + return YAFFS_FAIL;
23514 +
23515 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
23516 +
23517 + return YAFFS_OK;
23518 +}
23519 --- /dev/null
23520 +++ b/fs/yaffs2/yaffs_yaffs2.h
23521 @@ -0,0 +1,36 @@
23522 +/*
23523 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
23524 + *
23525 + * Copyright (C) 2002-2010 Aleph One Ltd.
23526 + * for Toby Churchill Ltd and Brightstar Engineering
23527 + *
23528 + * Created by Charles Manning <charles@aleph1.co.uk>
23529 + *
23530 + * This program is free software; you can redistribute it and/or modify
23531 + * it under the terms of the GNU General Public License version 2 as
23532 + * published by the Free Software Foundation.
23533 + */
23534 +
23535 +#ifndef __YAFFS_YAFFS2_H__
23536 +#define __YAFFS_YAFFS2_H__
23537 +
23538 +#include "yaffs_guts.h"
23539 +
23540 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev);
23541 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev);
23542 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi);
23543 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi);
23544 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi);
23545 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev);
23546 +int yaffs2_CheckpointRequired(yaffs_Device *dev);
23547 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev);
23548 +
23549 +
23550 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
23551 +int yaffs2_CheckpointSave(yaffs_Device *dev);
23552 +int yaffs2_CheckpointRestore(yaffs_Device *dev);
23553 +
23554 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
23555 +int yaffs2_ScanBackwards(yaffs_Device *dev);
23556 +
23557 +#endif
23558 --- a/fs/yaffs2/yportenv.h
23559 +++ b/fs/yaffs2/yportenv.h
23560 @@ -1,7 +1,7 @@
23561 /*
23562 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
23563 *
23564 - * Copyright (C) 2002-2007 Aleph One Ltd.
23565 + * Copyright (C) 2002-2010 Aleph One Ltd.
23566 * for Toby Churchill Ltd and Brightstar Engineering
23567 *
23568 * Created by Charles Manning <charles@aleph1.co.uk>
23569 @@ -41,12 +41,14 @@
23570 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
23571 #include <linux/config.h>
23572 #endif
23573 +
23574 #include <linux/kernel.h>
23575 #include <linux/mm.h>
23576 #include <linux/sched.h>
23577 #include <linux/string.h>
23578 #include <linux/slab.h>
23579 #include <linux/vmalloc.h>
23580 +#include <linux/xattr.h>
23581
23582 #define YCHAR char
23583 #define YUCHAR unsigned char
23584 @@ -55,11 +57,11 @@
23585 #define yaffs_strcpy(a, b) strcpy(a, b)
23586 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23587 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
23588 -#define yaffs_strlen(s) strlen(s)
23589 +#define yaffs_strnlen(s,m) strnlen(s,m)
23590 #define yaffs_sprintf sprintf
23591 #define yaffs_toupper(a) toupper(a)
23592
23593 -#define Y_INLINE inline
23594 +#define Y_INLINE __inline__
23595
23596 #define YAFFS_LOSTNFOUND_NAME "lost+found"
23597 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23598 @@ -71,11 +73,11 @@
23599 #define YFREE_ALT(x) vfree(x)
23600 #define YMALLOC_DMA(x) YMALLOC(x)
23601
23602 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
23603 #define YYIELD() schedule()
23604 +#define Y_DUMP_STACK() dump_stack()
23605
23606 -#define YAFFS_ROOT_MODE 0666
23607 -#define YAFFS_LOSTNFOUND_MODE 0666
23608 +#define YAFFS_ROOT_MODE 0755
23609 +#define YAFFS_LOSTNFOUND_MODE 0700
23610
23611 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23612 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
23613 @@ -89,15 +91,10 @@
23614 #define yaffs_strcmp(a, b) strcmp(a, b)
23615
23616 #define TENDSTR "\n"
23617 -#define TSTR(x) KERN_WARNING x
23618 +#define TSTR(x) KERN_DEBUG x
23619 #define TCONT(x) x
23620 #define TOUT(p) printk p
23621
23622 -#define yaffs_trace(mask, fmt, args...) \
23623 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
23624 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
23625 - } while (0)
23626 -
23627 #define compile_time_assertion(assertion) \
23628 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
23629
23630 @@ -116,7 +113,6 @@
23631 #include "stdio.h"
23632 #include "string.h"
23633
23634 -#include "devextras.h"
23635
23636 #define YMALLOC(x) malloc(x)
23637 #define YFREE(x) free(x)
23638 @@ -129,7 +125,7 @@
23639 #define yaffs_strcat(a, b) strcat(a, b)
23640 #define yaffs_strcpy(a, b) strcpy(a, b)
23641 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23642 -#define yaffs_strlen(s) strlen(s)
23643 +#define yaffs_strnlen(s,m) strnlen(s,m)
23644 #define yaffs_sprintf sprintf
23645 #define yaffs_toupper(a) toupper(a)
23646
23647 @@ -146,8 +142,8 @@
23648 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23649 /* #define YPRINTF(x) printf x */
23650
23651 -#define YAFFS_ROOT_MODE 0666
23652 -#define YAFFS_LOSTNFOUND_MODE 0666
23653 +#define YAFFS_ROOT_MODE 0755
23654 +#define YAFFS_LOSTNFOUND_MODE 0700
23655
23656 #define yaffs_SumCompare(x, y) ((x) == (y))
23657 #define yaffs_strcmp(a, b) strcmp(a, b)
23658 @@ -158,46 +154,180 @@
23659
23660 #endif
23661
23662 -/* see yaffs_fs.c */
23663 -extern unsigned int yaffs_traceMask;
23664 -extern unsigned int yaffs_wr_attempts;
23665 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
23666
23667 -/*
23668 - * Tracing flags.
23669 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
23670 - */
23671 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
23672 +
23673 +#ifndef O_RDONLY
23674 +#define O_RDONLY 00
23675 +#endif
23676 +
23677 +#ifndef O_WRONLY
23678 +#define O_WRONLY 01
23679 +#endif
23680 +
23681 +#ifndef O_RDWR
23682 +#define O_RDWR 02
23683 +#endif
23684 +
23685 +#ifndef O_CREAT
23686 +#define O_CREAT 0100
23687 +#endif
23688 +
23689 +#ifndef O_EXCL
23690 +#define O_EXCL 0200
23691 +#endif
23692 +
23693 +#ifndef O_TRUNC
23694 +#define O_TRUNC 01000
23695 +#endif
23696 +
23697 +#ifndef O_APPEND
23698 +#define O_APPEND 02000
23699 +#endif
23700 +
23701 +#ifndef SEEK_SET
23702 +#define SEEK_SET 0
23703 +#endif
23704 +
23705 +#ifndef SEEK_CUR
23706 +#define SEEK_CUR 1
23707 +#endif
23708 +
23709 +#ifndef SEEK_END
23710 +#define SEEK_END 2
23711 +#endif
23712 +
23713 +#ifndef EBUSY
23714 +#define EBUSY 16
23715 +#endif
23716 +
23717 +#ifndef ENODEV
23718 +#define ENODEV 19
23719 +#endif
23720 +
23721 +#ifndef EINVAL
23722 +#define EINVAL 22
23723 +#endif
23724 +
23725 +#ifndef EBADF
23726 +#define EBADF 9
23727 +#endif
23728 +
23729 +#ifndef EACCES
23730 +#define EACCES 13
23731 +#endif
23732 +
23733 +#ifndef EXDEV
23734 +#define EXDEV 18
23735 +#endif
23736 +
23737 +#ifndef ENOENT
23738 +#define ENOENT 2
23739 +#endif
23740 +
23741 +#ifndef ENOSPC
23742 +#define ENOSPC 28
23743 +#endif
23744 +
23745 +#ifndef ERANGE
23746 +#define ERANGE 34
23747 +#endif
23748 +
23749 +#ifndef ENODATA
23750 +#define ENODATA 61
23751 +#endif
23752 +
23753 +#ifndef ENOTEMPTY
23754 +#define ENOTEMPTY 39
23755 +#endif
23756 +
23757 +#ifndef ENAMETOOLONG
23758 +#define ENAMETOOLONG 36
23759 +#endif
23760 +
23761 +#ifndef ENOMEM
23762 +#define ENOMEM 12
23763 +#endif
23764 +
23765 +#ifndef EEXIST
23766 +#define EEXIST 17
23767 +#endif
23768 +
23769 +#ifndef ENOTDIR
23770 +#define ENOTDIR 20
23771 +#endif
23772 +
23773 +#ifndef EISDIR
23774 +#define EISDIR 21
23775 +#endif
23776 +
23777 +
23778 +// Mode flags
23779 +
23780 +#ifndef S_IFMT
23781 +#define S_IFMT 0170000
23782 +#endif
23783 +
23784 +#ifndef S_IFLNK
23785 +#define S_IFLNK 0120000
23786 +#endif
23787
23788 -#define YAFFS_TRACE_OS 0x00000002
23789 -#define YAFFS_TRACE_ALLOCATE 0x00000004
23790 -#define YAFFS_TRACE_SCAN 0x00000008
23791 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
23792 -#define YAFFS_TRACE_ERASE 0x00000020
23793 -#define YAFFS_TRACE_GC 0x00000040
23794 -#define YAFFS_TRACE_WRITE 0x00000080
23795 -#define YAFFS_TRACE_TRACING 0x00000100
23796 -#define YAFFS_TRACE_DELETION 0x00000200
23797 -#define YAFFS_TRACE_BUFFERS 0x00000400
23798 -#define YAFFS_TRACE_NANDACCESS 0x00000800
23799 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
23800 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
23801 -#define YAFFS_TRACE_MTD 0x00004000
23802 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
23803 -
23804 -#define YAFFS_TRACE_VERIFY 0x00010000
23805 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
23806 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
23807 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
23808 -
23809 -
23810 -#define YAFFS_TRACE_ERROR 0x40000000
23811 -#define YAFFS_TRACE_BUG 0x80000000
23812 -#define YAFFS_TRACE_ALWAYS 0xF0000000
23813 +#ifndef S_IFDIR
23814 +#define S_IFDIR 0040000
23815 +#endif
23816 +
23817 +#ifndef S_IFREG
23818 +#define S_IFREG 0100000
23819 +#endif
23820
23821 +#ifndef S_IREAD
23822 +#define S_IREAD 0000400
23823 +#endif
23824 +
23825 +#ifndef S_IWRITE
23826 +#define S_IWRITE 0000200
23827 +#endif
23828
23829 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
23830 +#ifndef S_IEXEC
23831 +#define S_IEXEC 0000100
23832 +#endif
23833 +
23834 +#ifndef XATTR_CREATE
23835 +#define XATTR_CREATE 1
23836 +#endif
23837 +
23838 +#ifndef XATTR_REPLACE
23839 +#define XATTR_REPLACE 2
23840 +#endif
23841 +
23842 +#ifndef R_OK
23843 +#define R_OK 4
23844 +#define W_OK 2
23845 +#define X_OK 1
23846 +#define F_OK 0
23847 +#endif
23848 +
23849 +#else
23850 +#include <errno.h>
23851 +#include <sys/stat.h>
23852 +#include <fcntl.h>
23853 +#endif
23854 +
23855 +#endif
23856 +
23857 +#ifndef Y_DUMP_STACK
23858 +#define Y_DUMP_STACK() do { } while (0)
23859 +#endif
23860
23861 #ifndef YBUG
23862 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
23863 +#define YBUG() do {\
23864 + T(YAFFS_TRACE_BUG,\
23865 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
23866 + __LINE__));\
23867 + Y_DUMP_STACK();\
23868 +} while (0)
23869 #endif
23870
23871 +
23872 #endif
This page took 1.003261 seconds and 5 git commands to generate.