9d61508ad29eedcccc4ff9e645e2c0dadd8fd5a7
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-2.6.36 / 511-yaffs-git-2010-10-01.patch
1 diff -Nrup a/fs/yaffs2/devextras.h b/fs/yaffs2/devextras.h
2 --- a/fs/yaffs2/devextras.h 2010-10-03 17:48:22.704000363 +0300
3 +++ b/fs/yaffs2/devextras.h 2010-10-03 18:03:47.537000367 +0300
4 @@ -1,7 +1,7 @@
5 /*
6 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
7 *
8 - * Copyright (C) 2002-2007 Aleph One Ltd.
9 + * Copyright (C) 2002-2010 Aleph One Ltd.
10 * for Toby Churchill Ltd and Brightstar Engineering
11 *
12 * Created by Charles Manning <charles@aleph1.co.uk>
13 @@ -24,6 +24,8 @@
14 #define __EXTRAS_H__
15
16
17 +#include "yportenv.h"
18 +
19 #if !(defined __KERNEL__)
20
21 /* Definition of types */
22 @@ -33,103 +35,6 @@ typedef unsigned __u32;
23
24 #endif
25
26 -/*
27 - * This is a simple doubly linked list implementation that matches the
28 - * way the Linux kernel doubly linked list implementation works.
29 - */
30 -
31 -struct ylist_head {
32 - struct ylist_head *next; /* next in chain */
33 - struct ylist_head *prev; /* previous in chain */
34 -};
35 -
36 -
37 -/* Initialise a static list */
38 -#define YLIST_HEAD(name) \
39 -struct ylist_head name = { &(name), &(name)}
40 -
41 -
42 -
43 -/* Initialise a list head to an empty list */
44 -#define YINIT_LIST_HEAD(p) \
45 -do { \
46 - (p)->next = (p);\
47 - (p)->prev = (p); \
48 -} while (0)
49 -
50 -
51 -/* Add an element to a list */
52 -static __inline__ void ylist_add(struct ylist_head *newEntry,
53 - struct ylist_head *list)
54 -{
55 - struct ylist_head *listNext = list->next;
56 -
57 - list->next = newEntry;
58 - newEntry->prev = list;
59 - newEntry->next = listNext;
60 - listNext->prev = newEntry;
61 -
62 -}
63 -
64 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
65 - struct ylist_head *list)
66 -{
67 - struct ylist_head *listPrev = list->prev;
68 -
69 - list->prev = newEntry;
70 - newEntry->next = list;
71 - newEntry->prev = listPrev;
72 - listPrev->next = newEntry;
73 -
74 -}
75 -
76 -
77 -/* Take an element out of its current list, with or without
78 - * reinitialising the links.of the entry*/
79 -static __inline__ void ylist_del(struct ylist_head *entry)
80 -{
81 - struct ylist_head *listNext = entry->next;
82 - struct ylist_head *listPrev = entry->prev;
83 -
84 - listNext->prev = listPrev;
85 - listPrev->next = listNext;
86 -
87 -}
88 -
89 -static __inline__ void ylist_del_init(struct ylist_head *entry)
90 -{
91 - ylist_del(entry);
92 - entry->next = entry->prev = entry;
93 -}
94 -
95 -
96 -/* Test if the list is empty */
97 -static __inline__ int ylist_empty(struct ylist_head *entry)
98 -{
99 - return (entry->next == entry);
100 -}
101 -
102 -
103 -/* ylist_entry takes a pointer to a list entry and offsets it to that
104 - * we can find a pointer to the object it is embedded in.
105 - */
106 -
107 -
108 -#define ylist_entry(entry, type, member) \
109 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
110 -
111 -
112 -/* ylist_for_each and list_for_each_safe iterate over lists.
113 - * ylist_for_each_safe uses temporary storage to make the list delete safe
114 - */
115 -
116 -#define ylist_for_each(itervar, list) \
117 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
118 -
119 -#define ylist_for_each_safe(itervar, saveVar, list) \
120 - for (itervar = (list)->next, saveVar = (list)->next->next; \
121 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
122 -
123
124 #if !(defined __KERNEL__)
125
126 diff -Nrup a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
127 --- a/fs/yaffs2/Kconfig 2010-10-03 17:48:22.704000363 +0300
128 +++ b/fs/yaffs2/Kconfig 2010-10-03 18:03:47.461000368 +0300
129 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
130
131 If unsure, say Y.
132
133 -config YAFFS_DISABLE_LAZY_LOAD
134 - bool "Disable lazy loading"
135 - depends on YAFFS_YAFFS2
136 +config YAFFS_DISABLE_TAGS_ECC
137 + bool "Disable YAFFS from doing ECC on tags by default"
138 + depends on YAFFS_FS && YAFFS_YAFFS2
139 default n
140 help
141 - "Lazy loading" defers loading file details until they are
142 - required. This saves mount time, but makes the first look-up
143 - a bit longer.
144 -
145 - Lazy loading will only happen if enabled by this option being 'n'
146 - and if the appropriate tags are available, else yaffs2 will
147 - automatically fall back to immediate loading and do the right
148 - thing.
149 -
150 - Lazy laoding will be required by checkpointing.
151 -
152 - Setting this to 'y' will disable lazy loading.
153 + This defaults Yaffs to using its own ECC calculations on tags instead of
154 + just relying on the MTD.
155 + This behavior can also be overridden with tags_ecc_on and
156 + tags_ecc_off mount options.
157
158 If unsure, say N.
159
160 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
161 but makes look-ups faster.
162
163 If unsure, say Y.
164 +
165 +config YAFFS_EMPTY_LOST_AND_FOUND
166 + bool "Empty lost and found on boot"
167 + depends on YAFFS_FS
168 + default n
169 + help
170 + If this is enabled then the contents of lost and found is
171 + automatically dumped at mount.
172 +
173 + If unsure, say N.
174 +
175 +config YAFFS_DISABLE_BLOCK_REFRESHING
176 + bool "Disable yaffs2 block refreshing"
177 + depends on YAFFS_FS
178 + default n
179 + help
180 + If this is set, then block refreshing is disabled.
181 + Block refreshing infrequently refreshes the oldest block in
182 + a yaffs2 file system. This mechanism helps to refresh flash to
183 + mitigate against data loss. This is particularly useful for MLC.
184 +
185 + If unsure, say N.
186 +
187 +config YAFFS_DISABLE_BACKGROUND
188 + bool "Disable yaffs2 background processing"
189 + depends on YAFFS_FS
190 + default n
191 + help
192 + If this is set, then background processing is disabled.
193 + Background processing makes many foreground activities faster.
194 +
195 + If unsure, say N.
196 +
197 +config YAFFS_XATTR
198 + bool "Enable yaffs2 xattr support"
199 + depends on YAFFS_FS
200 + default y
201 + help
202 + If this is set then yaffs2 will provide xattr support.
203 + If unsure, say Y.
204 +
205 +
206 diff -Nrup a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
207 --- a/fs/yaffs2/Makefile 2010-10-03 17:48:22.705000363 +0300
208 +++ b/fs/yaffs2/Makefile 2010-10-03 18:03:47.460000369 +0300
209 @@ -4,7 +4,14 @@
210
211 obj-$(CONFIG_YAFFS_FS) += yaffs.o
212
213 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
214 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
215 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
216 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
217 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
218 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
219 +yaffs-y += yaffs_nameval.o
220 +yaffs-y += yaffs_allocator.o
221 +yaffs-y += yaffs_yaffs1.o
222 +yaffs-y += yaffs_yaffs2.o
223 +yaffs-y += yaffs_bitmap.o
224 +yaffs-y += yaffs_verify.o
225 +
226 diff -Nrup a/fs/yaffs2/moduleconfig.h b/fs/yaffs2/moduleconfig.h
227 --- a/fs/yaffs2/moduleconfig.h 2010-10-03 17:48:22.705000363 +0300
228 +++ b/fs/yaffs2/moduleconfig.h 2010-10-03 18:03:47.538000366 +0300
229 @@ -1,7 +1,7 @@
230 /*
231 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
232 *
233 - * Copyright (C) 2002-2007 Aleph One Ltd.
234 + * Copyright (C) 2002-2010 Aleph One Ltd.
235 * for Toby Churchill Ltd and Brightstar Engineering
236 *
237 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
238 @@ -29,22 +29,43 @@
239 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
240 /* #define CONFIG_YAFFS_DOES_ECC */
241
242 +/* Default: Selected */
243 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
244 +#define CONFIG_YAFFS_DOES_TAGS_ECC
245 +
246 /* Default: Not selected */
247 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
248 /* CONFIG_YAFFS_DOES_ECC is set */
249 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
250
251 -/* Default: Selected */
252 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
253 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
254 +/* Default: Not selected */
255 +/* Meaning: Always test whether chunks are erased before writing to them.
256 + Use during mtd debugging and init. */
257 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
258 +
259 +/* Default: Not Selected */
260 +/* Meaning: At mount automatically empty all files from lost and found. */
261 +/* This is done to fix an old problem where rmdir was not checking for an */
262 +/* empty directory. This can also be achieved with a mount option. */
263 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
264
265 /* Default: Selected */
266 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
267 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
268
269 -/* Default: 10 */
270 -/* Meaning: set the count of blocks to reserve for checkpointing */
271 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
272 +/* Default: Unselected */
273 +/* Meaning: Select to disable block refreshing. */
274 +/* Block Refreshing periodically rewrites the oldest block. */
275 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
276 +
277 +/* Default: Unselected */
278 +/* Meaning: Select to disable background processing */
279 +/* #define CONFIG_DISABLE_BACKGROUND */
280 +
281 +
282 +/* Default: Selected */
283 +/* Meaning: Enable XATTR support */
284 +#define CONFIG_YAFFS_XATTR
285
286 /*
287 Older-style on-NAND data format has a "pageStatus" byte to record
288 diff -Nrup a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c
289 --- a/fs/yaffs2/yaffs_allocator.c 1970-01-01 02:00:00.000000000 +0200
290 +++ b/fs/yaffs2/yaffs_allocator.c 2010-10-03 18:03:47.504000356 +0300
291 @@ -0,0 +1,409 @@
292 +/*
293 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
294 + *
295 + * Copyright (C) 2002-2010 Aleph One Ltd.
296 + * for Toby Churchill Ltd and Brightstar Engineering
297 + *
298 + * Created by Charles Manning <charles@aleph1.co.uk>
299 + *
300 + * This program is free software; you can redistribute it and/or modify
301 + * it under the terms of the GNU Lesser General Public License version 2.1 as
302 + * published by the Free Software Foundation.
303 + *
304 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
305 + */
306 +
307 +
308 +#include "yaffs_allocator.h"
309 +#include "yaffs_guts.h"
310 +#include "yaffs_trace.h"
311 +#include "yportenv.h"
312 +
313 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
314 +
315 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
316 +{
317 + dev = dev;
318 +}
319 +
320 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
321 +{
322 + dev = dev;
323 +}
324 +
325 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
326 +{
327 + return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
328 +}
329 +
330 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
331 +{
332 + dev = dev;
333 + YFREE(tn);
334 +}
335 +
336 +void yaffs_InitialiseRawObjects(yaffs_Device *dev)
337 +{
338 + dev = dev;
339 +}
340 +
341 +void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
342 +{
343 + dev = dev;
344 +}
345 +
346 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
347 +{
348 + dev = dev;
349 + return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
350 +}
351 +
352 +
353 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
354 +{
355 +
356 + dev = dev;
357 + YFREE(obj);
358 +}
359 +
360 +#else
361 +
362 +struct yaffs_TnodeList_struct {
363 + struct yaffs_TnodeList_struct *next;
364 + yaffs_Tnode *tnodes;
365 +};
366 +
367 +typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
368 +
369 +struct yaffs_ObjectList_struct {
370 + yaffs_Object *objects;
371 + struct yaffs_ObjectList_struct *next;
372 +};
373 +
374 +typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
375 +
376 +
377 +struct yaffs_AllocatorStruct {
378 + int nTnodesCreated;
379 + yaffs_Tnode *freeTnodes;
380 + int nFreeTnodes;
381 + yaffs_TnodeList *allocatedTnodeList;
382 +
383 + int nObjectsCreated;
384 + yaffs_Object *freeObjects;
385 + int nFreeObjects;
386 +
387 + yaffs_ObjectList *allocatedObjectList;
388 +};
389 +
390 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
391 +
392 +
393 +static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
394 +{
395 +
396 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
397 +
398 + yaffs_TnodeList *tmp;
399 +
400 + if(!allocator){
401 + YBUG();
402 + return;
403 + }
404 +
405 + while (allocator->allocatedTnodeList) {
406 + tmp = allocator->allocatedTnodeList->next;
407 +
408 + YFREE(allocator->allocatedTnodeList->tnodes);
409 + YFREE(allocator->allocatedTnodeList);
410 + allocator->allocatedTnodeList = tmp;
411 +
412 + }
413 +
414 + allocator->freeTnodes = NULL;
415 + allocator->nFreeTnodes = 0;
416 + allocator->nTnodesCreated = 0;
417 +}
418 +
419 +static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
420 +{
421 + yaffs_Allocator *allocator = dev->allocator;
422 +
423 + if(allocator){
424 + allocator->allocatedTnodeList = NULL;
425 + allocator->freeTnodes = NULL;
426 + allocator->nFreeTnodes = 0;
427 + allocator->nTnodesCreated = 0;
428 + } else
429 + YBUG();
430 +}
431 +
432 +static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
433 +{
434 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
435 + int i;
436 + yaffs_Tnode *newTnodes;
437 + __u8 *mem;
438 + yaffs_Tnode *curr;
439 + yaffs_Tnode *next;
440 + yaffs_TnodeList *tnl;
441 +
442 + if(!allocator){
443 + YBUG();
444 + return YAFFS_FAIL;
445 + }
446 +
447 + if (nTnodes < 1)
448 + return YAFFS_OK;
449 +
450 +
451 + /* make these things */
452 +
453 + newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
454 + mem = (__u8 *)newTnodes;
455 +
456 + if (!newTnodes) {
457 + T(YAFFS_TRACE_ERROR,
458 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
459 + return YAFFS_FAIL;
460 + }
461 +
462 + /* New hookup for wide tnodes */
463 + for (i = 0; i < nTnodes - 1; i++) {
464 + curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
465 + next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
466 + curr->internal[0] = next;
467 + }
468 +
469 + curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
470 + curr->internal[0] = allocator->freeTnodes;
471 + allocator->freeTnodes = (yaffs_Tnode *)mem;
472 +
473 + allocator->nFreeTnodes += nTnodes;
474 + allocator->nTnodesCreated += nTnodes;
475 +
476 + /* Now add this bunch of tnodes to a list for freeing up.
477 + * NB If we can't add this to the management list it isn't fatal
478 + * but it just means we can't free this bunch of tnodes later.
479 + */
480 +
481 + tnl = YMALLOC(sizeof(yaffs_TnodeList));
482 + if (!tnl) {
483 + T(YAFFS_TRACE_ERROR,
484 + (TSTR
485 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
486 + return YAFFS_FAIL;
487 + } else {
488 + tnl->tnodes = newTnodes;
489 + tnl->next = allocator->allocatedTnodeList;
490 + allocator->allocatedTnodeList = tnl;
491 + }
492 +
493 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
494 +
495 + return YAFFS_OK;
496 +}
497 +
498 +
499 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
500 +{
501 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
502 + yaffs_Tnode *tn = NULL;
503 +
504 + if(!allocator){
505 + YBUG();
506 + return NULL;
507 + }
508 +
509 + /* If there are none left make more */
510 + if (!allocator->freeTnodes)
511 + yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
512 +
513 + if (allocator->freeTnodes) {
514 + tn = allocator->freeTnodes;
515 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
516 + allocator->nFreeTnodes--;
517 + }
518 +
519 + return tn;
520 +}
521 +
522 +/* FreeTnode frees up a tnode and puts it back on the free list */
523 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
524 +{
525 + yaffs_Allocator *allocator = dev->allocator;
526 +
527 + if(!allocator){
528 + YBUG();
529 + return;
530 + }
531 +
532 + if (tn) {
533 + tn->internal[0] = allocator->freeTnodes;
534 + allocator->freeTnodes = tn;
535 + allocator->nFreeTnodes++;
536 + }
537 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
538 +}
539 +
540 +
541 +
542 +static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
543 +{
544 + yaffs_Allocator *allocator = dev->allocator;
545 +
546 + if(allocator) {
547 + allocator->allocatedObjectList = NULL;
548 + allocator->freeObjects = NULL;
549 + allocator->nFreeObjects = 0;
550 + } else
551 + YBUG();
552 +}
553 +
554 +static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
555 +{
556 + yaffs_Allocator *allocator = dev->allocator;
557 + yaffs_ObjectList *tmp;
558 +
559 + if(!allocator){
560 + YBUG();
561 + return;
562 + }
563 +
564 + while (allocator->allocatedObjectList) {
565 + tmp = allocator->allocatedObjectList->next;
566 + YFREE(allocator->allocatedObjectList->objects);
567 + YFREE(allocator->allocatedObjectList);
568 +
569 + allocator->allocatedObjectList = tmp;
570 + }
571 +
572 + allocator->freeObjects = NULL;
573 + allocator->nFreeObjects = 0;
574 + allocator->nObjectsCreated = 0;
575 +}
576 +
577 +
578 +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
579 +{
580 + yaffs_Allocator *allocator = dev->allocator;
581 +
582 + int i;
583 + yaffs_Object *newObjects;
584 + yaffs_ObjectList *list;
585 +
586 + if(!allocator){
587 + YBUG();
588 + return YAFFS_FAIL;
589 + }
590 +
591 + if (nObjects < 1)
592 + return YAFFS_OK;
593 +
594 + /* make these things */
595 + newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
596 + list = YMALLOC(sizeof(yaffs_ObjectList));
597 +
598 + if (!newObjects || !list) {
599 + if (newObjects){
600 + YFREE(newObjects);
601 + newObjects = NULL;
602 + }
603 + if (list){
604 + YFREE(list);
605 + list = NULL;
606 + }
607 + T(YAFFS_TRACE_ALLOCATE,
608 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
609 + return YAFFS_FAIL;
610 + }
611 +
612 + /* Hook them into the free list */
613 + for (i = 0; i < nObjects - 1; i++) {
614 + newObjects[i].siblings.next =
615 + (struct ylist_head *)(&newObjects[i + 1]);
616 + }
617 +
618 + newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
619 + allocator->freeObjects = newObjects;
620 + allocator->nFreeObjects += nObjects;
621 + allocator->nObjectsCreated += nObjects;
622 +
623 + /* Now add this bunch of Objects to a list for freeing up. */
624 +
625 + list->objects = newObjects;
626 + list->next = allocator->allocatedObjectList;
627 + allocator->allocatedObjectList = list;
628 +
629 + return YAFFS_OK;
630 +}
631 +
632 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
633 +{
634 + yaffs_Object *obj = NULL;
635 + yaffs_Allocator *allocator = dev->allocator;
636 +
637 + if(!allocator) {
638 + YBUG();
639 + return obj;
640 + }
641 +
642 + /* If there are none left make more */
643 + if (!allocator->freeObjects)
644 + yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
645 +
646 + if (allocator->freeObjects) {
647 + obj = allocator->freeObjects;
648 + allocator->freeObjects =
649 + (yaffs_Object *) (allocator->freeObjects->siblings.next);
650 + allocator->nFreeObjects--;
651 + }
652 +
653 + return obj;
654 +}
655 +
656 +
657 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
658 +{
659 +
660 + yaffs_Allocator *allocator = dev->allocator;
661 +
662 + if(!allocator)
663 + YBUG();
664 + else {
665 + /* Link into the free list. */
666 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
667 + allocator->freeObjects = obj;
668 + allocator->nFreeObjects++;
669 + }
670 +}
671 +
672 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
673 +{
674 + if(dev->allocator){
675 + yaffs_DeinitialiseRawTnodes(dev);
676 + yaffs_DeinitialiseRawObjects(dev);
677 +
678 + YFREE(dev->allocator);
679 + dev->allocator=NULL;
680 + } else
681 + YBUG();
682 +}
683 +
684 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
685 +{
686 + yaffs_Allocator *allocator;
687 +
688 + if(!dev->allocator){
689 + allocator = YMALLOC(sizeof(yaffs_Allocator));
690 + if(allocator){
691 + dev->allocator = allocator;
692 + yaffs_InitialiseRawTnodes(dev);
693 + yaffs_InitialiseRawObjects(dev);
694 + }
695 + } else
696 + YBUG();
697 +}
698 +
699 +
700 +#endif
701 diff -Nrup a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h
702 --- a/fs/yaffs2/yaffs_allocator.h 1970-01-01 02:00:00.000000000 +0200
703 +++ b/fs/yaffs2/yaffs_allocator.h 2010-10-03 18:03:47.538000366 +0300
704 @@ -0,0 +1,30 @@
705 +/*
706 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
707 + *
708 + * Copyright (C) 2002-2010 Aleph One Ltd.
709 + * for Toby Churchill Ltd and Brightstar Engineering
710 + *
711 + * Created by Charles Manning <charles@aleph1.co.uk>
712 + *
713 + * This program is free software; you can redistribute it and/or modify
714 + * it under the terms of the GNU Lesser General Public License version 2.1 as
715 + * published by the Free Software Foundation.
716 + *
717 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
718 + */
719 +
720 +#ifndef __YAFFS_ALLOCATOR_H__
721 +#define __YAFFS_ALLOCATOR_H__
722 +
723 +#include "yaffs_guts.h"
724 +
725 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
726 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
727 +
728 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
729 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
730 +
731 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
732 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
733 +
734 +#endif
735 diff -Nrup a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c
736 --- a/fs/yaffs2/yaffs_bitmap.c 1970-01-01 02:00:00.000000000 +0200
737 +++ b/fs/yaffs2/yaffs_bitmap.c 2010-10-03 18:03:47.505000364 +0300
738 @@ -0,0 +1,105 @@
739 +/*
740 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
741 + *
742 + * Copyright (C) 2002-2010 Aleph One Ltd.
743 + * for Toby Churchill Ltd and Brightstar Engineering
744 + *
745 + * Created by Charles Manning <charles@aleph1.co.uk>
746 + *
747 + * This program is free software; you can redistribute it and/or modify
748 + * it under the terms of the GNU General Public License version 2 as
749 + * published by the Free Software Foundation.
750 + */
751 +
752 +#include "yaffs_bitmap.h"
753 +#include "yaffs_trace.h"
754 +/*
755 + * Chunk bitmap manipulations
756 + */
757 +
758 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
759 +{
760 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
761 + T(YAFFS_TRACE_ERROR,
762 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
763 + blk));
764 + YBUG();
765 + }
766 + return dev->chunkBits +
767 + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
768 +}
769 +
770 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
771 +{
772 + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
773 + chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
774 + T(YAFFS_TRACE_ERROR,
775 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
776 + blk, chunk));
777 + YBUG();
778 + }
779 +}
780 +
781 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
782 +{
783 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
784 +
785 + memset(blkBits, 0, dev->chunkBitmapStride);
786 +}
787 +
788 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
789 +{
790 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
791 +
792 + yaffs_VerifyChunkBitId(dev, blk, chunk);
793 +
794 + blkBits[chunk / 8] &= ~(1 << (chunk & 7));
795 +}
796 +
797 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
798 +{
799 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
800 +
801 + yaffs_VerifyChunkBitId(dev, blk, chunk);
802 +
803 + blkBits[chunk / 8] |= (1 << (chunk & 7));
804 +}
805 +
806 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
807 +{
808 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
809 + yaffs_VerifyChunkBitId(dev, blk, chunk);
810 +
811 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
812 +}
813 +
814 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
815 +{
816 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
817 + int i;
818 + for (i = 0; i < dev->chunkBitmapStride; i++) {
819 + if (*blkBits)
820 + return 1;
821 + blkBits++;
822 + }
823 + return 0;
824 +}
825 +
826 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
827 +{
828 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
829 + int i;
830 + int n = 0;
831 + for (i = 0; i < dev->chunkBitmapStride; i++) {
832 + __u8 x = *blkBits;
833 + while (x) {
834 + if (x & 1)
835 + n++;
836 + x >>= 1;
837 + }
838 +
839 + blkBits++;
840 + }
841 + return n;
842 +}
843 +
844 diff -Nrup a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h
845 --- a/fs/yaffs2/yaffs_bitmap.h 1970-01-01 02:00:00.000000000 +0200
846 +++ b/fs/yaffs2/yaffs_bitmap.h 2010-10-03 18:03:47.539000363 +0300
847 @@ -0,0 +1,31 @@
848 +/*
849 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
850 + *
851 + * Copyright (C) 2002-2010 Aleph One Ltd.
852 + * for Toby Churchill Ltd and Brightstar Engineering
853 + *
854 + * Created by Charles Manning <charles@aleph1.co.uk>
855 + *
856 + * This program is free software; you can redistribute it and/or modify
857 + * it under the terms of the GNU General Public License version 2 as
858 + * published by the Free Software Foundation.
859 + */
860 +
861 +/*
862 + * Chunk bitmap manipulations
863 + */
864 +
865 +#ifndef __YAFFS_BITMAP_H__
866 +#define __YAFFS_BITMAP_H__
867 +
868 +#include "yaffs_guts.h"
869 +
870 +void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
871 +void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
872 +void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
873 +void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
874 +int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
875 +int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
876 +int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
877 +
878 +#endif
879 diff -Nrup a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
880 --- a/fs/yaffs2/yaffs_checkptrw.c 2010-10-03 17:48:22.706000363 +0300
881 +++ b/fs/yaffs2/yaffs_checkptrw.c 2010-10-03 18:03:47.505000364 +0300
882 @@ -1,7 +1,7 @@
883 /*
884 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
885 *
886 - * Copyright (C) 2002-2007 Aleph One Ltd.
887 + * Copyright (C) 2002-2010 Aleph One Ltd.
888 * for Toby Churchill Ltd and Brightstar Engineering
889 *
890 * Created by Charles Manning <charles@aleph1.co.uk>
891 @@ -11,16 +11,12 @@
892 * published by the Free Software Foundation.
893 */
894
895 -const char *yaffs_checkptrw_c_version =
896 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
897 -
898 -
899 #include "yaffs_checkptrw.h"
900 #include "yaffs_getblockinfo.h"
901
902 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
903 +static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev)
904 {
905 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
906 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
907
908 T(YAFFS_TRACE_CHECKPOINT,
909 (TSTR("checkpt blocks available = %d" TENDSTR),
910 @@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs
911 }
912
913
914 -static int yaffs_CheckpointErase(yaffs_Device *dev)
915 +static int yaffs2_CheckpointErase(yaffs_Device *dev)
916 {
917 int i;
918
919 - if (!dev->eraseBlockInNAND)
920 + if (!dev->param.eraseBlockInNAND)
921 return 0;
922 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
923 dev->internalStartBlock, dev->internalEndBlock));
924 @@ -43,12 +39,15 @@ static int yaffs_CheckpointErase(yaffs_D
925 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
926 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
927 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
928 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
929 +
930 + dev->nBlockErasures++;
931 +
932 + if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
933 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
934 dev->nErasedBlocks++;
935 - dev->nFreeChunks += dev->nChunksPerBlock;
936 + dev->nFreeChunks += dev->param.nChunksPerBlock;
937 } else {
938 - dev->markNANDBlockBad(dev, i);
939 + dev->param.markNANDBlockBad(dev, i);
940 bi->blockState = YAFFS_BLOCK_STATE_DEAD;
941 }
942 }
943 @@ -60,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_D
944 }
945
946
947 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
948 +static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev)
949 {
950 int i;
951 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
952 + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
953 T(YAFFS_TRACE_CHECKPOINT,
954 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
955 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
956 + dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
957
958 if (dev->checkpointNextBlock >= 0 &&
959 dev->checkpointNextBlock <= dev->internalEndBlock &&
960 @@ -88,7 +87,7 @@ static void yaffs_CheckpointFindNextEras
961 dev->checkpointCurrentBlock = -1;
962 }
963
964 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
965 +static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
966 {
967 int i;
968 yaffs_ExtendedTags tags;
969 @@ -98,10 +97,10 @@ static void yaffs_CheckpointFindNextChec
970
971 if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
972 for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
973 - int chunk = i * dev->nChunksPerBlock;
974 + int chunk = i * dev->param.nChunksPerBlock;
975 int realignedChunk = chunk - dev->chunkOffset;
976
977 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
978 + dev->param.readChunkWithTagsFromNAND(dev, realignedChunk,
979 NULL, &tags);
980 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
981 i, tags.objectId, tags.sequenceNumber, tags.eccResult));
982 @@ -124,29 +123,29 @@ static void yaffs_CheckpointFindNextChec
983 }
984
985
986 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
987 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting)
988 {
989
990 +
991 + dev->checkpointOpenForWrite = forWriting;
992 +
993 /* Got the functions we need? */
994 - if (!dev->writeChunkWithTagsToNAND ||
995 - !dev->readChunkWithTagsFromNAND ||
996 - !dev->eraseBlockInNAND ||
997 - !dev->markNANDBlockBad)
998 + if (!dev->param.writeChunkWithTagsToNAND ||
999 + !dev->param.readChunkWithTagsFromNAND ||
1000 + !dev->param.eraseBlockInNAND ||
1001 + !dev->param.markNANDBlockBad)
1002 return 0;
1003
1004 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
1005 + if (forWriting && !yaffs2_CheckpointSpaceOk(dev))
1006 return 0;
1007
1008 if (!dev->checkpointBuffer)
1009 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1010 + dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk);
1011 if (!dev->checkpointBuffer)
1012 return 0;
1013
1014
1015 dev->checkpointPageSequence = 0;
1016 -
1017 - dev->checkpointOpenForWrite = forWriting;
1018 -
1019 dev->checkpointByteCount = 0;
1020 dev->checkpointSum = 0;
1021 dev->checkpointXor = 0;
1022 @@ -158,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1023 if (forWriting) {
1024 memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1025 dev->checkpointByteOffset = 0;
1026 - return yaffs_CheckpointErase(dev);
1027 + return yaffs2_CheckpointErase(dev);
1028 } else {
1029 int i;
1030 /* Set to a value that will kick off a read */
1031 @@ -168,6 +167,9 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1032 dev->blocksInCheckpoint = 0;
1033 dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1034 dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1035 + if(!dev->checkpointBlockList)
1036 + return 0;
1037 +
1038 for (i = 0; i < dev->checkpointMaxBlocks; i++)
1039 dev->checkpointBlockList[i] = -1;
1040 }
1041 @@ -175,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
1042 return 1;
1043 }
1044
1045 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1046 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1047 {
1048 __u32 compositeSum;
1049 compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1050 @@ -183,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device
1051 return 1;
1052 }
1053
1054 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1055 +static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev)
1056 {
1057 int chunk;
1058 int realignedChunk;
1059 @@ -191,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(y
1060 yaffs_ExtendedTags tags;
1061
1062 if (dev->checkpointCurrentBlock < 0) {
1063 - yaffs_CheckpointFindNextErasedBlock(dev);
1064 + yaffs2_CheckpointFindNextErasedBlock(dev);
1065 dev->checkpointCurrentChunk = 0;
1066 }
1067
1068 @@ -211,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(y
1069 dev->blocksInCheckpoint++;
1070 }
1071
1072 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1073 + chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk;
1074
1075
1076 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1077 @@ -219,12 +221,14 @@ static int yaffs_CheckpointFlushBuffer(y
1078
1079 realignedChunk = chunk - dev->chunkOffset;
1080
1081 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1082 + dev->nPageWrites++;
1083 +
1084 + dev->param.writeChunkWithTagsToNAND(dev, realignedChunk,
1085 dev->checkpointBuffer, &tags);
1086 dev->checkpointByteOffset = 0;
1087 dev->checkpointPageSequence++;
1088 dev->checkpointCurrentChunk++;
1089 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1090 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) {
1091 dev->checkpointCurrentChunk = 0;
1092 dev->checkpointCurrentBlock = -1;
1093 }
1094 @@ -234,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(y
1095 }
1096
1097
1098 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1099 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1100 {
1101 int i = 0;
1102 int ok = 1;
1103 @@ -263,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *
1104
1105 if (dev->checkpointByteOffset < 0 ||
1106 dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1107 - ok = yaffs_CheckpointFlushBuffer(dev);
1108 + ok = yaffs2_CheckpointFlushBuffer(dev);
1109 }
1110
1111 return i;
1112 }
1113
1114 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1115 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1116 {
1117 int i = 0;
1118 int ok = 1;
1119 @@ -294,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1120 dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1121
1122 if (dev->checkpointCurrentBlock < 0) {
1123 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1124 + yaffs2_CheckpointFindNextCheckpointBlock(dev);
1125 dev->checkpointCurrentChunk = 0;
1126 }
1127
1128 @@ -302,14 +306,16 @@ int yaffs_CheckpointRead(yaffs_Device *d
1129 ok = 0;
1130 else {
1131 chunk = dev->checkpointCurrentBlock *
1132 - dev->nChunksPerBlock +
1133 + dev->param.nChunksPerBlock +
1134 dev->checkpointCurrentChunk;
1135
1136 realignedChunk = chunk - dev->chunkOffset;
1137 +
1138 + dev->nPageReads++;
1139
1140 /* read in the next chunk */
1141 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1142 - dev->readChunkWithTagsFromNAND(dev,
1143 + dev->param.readChunkWithTagsFromNAND(dev,
1144 realignedChunk,
1145 dev->checkpointBuffer,
1146 &tags);
1147 @@ -323,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
1148 dev->checkpointPageSequence++;
1149 dev->checkpointCurrentChunk++;
1150
1151 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1152 + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock)
1153 dev->checkpointCurrentBlock = -1;
1154 }
1155 }
1156 @@ -342,17 +348,20 @@ int yaffs_CheckpointRead(yaffs_Device *d
1157 return i;
1158 }
1159
1160 -int yaffs_CheckpointClose(yaffs_Device *dev)
1161 +int yaffs2_CheckpointClose(yaffs_Device *dev)
1162 {
1163
1164 if (dev->checkpointOpenForWrite) {
1165 if (dev->checkpointByteOffset != 0)
1166 - yaffs_CheckpointFlushBuffer(dev);
1167 - } else {
1168 + yaffs2_CheckpointFlushBuffer(dev);
1169 + } else if(dev->checkpointBlockList){
1170 int i;
1171 for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1172 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1173 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1174 + int blk = dev->checkpointBlockList[i];
1175 + yaffs_BlockInfo *bi = NULL;
1176 + if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
1177 + bi = yaffs_GetBlockInfo(dev, blk);
1178 + if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1179 bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1180 else {
1181 /* Todo this looks odd... */
1182 @@ -362,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *
1183 dev->checkpointBlockList = NULL;
1184 }
1185
1186 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1187 + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock;
1188 dev->nErasedBlocks -= dev->blocksInCheckpoint;
1189
1190
1191 @@ -378,16 +387,14 @@ int yaffs_CheckpointClose(yaffs_Device *
1192 return 0;
1193 }
1194
1195 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1196 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev)
1197 {
1198 - /* Erase the first checksum block */
1199 -
1200 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1201 + /* Erase the checkpoint data */
1202
1203 - if (!yaffs_CheckpointSpaceOk(dev))
1204 - return 0;
1205 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1206 + dev->blocksInCheckpoint));
1207
1208 - return yaffs_CheckpointErase(dev);
1209 + return yaffs2_CheckpointErase(dev);
1210 }
1211
1212
1213 diff -Nrup a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h
1214 --- a/fs/yaffs2/yaffs_checkptrw.h 2010-10-03 17:48:22.706000363 +0300
1215 +++ b/fs/yaffs2/yaffs_checkptrw.h 2010-10-03 18:03:47.540000359 +0300
1216 @@ -1,7 +1,7 @@
1217 /*
1218 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1219 *
1220 - * Copyright (C) 2002-2007 Aleph One Ltd.
1221 + * Copyright (C) 2002-2010 Aleph One Ltd.
1222 * for Toby Churchill Ltd and Brightstar Engineering
1223 *
1224 * Created by Charles Manning <charles@aleph1.co.uk>
1225 @@ -18,18 +18,17 @@
1226
1227 #include "yaffs_guts.h"
1228
1229 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1230 +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting);
1231
1232 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1233 +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1234
1235 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1236 +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1237
1238 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1239 +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1240
1241 -int yaffs_CheckpointClose(yaffs_Device *dev);
1242 +int yaffs2_CheckpointClose(yaffs_Device *dev);
1243
1244 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1245 +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev);
1246
1247
1248 #endif
1249 -
1250 diff -Nrup a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c
1251 --- a/fs/yaffs2/yaffs_ecc.c 2010-10-03 17:48:22.706000363 +0300
1252 +++ b/fs/yaffs2/yaffs_ecc.c 2010-10-03 18:03:47.509000373 +0300
1253 @@ -1,7 +1,7 @@
1254 /*
1255 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1256 *
1257 - * Copyright (C) 2002-2007 Aleph One Ltd.
1258 + * Copyright (C) 2002-2010 Aleph One Ltd.
1259 * for Toby Churchill Ltd and Brightstar Engineering
1260 *
1261 * Created by Charles Manning <charles@aleph1.co.uk>
1262 @@ -28,9 +28,6 @@
1263 * this bytes influence on the line parity.
1264 */
1265
1266 -const char *yaffs_ecc_c_version =
1267 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1268 -
1269 #include "yportenv.h"
1270
1271 #include "yaffs_ecc.h"
1272 diff -Nrup a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h
1273 --- a/fs/yaffs2/yaffs_ecc.h 2010-10-03 17:48:22.707000363 +0300
1274 +++ b/fs/yaffs2/yaffs_ecc.h 2010-10-03 18:03:47.541000359 +0300
1275 @@ -1,7 +1,7 @@
1276 /*
1277 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1278 *
1279 - * Copyright (C) 2002-2007 Aleph One Ltd.
1280 + * Copyright (C) 2002-2010 Aleph One Ltd.
1281 * for Toby Churchill Ltd and Brightstar Engineering
1282 *
1283 * Created by Charles Manning <charles@aleph1.co.uk>
1284 diff -Nrup a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
1285 --- a/fs/yaffs2/yaffs_fs.c 2010-10-03 17:48:22.708000363 +0300
1286 +++ b/fs/yaffs2/yaffs_fs.c 1970-01-01 02:00:00.000000000 +0200
1287 @@ -1,2529 +0,0 @@
1288 -/*
1289 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1290 - *
1291 - * Copyright (C) 2002-2009 Aleph One Ltd.
1292 - * for Toby Churchill Ltd and Brightstar Engineering
1293 - *
1294 - * Created by Charles Manning <charles@aleph1.co.uk>
1295 - * Acknowledgements:
1296 - * Luc van OostenRyck for numerous patches.
1297 - * Nick Bane for numerous patches.
1298 - * Nick Bane for 2.5/2.6 integration.
1299 - * Andras Toth for mknod rdev issue.
1300 - * Michael Fischer for finding the problem with inode inconsistency.
1301 - * Some code bodily lifted from JFFS
1302 - *
1303 - * This program is free software; you can redistribute it and/or modify
1304 - * it under the terms of the GNU General Public License version 2 as
1305 - * published by the Free Software Foundation.
1306 - */
1307 -
1308 -/*
1309 - *
1310 - * This is the file system front-end to YAFFS that hooks it up to
1311 - * the VFS.
1312 - *
1313 - * Special notes:
1314 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1315 - * this superblock
1316 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1317 - * superblock
1318 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1319 - */
1320 -
1321 -const char *yaffs_fs_c_version =
1322 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1323 -extern const char *yaffs_guts_c_version;
1324 -
1325 -#include <linux/version.h>
1326 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1327 -#include <linux/config.h>
1328 -#endif
1329 -#include <linux/kernel.h>
1330 -#include <linux/module.h>
1331 -#include <linux/slab.h>
1332 -#include <linux/init.h>
1333 -#include <linux/fs.h>
1334 -#include <linux/proc_fs.h>
1335 -#include <linux/smp_lock.h>
1336 -#include <linux/pagemap.h>
1337 -#include <linux/mtd/mtd.h>
1338 -#include <linux/interrupt.h>
1339 -#include <linux/string.h>
1340 -#include <linux/ctype.h>
1341 -
1342 -#include "asm/div64.h"
1343 -
1344 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1345 -
1346 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1347 -#include <linux/statfs.h>
1348 -#define UnlockPage(p) unlock_page(p)
1349 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1350 -
1351 -/* FIXME: use sb->s_id instead ? */
1352 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1353 -
1354 -#else
1355 -
1356 -#include <linux/locks.h>
1357 -#define BDEVNAME_SIZE 0
1358 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1359 -
1360 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1361 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1362 -#define __user
1363 -#endif
1364 -
1365 -#endif
1366 -
1367 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1368 -#define YPROC_ROOT (&proc_root)
1369 -#else
1370 -#define YPROC_ROOT NULL
1371 -#endif
1372 -
1373 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1374 -#define WRITE_SIZE_STR "writesize"
1375 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1376 -#else
1377 -#define WRITE_SIZE_STR "oobblock"
1378 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1379 -#endif
1380 -
1381 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1382 -#define YAFFS_USE_WRITE_BEGIN_END 1
1383 -#else
1384 -#define YAFFS_USE_WRITE_BEGIN_END 0
1385 -#endif
1386 -
1387 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1388 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1389 -{
1390 - uint64_t result = partition_size;
1391 - do_div(result, block_size);
1392 - return (uint32_t)result;
1393 -}
1394 -#else
1395 -#define YCALCBLOCKS(s, b) ((s)/(b))
1396 -#endif
1397 -
1398 -#include <linux/uaccess.h>
1399 -
1400 -#include "yportenv.h"
1401 -#include "yaffs_guts.h"
1402 -
1403 -#include <linux/mtd/mtd.h>
1404 -#include "yaffs_mtdif.h"
1405 -#include "yaffs_mtdif1.h"
1406 -#include "yaffs_mtdif2.h"
1407 -
1408 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1409 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1410 -unsigned int yaffs_auto_checkpoint = 1;
1411 -
1412 -/* Module Parameters */
1413 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1414 -module_param(yaffs_traceMask, uint, 0644);
1415 -module_param(yaffs_wr_attempts, uint, 0644);
1416 -module_param(yaffs_auto_checkpoint, uint, 0644);
1417 -#else
1418 -MODULE_PARM(yaffs_traceMask, "i");
1419 -MODULE_PARM(yaffs_wr_attempts, "i");
1420 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1421 -#endif
1422 -
1423 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1424 -/* use iget and read_inode */
1425 -#define Y_IGET(sb, inum) iget((sb), (inum))
1426 -static void yaffs_read_inode(struct inode *inode);
1427 -
1428 -#else
1429 -/* Call local equivalent */
1430 -#define YAFFS_USE_OWN_IGET
1431 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1432 -
1433 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1434 -#endif
1435 -
1436 -/*#define T(x) printk x */
1437 -
1438 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1439 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1440 -#else
1441 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1442 -#endif
1443 -
1444 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1445 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1446 -
1447 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1448 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1449 -#else
1450 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1451 -#endif
1452 -
1453 -static void yaffs_put_super(struct super_block *sb);
1454 -
1455 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1456 - loff_t *pos);
1457 -static ssize_t yaffs_hold_space(struct file *f);
1458 -static void yaffs_release_space(struct file *f);
1459 -
1460 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1461 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1462 -#else
1463 -static int yaffs_file_flush(struct file *file);
1464 -#endif
1465 -
1466 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1467 - int datasync);
1468 -
1469 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1470 -
1471 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1472 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1473 - struct nameidata *n);
1474 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1475 - struct nameidata *n);
1476 -#else
1477 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1478 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1479 -#endif
1480 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1481 - struct dentry *dentry);
1482 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1483 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1484 - const char *symname);
1485 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1486 -
1487 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1488 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1489 - dev_t dev);
1490 -#else
1491 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1492 - int dev);
1493 -#endif
1494 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1495 - struct inode *new_dir, struct dentry *new_dentry);
1496 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1497 -
1498 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1499 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1500 -static void yaffs_write_super(struct super_block *sb);
1501 -#else
1502 -static int yaffs_sync_fs(struct super_block *sb);
1503 -static int yaffs_write_super(struct super_block *sb);
1504 -#endif
1505 -
1506 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1507 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1508 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1509 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1510 -#else
1511 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1512 -#endif
1513 -
1514 -#ifdef YAFFS_HAS_PUT_INODE
1515 -static void yaffs_put_inode(struct inode *inode);
1516 -#endif
1517 -
1518 -static void yaffs_delete_inode(struct inode *);
1519 -static void yaffs_clear_inode(struct inode *);
1520 -
1521 -static int yaffs_readpage(struct file *file, struct page *page);
1522 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1523 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1524 -#else
1525 -static int yaffs_writepage(struct page *page);
1526 -#endif
1527 -
1528 -
1529 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1530 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1531 - loff_t pos, unsigned len, unsigned flags,
1532 - struct page **pagep, void **fsdata);
1533 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1534 - loff_t pos, unsigned len, unsigned copied,
1535 - struct page *pg, void *fsdadata);
1536 -#else
1537 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1538 - unsigned offset, unsigned to);
1539 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1540 - unsigned to);
1541 -
1542 -#endif
1543 -
1544 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1545 - int buflen);
1546 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1547 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1548 -#else
1549 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1550 -#endif
1551 -
1552 -static struct address_space_operations yaffs_file_address_operations = {
1553 - .readpage = yaffs_readpage,
1554 - .writepage = yaffs_writepage,
1555 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1556 - .write_begin = yaffs_write_begin,
1557 - .write_end = yaffs_write_end,
1558 -#else
1559 - .prepare_write = yaffs_prepare_write,
1560 - .commit_write = yaffs_commit_write,
1561 -#endif
1562 -};
1563 -
1564 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1565 -static const struct file_operations yaffs_file_operations = {
1566 - .read = do_sync_read,
1567 - .write = do_sync_write,
1568 - .aio_read = generic_file_aio_read,
1569 - .aio_write = generic_file_aio_write,
1570 - .mmap = generic_file_mmap,
1571 - .flush = yaffs_file_flush,
1572 - .fsync = yaffs_sync_object,
1573 - .splice_read = generic_file_splice_read,
1574 - .splice_write = generic_file_splice_write,
1575 - .llseek = generic_file_llseek,
1576 -};
1577 -
1578 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1579 -
1580 -static const struct file_operations yaffs_file_operations = {
1581 - .read = do_sync_read,
1582 - .write = do_sync_write,
1583 - .aio_read = generic_file_aio_read,
1584 - .aio_write = generic_file_aio_write,
1585 - .mmap = generic_file_mmap,
1586 - .flush = yaffs_file_flush,
1587 - .fsync = yaffs_sync_object,
1588 - .sendfile = generic_file_sendfile,
1589 -};
1590 -
1591 -#else
1592 -
1593 -static const struct file_operations yaffs_file_operations = {
1594 - .read = generic_file_read,
1595 - .write = generic_file_write,
1596 - .mmap = generic_file_mmap,
1597 - .flush = yaffs_file_flush,
1598 - .fsync = yaffs_sync_object,
1599 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1600 - .sendfile = generic_file_sendfile,
1601 -#endif
1602 -};
1603 -#endif
1604 -
1605 -static const struct inode_operations yaffs_file_inode_operations = {
1606 - .setattr = yaffs_setattr,
1607 -};
1608 -
1609 -static const struct inode_operations yaffs_symlink_inode_operations = {
1610 - .readlink = yaffs_readlink,
1611 - .follow_link = yaffs_follow_link,
1612 - .setattr = yaffs_setattr,
1613 -};
1614 -
1615 -static const struct inode_operations yaffs_dir_inode_operations = {
1616 - .create = yaffs_create,
1617 - .lookup = yaffs_lookup,
1618 - .link = yaffs_link,
1619 - .unlink = yaffs_unlink,
1620 - .symlink = yaffs_symlink,
1621 - .mkdir = yaffs_mkdir,
1622 - .rmdir = yaffs_unlink,
1623 - .mknod = yaffs_mknod,
1624 - .rename = yaffs_rename,
1625 - .setattr = yaffs_setattr,
1626 -};
1627 -
1628 -static const struct file_operations yaffs_dir_operations = {
1629 - .read = generic_read_dir,
1630 - .readdir = yaffs_readdir,
1631 - .fsync = yaffs_sync_object,
1632 -};
1633 -
1634 -static const struct super_operations yaffs_super_ops = {
1635 - .statfs = yaffs_statfs,
1636 -
1637 -#ifndef YAFFS_USE_OWN_IGET
1638 - .read_inode = yaffs_read_inode,
1639 -#endif
1640 -#ifdef YAFFS_HAS_PUT_INODE
1641 - .put_inode = yaffs_put_inode,
1642 -#endif
1643 - .put_super = yaffs_put_super,
1644 - .delete_inode = yaffs_delete_inode,
1645 - .clear_inode = yaffs_clear_inode,
1646 - .sync_fs = yaffs_sync_fs,
1647 - .write_super = yaffs_write_super,
1648 -};
1649 -
1650 -static void yaffs_GrossLock(yaffs_Device *dev)
1651 -{
1652 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
1653 - down(&dev->grossLock);
1654 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
1655 -}
1656 -
1657 -static void yaffs_GrossUnlock(yaffs_Device *dev)
1658 -{
1659 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
1660 - up(&dev->grossLock);
1661 -}
1662 -
1663 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1664 - int buflen)
1665 -{
1666 - unsigned char *alias;
1667 - int ret;
1668 -
1669 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1670 -
1671 - yaffs_GrossLock(dev);
1672 -
1673 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1674 -
1675 - yaffs_GrossUnlock(dev);
1676 -
1677 - if (!alias)
1678 - return -ENOMEM;
1679 -
1680 - ret = vfs_readlink(dentry, buffer, buflen, alias);
1681 - kfree(alias);
1682 - return ret;
1683 -}
1684 -
1685 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1686 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1687 -#else
1688 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1689 -#endif
1690 -{
1691 - unsigned char *alias;
1692 - int ret;
1693 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1694 -
1695 - yaffs_GrossLock(dev);
1696 -
1697 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1698 -
1699 - yaffs_GrossUnlock(dev);
1700 -
1701 - if (!alias) {
1702 - ret = -ENOMEM;
1703 - goto out;
1704 - }
1705 -
1706 - ret = vfs_follow_link(nd, alias);
1707 - kfree(alias);
1708 -out:
1709 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1710 - return ERR_PTR(ret);
1711 -#else
1712 - return ret;
1713 -#endif
1714 -}
1715 -
1716 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1717 - yaffs_Object *obj);
1718 -
1719 -/*
1720 - * Lookup is used to find objects in the fs
1721 - */
1722 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1723 -
1724 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1725 - struct nameidata *n)
1726 -#else
1727 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
1728 -#endif
1729 -{
1730 - yaffs_Object *obj;
1731 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
1732 -
1733 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
1734 -
1735 - yaffs_GrossLock(dev);
1736 -
1737 - T(YAFFS_TRACE_OS,
1738 - ("yaffs_lookup for %d:%s\n",
1739 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
1740 -
1741 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
1742 - dentry->d_name.name);
1743 -
1744 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
1745 -
1746 - /* Can't hold gross lock when calling yaffs_get_inode() */
1747 - yaffs_GrossUnlock(dev);
1748 -
1749 - if (obj) {
1750 - T(YAFFS_TRACE_OS,
1751 - ("yaffs_lookup found %d\n", obj->objectId));
1752 -
1753 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1754 -
1755 - if (inode) {
1756 - T(YAFFS_TRACE_OS,
1757 - ("yaffs_loookup dentry \n"));
1758 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
1759 - * d_add even if NULL inode */
1760 -#if 0
1761 - /*dget(dentry); // try to solve directory bug */
1762 - d_add(dentry, inode);
1763 -
1764 - /* return dentry; */
1765 - return NULL;
1766 -#endif
1767 - }
1768 -
1769 - } else {
1770 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
1771 -
1772 - }
1773 -
1774 -/* added NCB for 2.5/6 compatability - forces add even if inode is
1775 - * NULL which creates dentry hash */
1776 - d_add(dentry, inode);
1777 -
1778 - return NULL;
1779 -}
1780 -
1781 -
1782 -#ifdef YAFFS_HAS_PUT_INODE
1783 -
1784 -/* For now put inode is just for debugging
1785 - * Put inode is called when the inode **structure** is put.
1786 - */
1787 -static void yaffs_put_inode(struct inode *inode)
1788 -{
1789 - T(YAFFS_TRACE_OS,
1790 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
1791 - atomic_read(&inode->i_count)));
1792 -
1793 -}
1794 -#endif
1795 -
1796 -/* clear is called to tell the fs to release any per-inode data it holds */
1797 -static void yaffs_clear_inode(struct inode *inode)
1798 -{
1799 - yaffs_Object *obj;
1800 - yaffs_Device *dev;
1801 -
1802 - obj = yaffs_InodeToObject(inode);
1803 -
1804 - T(YAFFS_TRACE_OS,
1805 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1806 - atomic_read(&inode->i_count),
1807 - obj ? "object exists" : "null object"));
1808 -
1809 - if (obj) {
1810 - dev = obj->myDev;
1811 - yaffs_GrossLock(dev);
1812 -
1813 - /* Clear the association between the inode and
1814 - * the yaffs_Object.
1815 - */
1816 - obj->myInode = NULL;
1817 - yaffs_InodeToObjectLV(inode) = NULL;
1818 -
1819 - /* If the object freeing was deferred, then the real
1820 - * free happens now.
1821 - * This should fix the inode inconsistency problem.
1822 - */
1823 -
1824 - yaffs_HandleDeferedFree(obj);
1825 -
1826 - yaffs_GrossUnlock(dev);
1827 - }
1828 -
1829 -}
1830 -
1831 -/* delete is called when the link count is zero and the inode
1832 - * is put (ie. nobody wants to know about it anymore, time to
1833 - * delete the file).
1834 - * NB Must call clear_inode()
1835 - */
1836 -static void yaffs_delete_inode(struct inode *inode)
1837 -{
1838 - yaffs_Object *obj = yaffs_InodeToObject(inode);
1839 - yaffs_Device *dev;
1840 -
1841 - T(YAFFS_TRACE_OS,
1842 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1843 - atomic_read(&inode->i_count),
1844 - obj ? "object exists" : "null object"));
1845 -
1846 - if (obj) {
1847 - dev = obj->myDev;
1848 - yaffs_GrossLock(dev);
1849 - yaffs_DeleteObject(obj);
1850 - yaffs_GrossUnlock(dev);
1851 - }
1852 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1853 - truncate_inode_pages(&inode->i_data, 0);
1854 -#endif
1855 - clear_inode(inode);
1856 -}
1857 -
1858 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1859 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
1860 -#else
1861 -static int yaffs_file_flush(struct file *file)
1862 -#endif
1863 -{
1864 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1865 -
1866 - yaffs_Device *dev = obj->myDev;
1867 -
1868 - T(YAFFS_TRACE_OS,
1869 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
1870 - obj->dirty ? "dirty" : "clean"));
1871 -
1872 - yaffs_GrossLock(dev);
1873 -
1874 - yaffs_FlushFile(obj, 1);
1875 -
1876 - yaffs_GrossUnlock(dev);
1877 -
1878 - return 0;
1879 -}
1880 -
1881 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
1882 -{
1883 - /* Lifted from jffs2 */
1884 -
1885 - yaffs_Object *obj;
1886 - unsigned char *pg_buf;
1887 - int ret;
1888 -
1889 - yaffs_Device *dev;
1890 -
1891 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
1892 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
1893 - (unsigned)PAGE_CACHE_SIZE));
1894 -
1895 - obj = yaffs_DentryToObject(f->f_dentry);
1896 -
1897 - dev = obj->myDev;
1898 -
1899 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1900 - BUG_ON(!PageLocked(pg));
1901 -#else
1902 - if (!PageLocked(pg))
1903 - PAGE_BUG(pg);
1904 -#endif
1905 -
1906 - pg_buf = kmap(pg);
1907 - /* FIXME: Can kmap fail? */
1908 -
1909 - yaffs_GrossLock(dev);
1910 -
1911 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
1912 - pg->index << PAGE_CACHE_SHIFT,
1913 - PAGE_CACHE_SIZE);
1914 -
1915 - yaffs_GrossUnlock(dev);
1916 -
1917 - if (ret >= 0)
1918 - ret = 0;
1919 -
1920 - if (ret) {
1921 - ClearPageUptodate(pg);
1922 - SetPageError(pg);
1923 - } else {
1924 - SetPageUptodate(pg);
1925 - ClearPageError(pg);
1926 - }
1927 -
1928 - flush_dcache_page(pg);
1929 - kunmap(pg);
1930 -
1931 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
1932 - return ret;
1933 -}
1934 -
1935 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1936 -{
1937 - int ret = yaffs_readpage_nolock(f, pg);
1938 - UnlockPage(pg);
1939 - return ret;
1940 -}
1941 -
1942 -static int yaffs_readpage(struct file *f, struct page *pg)
1943 -{
1944 - return yaffs_readpage_unlock(f, pg);
1945 -}
1946 -
1947 -/* writepage inspired by/stolen from smbfs */
1948 -
1949 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1950 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1951 -#else
1952 -static int yaffs_writepage(struct page *page)
1953 -#endif
1954 -{
1955 - struct address_space *mapping = page->mapping;
1956 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
1957 - struct inode *inode;
1958 - unsigned long end_index;
1959 - char *buffer;
1960 - yaffs_Object *obj;
1961 - int nWritten = 0;
1962 - unsigned nBytes;
1963 -
1964 - if (!mapping)
1965 - BUG();
1966 - inode = mapping->host;
1967 - if (!inode)
1968 - BUG();
1969 -
1970 - if (offset > inode->i_size) {
1971 - T(YAFFS_TRACE_OS,
1972 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
1973 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
1974 - (unsigned)inode->i_size));
1975 - T(YAFFS_TRACE_OS,
1976 - (" -> don't care!!\n"));
1977 - unlock_page(page);
1978 - return 0;
1979 - }
1980 -
1981 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1982 -
1983 - /* easy case */
1984 - if (page->index < end_index)
1985 - nBytes = PAGE_CACHE_SIZE;
1986 - else
1987 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
1988 -
1989 - get_page(page);
1990 -
1991 - buffer = kmap(page);
1992 -
1993 - obj = yaffs_InodeToObject(inode);
1994 - yaffs_GrossLock(obj->myDev);
1995 -
1996 - T(YAFFS_TRACE_OS,
1997 - ("yaffs_writepage at %08x, size %08x\n",
1998 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
1999 - T(YAFFS_TRACE_OS,
2000 - ("writepag0: obj = %05x, ino = %05x\n",
2001 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2002 -
2003 - nWritten = yaffs_WriteDataToFile(obj, buffer,
2004 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
2005 -
2006 - T(YAFFS_TRACE_OS,
2007 - ("writepag1: obj = %05x, ino = %05x\n",
2008 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2009 -
2010 - yaffs_GrossUnlock(obj->myDev);
2011 -
2012 - kunmap(page);
2013 - SetPageUptodate(page);
2014 - UnlockPage(page);
2015 - put_page(page);
2016 -
2017 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2018 -}
2019 -
2020 -
2021 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2022 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2023 - loff_t pos, unsigned len, unsigned flags,
2024 - struct page **pagep, void **fsdata)
2025 -{
2026 - struct page *pg = NULL;
2027 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2028 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2029 - uint32_t to = offset + len;
2030 -
2031 - int ret = 0;
2032 - int space_held = 0;
2033 -
2034 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2035 - /* Get a page */
2036 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2037 - pg = grab_cache_page_write_begin(mapping, index, flags);
2038 -#else
2039 - pg = __grab_cache_page(mapping, index);
2040 -#endif
2041 -
2042 - *pagep = pg;
2043 - if (!pg) {
2044 - ret = -ENOMEM;
2045 - goto out;
2046 - }
2047 - /* Get fs space */
2048 - space_held = yaffs_hold_space(filp);
2049 -
2050 - if (!space_held) {
2051 - ret = -ENOSPC;
2052 - goto out;
2053 - }
2054 -
2055 - /* Update page if required */
2056 -
2057 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2058 - ret = yaffs_readpage_nolock(filp, pg);
2059 -
2060 - if (ret)
2061 - goto out;
2062 -
2063 - /* Happy path return */
2064 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2065 -
2066 - return 0;
2067 -
2068 -out:
2069 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2070 - if (space_held)
2071 - yaffs_release_space(filp);
2072 - if (pg) {
2073 - unlock_page(pg);
2074 - page_cache_release(pg);
2075 - }
2076 - return ret;
2077 -}
2078 -
2079 -#else
2080 -
2081 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2082 - unsigned offset, unsigned to)
2083 -{
2084 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2085 -
2086 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2087 - return yaffs_readpage_nolock(f, pg);
2088 - return 0;
2089 -}
2090 -#endif
2091 -
2092 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2093 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2094 - loff_t pos, unsigned len, unsigned copied,
2095 - struct page *pg, void *fsdadata)
2096 -{
2097 - int ret = 0;
2098 - void *addr, *kva;
2099 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2100 -
2101 - kva = kmap(pg);
2102 - addr = kva + offset_into_page;
2103 -
2104 - T(YAFFS_TRACE_OS,
2105 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2106 - (unsigned) addr,
2107 - (int)pos, copied));
2108 -
2109 - ret = yaffs_file_write(filp, addr, copied, &pos);
2110 -
2111 - if (ret != copied) {
2112 - T(YAFFS_TRACE_OS,
2113 - ("yaffs_write_end not same size ret %d copied %d\n",
2114 - ret, copied));
2115 - SetPageError(pg);
2116 - ClearPageUptodate(pg);
2117 - } else {
2118 - SetPageUptodate(pg);
2119 - }
2120 -
2121 - kunmap(pg);
2122 -
2123 - yaffs_release_space(filp);
2124 - unlock_page(pg);
2125 - page_cache_release(pg);
2126 - return ret;
2127 -}
2128 -#else
2129 -
2130 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2131 - unsigned to)
2132 -{
2133 - void *addr, *kva;
2134 -
2135 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2136 - int nBytes = to - offset;
2137 - int nWritten;
2138 -
2139 - unsigned spos = pos;
2140 - unsigned saddr;
2141 -
2142 - kva = kmap(pg);
2143 - addr = kva + offset;
2144 -
2145 - saddr = (unsigned) addr;
2146 -
2147 - T(YAFFS_TRACE_OS,
2148 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2149 - saddr, spos, nBytes));
2150 -
2151 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2152 -
2153 - if (nWritten != nBytes) {
2154 - T(YAFFS_TRACE_OS,
2155 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2156 - nWritten, nBytes));
2157 - SetPageError(pg);
2158 - ClearPageUptodate(pg);
2159 - } else {
2160 - SetPageUptodate(pg);
2161 - }
2162 -
2163 - kunmap(pg);
2164 -
2165 - T(YAFFS_TRACE_OS,
2166 - ("yaffs_commit_write returning %d\n",
2167 - nWritten == nBytes ? 0 : nWritten));
2168 -
2169 - return nWritten == nBytes ? 0 : nWritten;
2170 -}
2171 -#endif
2172 -
2173 -
2174 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2175 -{
2176 - if (inode && obj) {
2177 -
2178 -
2179 - /* Check mode against the variant type and attempt to repair if broken. */
2180 - __u32 mode = obj->yst_mode;
2181 - switch (obj->variantType) {
2182 - case YAFFS_OBJECT_TYPE_FILE:
2183 - if (!S_ISREG(mode)) {
2184 - obj->yst_mode &= ~S_IFMT;
2185 - obj->yst_mode |= S_IFREG;
2186 - }
2187 -
2188 - break;
2189 - case YAFFS_OBJECT_TYPE_SYMLINK:
2190 - if (!S_ISLNK(mode)) {
2191 - obj->yst_mode &= ~S_IFMT;
2192 - obj->yst_mode |= S_IFLNK;
2193 - }
2194 -
2195 - break;
2196 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2197 - if (!S_ISDIR(mode)) {
2198 - obj->yst_mode &= ~S_IFMT;
2199 - obj->yst_mode |= S_IFDIR;
2200 - }
2201 -
2202 - break;
2203 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2204 - case YAFFS_OBJECT_TYPE_HARDLINK:
2205 - case YAFFS_OBJECT_TYPE_SPECIAL:
2206 - default:
2207 - /* TODO? */
2208 - break;
2209 - }
2210 -
2211 - inode->i_flags |= S_NOATIME;
2212 -
2213 - inode->i_ino = obj->objectId;
2214 - inode->i_mode = obj->yst_mode;
2215 - inode->i_uid = obj->yst_uid;
2216 - inode->i_gid = obj->yst_gid;
2217 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2218 - inode->i_blksize = inode->i_sb->s_blocksize;
2219 -#endif
2220 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2221 -
2222 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2223 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2224 - inode->i_atime.tv_nsec = 0;
2225 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2226 - inode->i_mtime.tv_nsec = 0;
2227 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2228 - inode->i_ctime.tv_nsec = 0;
2229 -#else
2230 - inode->i_rdev = obj->yst_rdev;
2231 - inode->i_atime = obj->yst_atime;
2232 - inode->i_mtime = obj->yst_mtime;
2233 - inode->i_ctime = obj->yst_ctime;
2234 -#endif
2235 - inode->i_size = yaffs_GetObjectFileLength(obj);
2236 - inode->i_blocks = (inode->i_size + 511) >> 9;
2237 -
2238 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2239 -
2240 - T(YAFFS_TRACE_OS,
2241 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2242 - inode->i_mode, inode->i_uid, inode->i_gid,
2243 - (int)inode->i_size, atomic_read(&inode->i_count)));
2244 -
2245 - switch (obj->yst_mode & S_IFMT) {
2246 - default: /* fifo, device or socket */
2247 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2248 - init_special_inode(inode, obj->yst_mode,
2249 - old_decode_dev(obj->yst_rdev));
2250 -#else
2251 - init_special_inode(inode, obj->yst_mode,
2252 - (dev_t) (obj->yst_rdev));
2253 -#endif
2254 - break;
2255 - case S_IFREG: /* file */
2256 - inode->i_op = &yaffs_file_inode_operations;
2257 - inode->i_fop = &yaffs_file_operations;
2258 - inode->i_mapping->a_ops =
2259 - &yaffs_file_address_operations;
2260 - break;
2261 - case S_IFDIR: /* directory */
2262 - inode->i_op = &yaffs_dir_inode_operations;
2263 - inode->i_fop = &yaffs_dir_operations;
2264 - break;
2265 - case S_IFLNK: /* symlink */
2266 - inode->i_op = &yaffs_symlink_inode_operations;
2267 - break;
2268 - }
2269 -
2270 - yaffs_InodeToObjectLV(inode) = obj;
2271 -
2272 - obj->myInode = inode;
2273 -
2274 - } else {
2275 - T(YAFFS_TRACE_OS,
2276 - ("yaffs_FileInode invalid parameters\n"));
2277 - }
2278 -
2279 -}
2280 -
2281 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2282 - yaffs_Object *obj)
2283 -{
2284 - struct inode *inode;
2285 -
2286 - if (!sb) {
2287 - T(YAFFS_TRACE_OS,
2288 - ("yaffs_get_inode for NULL super_block!!\n"));
2289 - return NULL;
2290 -
2291 - }
2292 -
2293 - if (!obj) {
2294 - T(YAFFS_TRACE_OS,
2295 - ("yaffs_get_inode for NULL object!!\n"));
2296 - return NULL;
2297 -
2298 - }
2299 -
2300 - T(YAFFS_TRACE_OS,
2301 - ("yaffs_get_inode for object %d\n", obj->objectId));
2302 -
2303 - inode = Y_IGET(sb, obj->objectId);
2304 - if (IS_ERR(inode))
2305 - return NULL;
2306 -
2307 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2308 - /* iget also increments the inode's i_count */
2309 - /* NB You can't be holding grossLock or deadlock will happen! */
2310 -
2311 - return inode;
2312 -}
2313 -
2314 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2315 - loff_t *pos)
2316 -{
2317 - yaffs_Object *obj;
2318 - int nWritten, ipos;
2319 - struct inode *inode;
2320 - yaffs_Device *dev;
2321 -
2322 - obj = yaffs_DentryToObject(f->f_dentry);
2323 -
2324 - dev = obj->myDev;
2325 -
2326 - yaffs_GrossLock(dev);
2327 -
2328 - inode = f->f_dentry->d_inode;
2329 -
2330 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2331 - ipos = inode->i_size;
2332 - else
2333 - ipos = *pos;
2334 -
2335 - if (!obj)
2336 - T(YAFFS_TRACE_OS,
2337 - ("yaffs_file_write: hey obj is null!\n"));
2338 - else
2339 - T(YAFFS_TRACE_OS,
2340 - ("yaffs_file_write about to write writing %zu bytes"
2341 - "to object %d at %d\n",
2342 - n, obj->objectId, ipos));
2343 -
2344 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2345 -
2346 - T(YAFFS_TRACE_OS,
2347 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2348 - n, nWritten, ipos));
2349 -
2350 - if (nWritten > 0) {
2351 - ipos += nWritten;
2352 - *pos = ipos;
2353 - if (ipos > inode->i_size) {
2354 - inode->i_size = ipos;
2355 - inode->i_blocks = (ipos + 511) >> 9;
2356 -
2357 - T(YAFFS_TRACE_OS,
2358 - ("yaffs_file_write size updated to %d bytes, "
2359 - "%d blocks\n",
2360 - ipos, (int)(inode->i_blocks)));
2361 - }
2362 -
2363 - }
2364 - yaffs_GrossUnlock(dev);
2365 - return nWritten == 0 ? -ENOSPC : nWritten;
2366 -}
2367 -
2368 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2369 -/* For now we just assume few parallel writes and check against a small number. */
2370 -/* Todo: need to do this with a counter to handle parallel reads better */
2371 -
2372 -static ssize_t yaffs_hold_space(struct file *f)
2373 -{
2374 - yaffs_Object *obj;
2375 - yaffs_Device *dev;
2376 -
2377 - int nFreeChunks;
2378 -
2379 -
2380 - obj = yaffs_DentryToObject(f->f_dentry);
2381 -
2382 - dev = obj->myDev;
2383 -
2384 - yaffs_GrossLock(dev);
2385 -
2386 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2387 -
2388 - yaffs_GrossUnlock(dev);
2389 -
2390 - return (nFreeChunks > 20) ? 1 : 0;
2391 -}
2392 -
2393 -static void yaffs_release_space(struct file *f)
2394 -{
2395 - yaffs_Object *obj;
2396 - yaffs_Device *dev;
2397 -
2398 -
2399 - obj = yaffs_DentryToObject(f->f_dentry);
2400 -
2401 - dev = obj->myDev;
2402 -
2403 - yaffs_GrossLock(dev);
2404 -
2405 -
2406 - yaffs_GrossUnlock(dev);
2407 -}
2408 -
2409 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2410 -{
2411 - yaffs_Object *obj;
2412 - yaffs_Device *dev;
2413 - struct inode *inode = f->f_dentry->d_inode;
2414 - unsigned long offset, curoffs;
2415 - struct ylist_head *i;
2416 - yaffs_Object *l;
2417 -
2418 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2419 -
2420 - obj = yaffs_DentryToObject(f->f_dentry);
2421 - dev = obj->myDev;
2422 -
2423 - yaffs_GrossLock(dev);
2424 -
2425 - offset = f->f_pos;
2426 -
2427 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2428 -
2429 - if (offset == 0) {
2430 - T(YAFFS_TRACE_OS,
2431 - ("yaffs_readdir: entry . ino %d \n",
2432 - (int)inode->i_ino));
2433 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2434 - goto out;
2435 - offset++;
2436 - f->f_pos++;
2437 - }
2438 - if (offset == 1) {
2439 - T(YAFFS_TRACE_OS,
2440 - ("yaffs_readdir: entry .. ino %d \n",
2441 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2442 - if (filldir(dirent, "..", 2, offset,
2443 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2444 - goto out;
2445 - offset++;
2446 - f->f_pos++;
2447 - }
2448 -
2449 - curoffs = 1;
2450 -
2451 - /* If the directory has changed since the open or last call to
2452 - readdir, rewind to after the 2 canned entries. */
2453 -
2454 - if (f->f_version != inode->i_version) {
2455 - offset = 2;
2456 - f->f_pos = offset;
2457 - f->f_version = inode->i_version;
2458 - }
2459 -
2460 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2461 - curoffs++;
2462 - if (curoffs >= offset) {
2463 - l = ylist_entry(i, yaffs_Object, siblings);
2464 -
2465 - yaffs_GetObjectName(l, name,
2466 - YAFFS_MAX_NAME_LENGTH + 1);
2467 - T(YAFFS_TRACE_OS,
2468 - ("yaffs_readdir: %s inode %d\n", name,
2469 - yaffs_GetObjectInode(l)));
2470 -
2471 - if (filldir(dirent,
2472 - name,
2473 - strlen(name),
2474 - offset,
2475 - yaffs_GetObjectInode(l),
2476 - yaffs_GetObjectType(l)) < 0)
2477 - goto up_and_out;
2478 -
2479 - offset++;
2480 - f->f_pos++;
2481 - }
2482 - }
2483 -
2484 -up_and_out:
2485 -out:
2486 - yaffs_GrossUnlock(dev);
2487 -
2488 - return 0;
2489 -}
2490 -
2491 -/*
2492 - * File creation. Allocate an inode, and we're done..
2493 - */
2494 -
2495 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2496 -#define YCRED(x) x
2497 -#else
2498 -#define YCRED(x) (x->cred)
2499 -#endif
2500 -
2501 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2502 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2503 - dev_t rdev)
2504 -#else
2505 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2506 - int rdev)
2507 -#endif
2508 -{
2509 - struct inode *inode;
2510 -
2511 - yaffs_Object *obj = NULL;
2512 - yaffs_Device *dev;
2513 -
2514 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2515 -
2516 - int error = -ENOSPC;
2517 - uid_t uid = YCRED(current)->fsuid;
2518 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2519 -
2520 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2521 - mode |= S_ISGID;
2522 -
2523 - if (parent) {
2524 - T(YAFFS_TRACE_OS,
2525 - ("yaffs_mknod: parent object %d type %d\n",
2526 - parent->objectId, parent->variantType));
2527 - } else {
2528 - T(YAFFS_TRACE_OS,
2529 - ("yaffs_mknod: could not get parent object\n"));
2530 - return -EPERM;
2531 - }
2532 -
2533 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2534 - "mode %x dev %x\n",
2535 - dentry->d_name.name, mode, rdev));
2536 -
2537 - dev = parent->myDev;
2538 -
2539 - yaffs_GrossLock(dev);
2540 -
2541 - switch (mode & S_IFMT) {
2542 - default:
2543 - /* Special (socket, fifo, device...) */
2544 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2545 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2546 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2547 - gid, old_encode_dev(rdev));
2548 -#else
2549 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2550 - gid, rdev);
2551 -#endif
2552 - break;
2553 - case S_IFREG: /* file */
2554 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2555 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2556 - gid);
2557 - break;
2558 - case S_IFDIR: /* directory */
2559 - T(YAFFS_TRACE_OS,
2560 - ("yaffs_mknod: making directory\n"));
2561 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2562 - uid, gid);
2563 - break;
2564 - case S_IFLNK: /* symlink */
2565 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2566 - obj = NULL; /* Do we ever get here? */
2567 - break;
2568 - }
2569 -
2570 - /* Can not call yaffs_get_inode() with gross lock held */
2571 - yaffs_GrossUnlock(dev);
2572 -
2573 - if (obj) {
2574 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2575 - d_instantiate(dentry, inode);
2576 - T(YAFFS_TRACE_OS,
2577 - ("yaffs_mknod created object %d count = %d\n",
2578 - obj->objectId, atomic_read(&inode->i_count)));
2579 - error = 0;
2580 - } else {
2581 - T(YAFFS_TRACE_OS,
2582 - ("yaffs_mknod failed making object\n"));
2583 - error = -ENOMEM;
2584 - }
2585 -
2586 - return error;
2587 -}
2588 -
2589 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2590 -{
2591 - int retVal;
2592 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2593 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2594 - return retVal;
2595 -}
2596 -
2597 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2598 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2599 - struct nameidata *n)
2600 -#else
2601 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2602 -#endif
2603 -{
2604 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
2605 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
2606 -}
2607 -
2608 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
2609 -{
2610 - int retVal;
2611 -
2612 - yaffs_Device *dev;
2613 -
2614 - T(YAFFS_TRACE_OS,
2615 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
2616 - dentry->d_name.name));
2617 -
2618 - dev = yaffs_InodeToObject(dir)->myDev;
2619 -
2620 - yaffs_GrossLock(dev);
2621 -
2622 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
2623 -
2624 - if (retVal == YAFFS_OK) {
2625 - dentry->d_inode->i_nlink--;
2626 - dir->i_version++;
2627 - yaffs_GrossUnlock(dev);
2628 - mark_inode_dirty(dentry->d_inode);
2629 - return 0;
2630 - }
2631 - yaffs_GrossUnlock(dev);
2632 - return -ENOTEMPTY;
2633 -}
2634 -
2635 -/*
2636 - * Create a link...
2637 - */
2638 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
2639 - struct dentry *dentry)
2640 -{
2641 - struct inode *inode = old_dentry->d_inode;
2642 - yaffs_Object *obj = NULL;
2643 - yaffs_Object *link = NULL;
2644 - yaffs_Device *dev;
2645 -
2646 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
2647 -
2648 - obj = yaffs_InodeToObject(inode);
2649 - dev = obj->myDev;
2650 -
2651 - yaffs_GrossLock(dev);
2652 -
2653 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
2654 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
2655 - obj);
2656 -
2657 - if (link) {
2658 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2659 - d_instantiate(dentry, old_dentry->d_inode);
2660 - atomic_inc(&old_dentry->d_inode->i_count);
2661 - T(YAFFS_TRACE_OS,
2662 - ("yaffs_link link count %d i_count %d\n",
2663 - old_dentry->d_inode->i_nlink,
2664 - atomic_read(&old_dentry->d_inode->i_count)));
2665 - }
2666 -
2667 - yaffs_GrossUnlock(dev);
2668 -
2669 - if (link)
2670 - return 0;
2671 -
2672 - return -EPERM;
2673 -}
2674 -
2675 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
2676 - const char *symname)
2677 -{
2678 - yaffs_Object *obj;
2679 - yaffs_Device *dev;
2680 - uid_t uid = YCRED(current)->fsuid;
2681 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2682 -
2683 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
2684 -
2685 - dev = yaffs_InodeToObject(dir)->myDev;
2686 - yaffs_GrossLock(dev);
2687 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
2688 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
2689 - yaffs_GrossUnlock(dev);
2690 -
2691 - if (obj) {
2692 - struct inode *inode;
2693 -
2694 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2695 - d_instantiate(dentry, inode);
2696 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
2697 - return 0;
2698 - } else {
2699 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
2700 - }
2701 -
2702 - return -ENOMEM;
2703 -}
2704 -
2705 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
2706 - int datasync)
2707 -{
2708 -
2709 - yaffs_Object *obj;
2710 - yaffs_Device *dev;
2711 -
2712 - obj = yaffs_DentryToObject(dentry);
2713 -
2714 - dev = obj->myDev;
2715 -
2716 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
2717 - yaffs_GrossLock(dev);
2718 - yaffs_FlushFile(obj, 1);
2719 - yaffs_GrossUnlock(dev);
2720 - return 0;
2721 -}
2722 -
2723 -/*
2724 - * The VFS layer already does all the dentry stuff for rename.
2725 - *
2726 - * NB: POSIX says you can rename an object over an old object of the same name
2727 - */
2728 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
2729 - struct inode *new_dir, struct dentry *new_dentry)
2730 -{
2731 - yaffs_Device *dev;
2732 - int retVal = YAFFS_FAIL;
2733 - yaffs_Object *target;
2734 -
2735 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
2736 - dev = yaffs_InodeToObject(old_dir)->myDev;
2737 -
2738 - yaffs_GrossLock(dev);
2739 -
2740 - /* Check if the target is an existing directory that is not empty. */
2741 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
2742 - new_dentry->d_name.name);
2743 -
2744 -
2745 -
2746 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
2747 - !ylist_empty(&target->variant.directoryVariant.children)) {
2748 -
2749 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
2750 -
2751 - retVal = YAFFS_FAIL;
2752 - } else {
2753 - /* Now does unlinking internally using shadowing mechanism */
2754 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
2755 -
2756 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
2757 - old_dentry->d_name.name,
2758 - yaffs_InodeToObject(new_dir),
2759 - new_dentry->d_name.name);
2760 - }
2761 - yaffs_GrossUnlock(dev);
2762 -
2763 - if (retVal == YAFFS_OK) {
2764 - if (target) {
2765 - new_dentry->d_inode->i_nlink--;
2766 - mark_inode_dirty(new_dentry->d_inode);
2767 - }
2768 -
2769 - return 0;
2770 - } else {
2771 - return -ENOTEMPTY;
2772 - }
2773 -}
2774 -
2775 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
2776 -{
2777 - struct inode *inode = dentry->d_inode;
2778 - int error;
2779 - yaffs_Device *dev;
2780 -
2781 - T(YAFFS_TRACE_OS,
2782 - ("yaffs_setattr of object %d\n",
2783 - yaffs_InodeToObject(inode)->objectId));
2784 -
2785 - error = inode_change_ok(inode, attr);
2786 - if (error == 0) {
2787 - dev = yaffs_InodeToObject(inode)->myDev;
2788 - yaffs_GrossLock(dev);
2789 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
2790 - YAFFS_OK) {
2791 - error = 0;
2792 - } else {
2793 - error = -EPERM;
2794 - }
2795 - yaffs_GrossUnlock(dev);
2796 - if (!error)
2797 - error = inode_setattr(inode, attr);
2798 - }
2799 - return error;
2800 -}
2801 -
2802 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2803 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
2804 -{
2805 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2806 - struct super_block *sb = dentry->d_sb;
2807 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2808 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
2809 -{
2810 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2811 -#else
2812 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
2813 -{
2814 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2815 -#endif
2816 -
2817 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
2818 -
2819 - yaffs_GrossLock(dev);
2820 -
2821 - buf->f_type = YAFFS_MAGIC;
2822 - buf->f_bsize = sb->s_blocksize;
2823 - buf->f_namelen = 255;
2824 -
2825 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
2826 - /* Do this if chunk size is not a power of 2 */
2827 -
2828 - uint64_t bytesInDev;
2829 - uint64_t bytesFree;
2830 -
2831 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
2832 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
2833 -
2834 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
2835 - buf->f_blocks = bytesInDev;
2836 -
2837 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
2838 - ((uint64_t)(dev->nDataBytesPerChunk));
2839 -
2840 - do_div(bytesFree, sb->s_blocksize);
2841 -
2842 - buf->f_bfree = bytesFree;
2843 -
2844 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
2845 -
2846 - buf->f_blocks =
2847 - (dev->endBlock - dev->startBlock + 1) *
2848 - dev->nChunksPerBlock /
2849 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2850 - buf->f_bfree =
2851 - yaffs_GetNumberOfFreeChunks(dev) /
2852 - (sb->s_blocksize / dev->nDataBytesPerChunk);
2853 - } else {
2854 - buf->f_blocks =
2855 - (dev->endBlock - dev->startBlock + 1) *
2856 - dev->nChunksPerBlock *
2857 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2858 -
2859 - buf->f_bfree =
2860 - yaffs_GetNumberOfFreeChunks(dev) *
2861 - (dev->nDataBytesPerChunk / sb->s_blocksize);
2862 - }
2863 -
2864 - buf->f_files = 0;
2865 - buf->f_ffree = 0;
2866 - buf->f_bavail = buf->f_bfree;
2867 -
2868 - yaffs_GrossUnlock(dev);
2869 - return 0;
2870 -}
2871 -
2872 -
2873 -static int yaffs_do_sync_fs(struct super_block *sb)
2874 -{
2875 -
2876 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2877 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
2878 -
2879 - if (sb->s_dirt) {
2880 - yaffs_GrossLock(dev);
2881 -
2882 - if (dev) {
2883 - yaffs_FlushEntireDeviceCache(dev);
2884 - yaffs_CheckpointSave(dev);
2885 - }
2886 -
2887 - yaffs_GrossUnlock(dev);
2888 -
2889 - sb->s_dirt = 0;
2890 - }
2891 - return 0;
2892 -}
2893 -
2894 -
2895 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2896 -static void yaffs_write_super(struct super_block *sb)
2897 -#else
2898 -static int yaffs_write_super(struct super_block *sb)
2899 -#endif
2900 -{
2901 -
2902 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
2903 - if (yaffs_auto_checkpoint >= 2)
2904 - yaffs_do_sync_fs(sb);
2905 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
2906 - return 0;
2907 -#endif
2908 -}
2909 -
2910 -
2911 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2912 -static int yaffs_sync_fs(struct super_block *sb, int wait)
2913 -#else
2914 -static int yaffs_sync_fs(struct super_block *sb)
2915 -#endif
2916 -{
2917 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
2918 -
2919 - if (yaffs_auto_checkpoint >= 1)
2920 - yaffs_do_sync_fs(sb);
2921 -
2922 - return 0;
2923 -}
2924 -
2925 -#ifdef YAFFS_USE_OWN_IGET
2926 -
2927 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
2928 -{
2929 - struct inode *inode;
2930 - yaffs_Object *obj;
2931 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2932 -
2933 - T(YAFFS_TRACE_OS,
2934 - ("yaffs_iget for %lu\n", ino));
2935 -
2936 - inode = iget_locked(sb, ino);
2937 - if (!inode)
2938 - return ERR_PTR(-ENOMEM);
2939 - if (!(inode->i_state & I_NEW))
2940 - return inode;
2941 -
2942 - /* NB This is called as a side effect of other functions, but
2943 - * we had to release the lock to prevent deadlocks, so
2944 - * need to lock again.
2945 - */
2946 -
2947 - yaffs_GrossLock(dev);
2948 -
2949 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2950 -
2951 - yaffs_FillInodeFromObject(inode, obj);
2952 -
2953 - yaffs_GrossUnlock(dev);
2954 -
2955 - unlock_new_inode(inode);
2956 - return inode;
2957 -}
2958 -
2959 -#else
2960 -
2961 -static void yaffs_read_inode(struct inode *inode)
2962 -{
2963 - /* NB This is called as a side effect of other functions, but
2964 - * we had to release the lock to prevent deadlocks, so
2965 - * need to lock again.
2966 - */
2967 -
2968 - yaffs_Object *obj;
2969 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
2970 -
2971 - T(YAFFS_TRACE_OS,
2972 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
2973 -
2974 - yaffs_GrossLock(dev);
2975 -
2976 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2977 -
2978 - yaffs_FillInodeFromObject(inode, obj);
2979 -
2980 - yaffs_GrossUnlock(dev);
2981 -}
2982 -
2983 -#endif
2984 -
2985 -static YLIST_HEAD(yaffs_dev_list);
2986 -
2987 -#if 0 /* not used */
2988 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
2989 -{
2990 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
2991 -
2992 - if (*flags & MS_RDONLY) {
2993 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
2994 -
2995 - T(YAFFS_TRACE_OS,
2996 - ("yaffs_remount_fs: %s: RO\n", dev->name));
2997 -
2998 - yaffs_GrossLock(dev);
2999 -
3000 - yaffs_FlushEntireDeviceCache(dev);
3001 -
3002 - yaffs_CheckpointSave(dev);
3003 -
3004 - if (mtd->sync)
3005 - mtd->sync(mtd);
3006 -
3007 - yaffs_GrossUnlock(dev);
3008 - } else {
3009 - T(YAFFS_TRACE_OS,
3010 - ("yaffs_remount_fs: %s: RW\n", dev->name));
3011 - }
3012 -
3013 - return 0;
3014 -}
3015 -#endif
3016 -
3017 -static void yaffs_put_super(struct super_block *sb)
3018 -{
3019 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3020 -
3021 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3022 -
3023 - yaffs_GrossLock(dev);
3024 -
3025 - yaffs_FlushEntireDeviceCache(dev);
3026 -
3027 - yaffs_CheckpointSave(dev);
3028 -
3029 - if (dev->putSuperFunc)
3030 - dev->putSuperFunc(sb);
3031 -
3032 - yaffs_Deinitialise(dev);
3033 -
3034 - yaffs_GrossUnlock(dev);
3035 -
3036 - /* we assume this is protected by lock_kernel() in mount/umount */
3037 - ylist_del(&dev->devList);
3038 -
3039 - if (dev->spareBuffer) {
3040 - YFREE(dev->spareBuffer);
3041 - dev->spareBuffer = NULL;
3042 - }
3043 -
3044 - kfree(dev);
3045 -}
3046 -
3047 -
3048 -static void yaffs_MTDPutSuper(struct super_block *sb)
3049 -{
3050 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3051 -
3052 - if (mtd->sync)
3053 - mtd->sync(mtd);
3054 -
3055 - put_mtd_device(mtd);
3056 -}
3057 -
3058 -
3059 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3060 -{
3061 - struct super_block *sb = (struct super_block *)vsb;
3062 -
3063 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3064 - if (sb)
3065 - sb->s_dirt = 1;
3066 -}
3067 -
3068 -typedef struct {
3069 - int inband_tags;
3070 - int skip_checkpoint_read;
3071 - int skip_checkpoint_write;
3072 - int no_cache;
3073 -} yaffs_options;
3074 -
3075 -#define MAX_OPT_LEN 20
3076 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3077 -{
3078 - char cur_opt[MAX_OPT_LEN + 1];
3079 - int p;
3080 - int error = 0;
3081 -
3082 - /* Parse through the options which is a comma seperated list */
3083 -
3084 - while (options_str && *options_str && !error) {
3085 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3086 - p = 0;
3087 -
3088 - while (*options_str && *options_str != ',') {
3089 - if (p < MAX_OPT_LEN) {
3090 - cur_opt[p] = *options_str;
3091 - p++;
3092 - }
3093 - options_str++;
3094 - }
3095 -
3096 - if (!strcmp(cur_opt, "inband-tags"))
3097 - options->inband_tags = 1;
3098 - else if (!strcmp(cur_opt, "no-cache"))
3099 - options->no_cache = 1;
3100 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3101 - options->skip_checkpoint_read = 1;
3102 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3103 - options->skip_checkpoint_write = 1;
3104 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3105 - options->skip_checkpoint_read = 1;
3106 - options->skip_checkpoint_write = 1;
3107 - } else {
3108 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3109 - cur_opt);
3110 - error = 1;
3111 - }
3112 - }
3113 -
3114 - return error;
3115 -}
3116 -
3117 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3118 - struct super_block *sb,
3119 - void *data, int silent)
3120 -{
3121 - int nBlocks;
3122 - struct inode *inode = NULL;
3123 - struct dentry *root;
3124 - yaffs_Device *dev = 0;
3125 - char devname_buf[BDEVNAME_SIZE + 1];
3126 - struct mtd_info *mtd;
3127 - int err;
3128 - char *data_str = (char *)data;
3129 -
3130 - yaffs_options options;
3131 -
3132 - sb->s_magic = YAFFS_MAGIC;
3133 - sb->s_op = &yaffs_super_ops;
3134 - sb->s_flags |= MS_NOATIME;
3135 -
3136 - if (!sb)
3137 - printk(KERN_INFO "yaffs: sb is NULL\n");
3138 - else if (!sb->s_dev)
3139 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3140 - else if (!yaffs_devname(sb, devname_buf))
3141 - printk(KERN_INFO "yaffs: devname is NULL\n");
3142 - else
3143 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3144 - sb->s_dev,
3145 - yaffs_devname(sb, devname_buf));
3146 -
3147 - if (!data_str)
3148 - data_str = "";
3149 -
3150 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3151 -
3152 - memset(&options, 0, sizeof(options));
3153 -
3154 - if (yaffs_parse_options(&options, data_str)) {
3155 - /* Option parsing failed */
3156 - return NULL;
3157 - }
3158 -
3159 -
3160 - sb->s_blocksize = PAGE_CACHE_SIZE;
3161 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3162 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3163 - T(YAFFS_TRACE_OS,
3164 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3165 -
3166 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3167 - T(YAFFS_TRACE_OS,
3168 - ("yaffs: Write verification disabled. All guarantees "
3169 - "null and void\n"));
3170 -#endif
3171 -
3172 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3173 - "\"%s\"\n",
3174 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3175 - yaffs_devname(sb, devname_buf)));
3176 -
3177 - /* Check it's an mtd device..... */
3178 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3179 - return NULL; /* This isn't an mtd device */
3180 -
3181 - /* Get the device */
3182 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3183 - if (!mtd) {
3184 - T(YAFFS_TRACE_ALWAYS,
3185 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3186 - MINOR(sb->s_dev)));
3187 - return NULL;
3188 - }
3189 - /* Check it's NAND */
3190 - if (mtd->type != MTD_NANDFLASH) {
3191 - T(YAFFS_TRACE_ALWAYS,
3192 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3193 - return NULL;
3194 - }
3195 -
3196 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3197 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3198 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3199 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3200 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3201 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3202 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3203 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3204 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3205 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3206 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3207 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3208 -#else
3209 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3210 -#endif
3211 -
3212 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3213 -
3214 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3215 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3216 - yaffsVersion = 2;
3217 - }
3218 -
3219 - /* Added NCB 26/5/2006 for completeness */
3220 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3221 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3222 - yaffsVersion = 1;
3223 - }
3224 -
3225 -#endif
3226 -
3227 - if (yaffsVersion == 2) {
3228 - /* Check for version 2 style functions */
3229 - if (!mtd->erase ||
3230 - !mtd->block_isbad ||
3231 - !mtd->block_markbad ||
3232 - !mtd->read ||
3233 - !mtd->write ||
3234 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3235 - !mtd->read_oob || !mtd->write_oob) {
3236 -#else
3237 - !mtd->write_ecc ||
3238 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3239 -#endif
3240 - T(YAFFS_TRACE_ALWAYS,
3241 - ("yaffs: MTD device does not support required "
3242 - "functions\n"));;
3243 - return NULL;
3244 - }
3245 -
3246 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3247 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3248 - !options.inband_tags) {
3249 - T(YAFFS_TRACE_ALWAYS,
3250 - ("yaffs: MTD device does not have the "
3251 - "right page sizes\n"));
3252 - return NULL;
3253 - }
3254 - } else {
3255 - /* Check for V1 style functions */
3256 - if (!mtd->erase ||
3257 - !mtd->read ||
3258 - !mtd->write ||
3259 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3260 - !mtd->read_oob || !mtd->write_oob) {
3261 -#else
3262 - !mtd->write_ecc ||
3263 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3264 -#endif
3265 - T(YAFFS_TRACE_ALWAYS,
3266 - ("yaffs: MTD device does not support required "
3267 - "functions\n"));;
3268 - return NULL;
3269 - }
3270 -
3271 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3272 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3273 - T(YAFFS_TRACE_ALWAYS,
3274 - ("yaffs: MTD device does not support have the "
3275 - "right page sizes\n"));
3276 - return NULL;
3277 - }
3278 - }
3279 -
3280 - /* OK, so if we got here, we have an MTD that's NAND and looks
3281 - * like it has the right capabilities
3282 - * Set the yaffs_Device up for mtd
3283 - */
3284 -
3285 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3286 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3287 -#else
3288 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3289 -#endif
3290 - if (!dev) {
3291 - /* Deep shit could not allocate device structure */
3292 - T(YAFFS_TRACE_ALWAYS,
3293 - ("yaffs_read_super: Failed trying to allocate "
3294 - "yaffs_Device. \n"));
3295 - return NULL;
3296 - }
3297 -
3298 - memset(dev, 0, sizeof(yaffs_Device));
3299 - dev->genericDevice = mtd;
3300 - dev->name = mtd->name;
3301 -
3302 - /* Set up the memory size parameters.... */
3303 -
3304 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3305 -
3306 - dev->startBlock = 0;
3307 - dev->endBlock = nBlocks - 1;
3308 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3309 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3310 - dev->nReservedBlocks = 5;
3311 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3312 - dev->inbandTags = options.inband_tags;
3313 -
3314 - /* ... and the functions. */
3315 - if (yaffsVersion == 2) {
3316 - dev->writeChunkWithTagsToNAND =
3317 - nandmtd2_WriteChunkWithTagsToNAND;
3318 - dev->readChunkWithTagsFromNAND =
3319 - nandmtd2_ReadChunkWithTagsFromNAND;
3320 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3321 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3322 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3323 - dev->isYaffs2 = 1;
3324 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3325 - dev->totalBytesPerChunk = mtd->writesize;
3326 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3327 -#else
3328 - dev->totalBytesPerChunk = mtd->oobblock;
3329 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3330 -#endif
3331 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3332 -
3333 - dev->startBlock = 0;
3334 - dev->endBlock = nBlocks - 1;
3335 - } else {
3336 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3337 - /* use the MTD interface in yaffs_mtdif1.c */
3338 - dev->writeChunkWithTagsToNAND =
3339 - nandmtd1_WriteChunkWithTagsToNAND;
3340 - dev->readChunkWithTagsFromNAND =
3341 - nandmtd1_ReadChunkWithTagsFromNAND;
3342 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3343 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3344 -#else
3345 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3346 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3347 -#endif
3348 - dev->isYaffs2 = 0;
3349 - }
3350 - /* ... and common functions */
3351 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3352 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3353 -
3354 - dev->putSuperFunc = yaffs_MTDPutSuper;
3355 -
3356 - dev->superBlock = (void *)sb;
3357 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3358 -
3359 -
3360 -#ifndef CONFIG_YAFFS_DOES_ECC
3361 - dev->useNANDECC = 1;
3362 -#endif
3363 -
3364 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3365 - dev->wideTnodesDisabled = 1;
3366 -#endif
3367 -
3368 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3369 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3370 -
3371 - /* we assume this is protected by lock_kernel() in mount/umount */
3372 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3373 -
3374 - init_MUTEX(&dev->grossLock);
3375 -
3376 - yaffs_GrossLock(dev);
3377 -
3378 - err = yaffs_GutsInitialise(dev);
3379 -
3380 - T(YAFFS_TRACE_OS,
3381 - ("yaffs_read_super: guts initialised %s\n",
3382 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3383 -
3384 - /* Release lock before yaffs_get_inode() */
3385 - yaffs_GrossUnlock(dev);
3386 -
3387 - /* Create root inode */
3388 - if (err == YAFFS_OK)
3389 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3390 - yaffs_Root(dev));
3391 -
3392 - if (!inode)
3393 - return NULL;
3394 -
3395 - inode->i_op = &yaffs_dir_inode_operations;
3396 - inode->i_fop = &yaffs_dir_operations;
3397 -
3398 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3399 -
3400 - root = d_alloc_root(inode);
3401 -
3402 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3403 -
3404 - if (!root) {
3405 - iput(inode);
3406 - return NULL;
3407 - }
3408 - sb->s_root = root;
3409 - sb->s_dirt = !dev->isCheckpointed;
3410 - T(YAFFS_TRACE_ALWAYS,
3411 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3412 -
3413 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3414 - return sb;
3415 -}
3416 -
3417 -
3418 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3419 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3420 - int silent)
3421 -{
3422 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3423 -}
3424 -
3425 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3426 -static int yaffs_read_super(struct file_system_type *fs,
3427 - int flags, const char *dev_name,
3428 - void *data, struct vfsmount *mnt)
3429 -{
3430 -
3431 - return get_sb_bdev(fs, flags, dev_name, data,
3432 - yaffs_internal_read_super_mtd, mnt);
3433 -}
3434 -#else
3435 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3436 - int flags, const char *dev_name,
3437 - void *data)
3438 -{
3439 -
3440 - return get_sb_bdev(fs, flags, dev_name, data,
3441 - yaffs_internal_read_super_mtd);
3442 -}
3443 -#endif
3444 -
3445 -static struct file_system_type yaffs_fs_type = {
3446 - .owner = THIS_MODULE,
3447 - .name = "yaffs",
3448 - .get_sb = yaffs_read_super,
3449 - .kill_sb = kill_block_super,
3450 - .fs_flags = FS_REQUIRES_DEV,
3451 -};
3452 -#else
3453 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3454 - int silent)
3455 -{
3456 - return yaffs_internal_read_super(1, sb, data, silent);
3457 -}
3458 -
3459 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3460 - FS_REQUIRES_DEV);
3461 -#endif
3462 -
3463 -
3464 -#ifdef CONFIG_YAFFS_YAFFS2
3465 -
3466 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3467 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3468 - int silent)
3469 -{
3470 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3471 -}
3472 -
3473 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3474 -static int yaffs2_read_super(struct file_system_type *fs,
3475 - int flags, const char *dev_name, void *data,
3476 - struct vfsmount *mnt)
3477 -{
3478 - return get_sb_bdev(fs, flags, dev_name, data,
3479 - yaffs2_internal_read_super_mtd, mnt);
3480 -}
3481 -#else
3482 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3483 - int flags, const char *dev_name,
3484 - void *data)
3485 -{
3486 -
3487 - return get_sb_bdev(fs, flags, dev_name, data,
3488 - yaffs2_internal_read_super_mtd);
3489 -}
3490 -#endif
3491 -
3492 -static struct file_system_type yaffs2_fs_type = {
3493 - .owner = THIS_MODULE,
3494 - .name = "yaffs2",
3495 - .get_sb = yaffs2_read_super,
3496 - .kill_sb = kill_block_super,
3497 - .fs_flags = FS_REQUIRES_DEV,
3498 -};
3499 -#else
3500 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3501 - void *data, int silent)
3502 -{
3503 - return yaffs_internal_read_super(2, sb, data, silent);
3504 -}
3505 -
3506 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3507 - FS_REQUIRES_DEV);
3508 -#endif
3509 -
3510 -#endif /* CONFIG_YAFFS_YAFFS2 */
3511 -
3512 -static struct proc_dir_entry *my_proc_entry;
3513 -
3514 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3515 -{
3516 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3517 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3518 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3519 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3520 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3521 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3522 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3523 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3524 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3525 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3526 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3527 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3528 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3529 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3530 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3531 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3532 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3533 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3534 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3535 - buf += sprintf(buf, "passiveGCs......... %d\n",
3536 - dev->passiveGarbageCollections);
3537 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3538 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3539 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3540 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3541 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3542 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3543 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3544 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3545 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3546 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3547 - buf +=
3548 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3549 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3550 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3551 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3552 -
3553 - return buf;
3554 -}
3555 -
3556 -static int yaffs_proc_read(char *page,
3557 - char **start,
3558 - off_t offset, int count, int *eof, void *data)
3559 -{
3560 - struct ylist_head *item;
3561 - char *buf = page;
3562 - int step = offset;
3563 - int n = 0;
3564 -
3565 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3566 - * We use 'offset' (*ppos) to indicate where we are in devList.
3567 - * This also assumes the user has posted a read buffer large
3568 - * enough to hold the complete output; but that's life in /proc.
3569 - */
3570 -
3571 - *(int *)start = 1;
3572 -
3573 - /* Print header first */
3574 - if (step == 0) {
3575 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3576 - "\n%s\n%s\n", yaffs_fs_c_version,
3577 - yaffs_guts_c_version);
3578 - }
3579 -
3580 - /* hold lock_kernel while traversing yaffs_dev_list */
3581 - lock_kernel();
3582 -
3583 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3584 - ylist_for_each(item, &yaffs_dev_list) {
3585 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3586 - if (n < step) {
3587 - n++;
3588 - continue;
3589 - }
3590 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3591 - buf = yaffs_dump_dev(buf, dev);
3592 - break;
3593 - }
3594 - unlock_kernel();
3595 -
3596 - return buf - page < count ? buf - page : count;
3597 -}
3598 -
3599 -/**
3600 - * Set the verbosity of the warnings and error messages.
3601 - *
3602 - * Note that the names can only be a..z or _ with the current code.
3603 - */
3604 -
3605 -static struct {
3606 - char *mask_name;
3607 - unsigned mask_bitfield;
3608 -} mask_flags[] = {
3609 - {"allocate", YAFFS_TRACE_ALLOCATE},
3610 - {"always", YAFFS_TRACE_ALWAYS},
3611 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3612 - {"buffers", YAFFS_TRACE_BUFFERS},
3613 - {"bug", YAFFS_TRACE_BUG},
3614 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
3615 - {"deletion", YAFFS_TRACE_DELETION},
3616 - {"erase", YAFFS_TRACE_ERASE},
3617 - {"error", YAFFS_TRACE_ERROR},
3618 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
3619 - {"gc", YAFFS_TRACE_GC},
3620 - {"mtd", YAFFS_TRACE_MTD},
3621 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
3622 - {"os", YAFFS_TRACE_OS},
3623 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
3624 - {"scan", YAFFS_TRACE_SCAN},
3625 - {"tracing", YAFFS_TRACE_TRACING},
3626 -
3627 - {"verify", YAFFS_TRACE_VERIFY},
3628 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
3629 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
3630 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
3631 -
3632 - {"write", YAFFS_TRACE_WRITE},
3633 - {"all", 0xffffffff},
3634 - {"none", 0},
3635 - {NULL, 0},
3636 -};
3637 -
3638 -#define MAX_MASK_NAME_LENGTH 40
3639 -static int yaffs_proc_write(struct file *file, const char *buf,
3640 - unsigned long count, void *data)
3641 -{
3642 - unsigned rg = 0, mask_bitfield;
3643 - char *end;
3644 - char *mask_name;
3645 - const char *x;
3646 - char substring[MAX_MASK_NAME_LENGTH + 1];
3647 - int i;
3648 - int done = 0;
3649 - int add, len = 0;
3650 - int pos = 0;
3651 -
3652 - rg = yaffs_traceMask;
3653 -
3654 - while (!done && (pos < count)) {
3655 - done = 1;
3656 - while ((pos < count) && isspace(buf[pos]))
3657 - pos++;
3658 -
3659 - switch (buf[pos]) {
3660 - case '+':
3661 - case '-':
3662 - case '=':
3663 - add = buf[pos];
3664 - pos++;
3665 - break;
3666 -
3667 - default:
3668 - add = ' ';
3669 - break;
3670 - }
3671 - mask_name = NULL;
3672 -
3673 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
3674 -
3675 - if (end > buf + pos) {
3676 - mask_name = "numeral";
3677 - len = end - (buf + pos);
3678 - pos += len;
3679 - done = 0;
3680 - } else {
3681 - for (x = buf + pos, i = 0;
3682 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
3683 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
3684 - substring[i] = *x;
3685 - substring[i] = '\0';
3686 -
3687 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3688 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
3689 - mask_name = mask_flags[i].mask_name;
3690 - mask_bitfield = mask_flags[i].mask_bitfield;
3691 - done = 0;
3692 - break;
3693 - }
3694 - }
3695 - }
3696 -
3697 - if (mask_name != NULL) {
3698 - done = 0;
3699 - switch (add) {
3700 - case '-':
3701 - rg &= ~mask_bitfield;
3702 - break;
3703 - case '+':
3704 - rg |= mask_bitfield;
3705 - break;
3706 - case '=':
3707 - rg = mask_bitfield;
3708 - break;
3709 - default:
3710 - rg |= mask_bitfield;
3711 - break;
3712 - }
3713 - }
3714 - }
3715 -
3716 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
3717 -
3718 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
3719 -
3720 - if (rg & YAFFS_TRACE_ALWAYS) {
3721 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3722 - char flag;
3723 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
3724 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
3725 - }
3726 - }
3727 -
3728 - return count;
3729 -}
3730 -
3731 -/* Stuff to handle installation of file systems */
3732 -struct file_system_to_install {
3733 - struct file_system_type *fst;
3734 - int installed;
3735 -};
3736 -
3737 -static struct file_system_to_install fs_to_install[] = {
3738 - {&yaffs_fs_type, 0},
3739 - {&yaffs2_fs_type, 0},
3740 - {NULL, 0}
3741 -};
3742 -
3743 -static int __init init_yaffs_fs(void)
3744 -{
3745 - int error = 0;
3746 - struct file_system_to_install *fsinst;
3747 -
3748 - T(YAFFS_TRACE_ALWAYS,
3749 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
3750 -
3751 - /* Install the proc_fs entry */
3752 - my_proc_entry = create_proc_entry("yaffs",
3753 - S_IRUGO | S_IFREG,
3754 - YPROC_ROOT);
3755 -
3756 - if (my_proc_entry) {
3757 - my_proc_entry->write_proc = yaffs_proc_write;
3758 - my_proc_entry->read_proc = yaffs_proc_read;
3759 - my_proc_entry->data = NULL;
3760 - } else
3761 - return -ENOMEM;
3762 -
3763 - /* Now add the file system entries */
3764 -
3765 - fsinst = fs_to_install;
3766 -
3767 - while (fsinst->fst && !error) {
3768 - error = register_filesystem(fsinst->fst);
3769 - if (!error)
3770 - fsinst->installed = 1;
3771 - fsinst++;
3772 - }
3773 -
3774 - /* Any errors? uninstall */
3775 - if (error) {
3776 - fsinst = fs_to_install;
3777 -
3778 - while (fsinst->fst) {
3779 - if (fsinst->installed) {
3780 - unregister_filesystem(fsinst->fst);
3781 - fsinst->installed = 0;
3782 - }
3783 - fsinst++;
3784 - }
3785 - }
3786 -
3787 - return error;
3788 -}
3789 -
3790 -static void __exit exit_yaffs_fs(void)
3791 -{
3792 -
3793 - struct file_system_to_install *fsinst;
3794 -
3795 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
3796 - " removing. \n"));
3797 -
3798 - remove_proc_entry("yaffs", YPROC_ROOT);
3799 -
3800 - fsinst = fs_to_install;
3801 -
3802 - while (fsinst->fst) {
3803 - if (fsinst->installed) {
3804 - unregister_filesystem(fsinst->fst);
3805 - fsinst->installed = 0;
3806 - }
3807 - fsinst++;
3808 - }
3809 -}
3810 -
3811 -module_init(init_yaffs_fs)
3812 -module_exit(exit_yaffs_fs)
3813 -
3814 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
3815 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
3816 -MODULE_LICENSE("GPL");
3817 diff -Nrup a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h
3818 --- a/fs/yaffs2/yaffs_getblockinfo.h 2010-10-03 17:48:22.710000363 +0300
3819 +++ b/fs/yaffs2/yaffs_getblockinfo.h 2010-10-03 18:03:47.542000362 +0300
3820 @@ -1,7 +1,7 @@
3821 /*
3822 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3823 *
3824 - * Copyright (C) 2002-2007 Aleph One Ltd.
3825 + * Copyright (C) 2002-2010 Aleph One Ltd.
3826 * for Toby Churchill Ltd and Brightstar Engineering
3827 *
3828 * Created by Charles Manning <charles@aleph1.co.uk>
3829 @@ -17,6 +17,7 @@
3830 #define __YAFFS_GETBLOCKINFO_H__
3831
3832 #include "yaffs_guts.h"
3833 +#include "yaffs_trace.h"
3834
3835 /* Function to manipulate block info */
3836 static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
3837 diff -Nrup a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
3838 --- a/fs/yaffs2/yaffs_guts.c 2010-10-03 17:48:22.715000364 +0300
3839 +++ b/fs/yaffs2/yaffs_guts.c 2010-10-03 18:03:47.518000364 +0300
3840 @@ -1,7 +1,7 @@
3841 /*
3842 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3843 *
3844 - * Copyright (C) 2002-2007 Aleph One Ltd.
3845 + * Copyright (C) 2002-2010 Aleph One Ltd.
3846 * for Toby Churchill Ltd and Brightstar Engineering
3847 *
3848 * Created by Charles Manning <charles@aleph1.co.uk>
3849 @@ -10,11 +10,8 @@
3850 * it under the terms of the GNU General Public License version 2 as
3851 * published by the Free Software Foundation.
3852 */
3853 -
3854 -const char *yaffs_guts_c_version =
3855 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
3856 -
3857 #include "yportenv.h"
3858 +#include "yaffs_trace.h"
3859
3860 #include "yaffsinterface.h"
3861 #include "yaffs_guts.h"
3862 @@ -22,22 +19,28 @@ const char *yaffs_guts_c_version =
3863 #include "yaffs_getblockinfo.h"
3864
3865 #include "yaffs_tagscompat.h"
3866 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
3867 -#include "yaffs_qsort.h"
3868 -#endif
3869 +
3870 #include "yaffs_nand.h"
3871
3872 -#include "yaffs_checkptrw.h"
3873 +#include "yaffs_yaffs1.h"
3874 +#include "yaffs_yaffs2.h"
3875 +#include "yaffs_bitmap.h"
3876 +#include "yaffs_verify.h"
3877
3878 #include "yaffs_nand.h"
3879 #include "yaffs_packedtags2.h"
3880
3881 +#include "yaffs_nameval.h"
3882 +#include "yaffs_allocator.h"
3883
3884 -#define YAFFS_PASSIVE_GC_CHUNKS 2
3885 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
3886 +#define YAFFS_GC_GOOD_ENOUGH 2
3887 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
3888
3889 #include "yaffs_ecc.h"
3890
3891
3892 +
3893 /* Robustification (if it ever comes about...) */
3894 static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
3895 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
3896 @@ -49,33 +52,26 @@ static void yaffs_HandleUpdateChunk(yaff
3897 const yaffs_ExtendedTags *tags);
3898
3899 /* Other local prototypes */
3900 +static void yaffs_UpdateParent(yaffs_Object *obj);
3901 static int yaffs_UnlinkObject(yaffs_Object *obj);
3902 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
3903
3904 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
3905 -
3906 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
3907 const __u8 *buffer,
3908 yaffs_ExtendedTags *tags,
3909 int useReserve);
3910 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
3911 - int chunkInNAND, int inScan);
3912 +
3913
3914 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
3915 yaffs_ObjectType type);
3916 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
3917 - yaffs_Object *obj);
3918 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
3919 - int force, int isShrink, int shadows);
3920 +
3921 +
3922 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
3923 +
3924 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
3925 static int yaffs_CheckStructures(void);
3926 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
3927 - int chunkOffset, int *limit);
3928 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
3929
3930 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
3931 -
3932 -
3933 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
3934 int chunkInNAND);
3935
3936 @@ -87,30 +83,22 @@ static int yaffs_TagsMatch(const yaffs_E
3937 static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
3938 yaffs_BlockInfo **blockUsedPtr);
3939
3940 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
3941 -
3942 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
3943
3944 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
3945 -#ifdef YAFFS_PARANOID
3946 -static int yaffs_CheckFileSanity(yaffs_Object *in);
3947 -#else
3948 -#define yaffs_CheckFileSanity(in)
3949 -#endif
3950 -
3951 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
3952 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
3953
3954 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
3955 -
3956 static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
3957 yaffs_ExtendedTags *tags);
3958
3959 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
3960 - unsigned pos);
3961 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
3962 - yaffs_FileStructure *fStruct,
3963 - __u32 chunkId);
3964 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
3965 + int chunkInNAND,
3966 + const __u8 *data,
3967 + yaffs_ExtendedTags *tags);
3968 +
3969 +
3970 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
3971 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
3972
3973
3974 /* Function to calculate chunk and offset */
3975 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
3976
3977 static __u32 Shifts(__u32 x)
3978 {
3979 - int nShifts;
3980 + __u32 nShifts;
3981
3982 nShifts = 0;
3983
3984 @@ -203,7 +191,7 @@ static int yaffs_InitialiseTempBuffers(y
3985 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
3986 dev->tempBuffer[i].line = 0; /* not in use */
3987 dev->tempBuffer[i].buffer = buf =
3988 - YMALLOC_DMA(dev->totalBytesPerChunk);
3989 + YMALLOC_DMA(dev->param.totalBytesPerChunk);
3990 }
3991
3992 return buf ? YAFFS_OK : YAFFS_FAIL;
3993 @@ -286,7 +274,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
3994 return 1;
3995 }
3996
3997 - for (i = 0; i < dev->nShortOpCaches; i++) {
3998 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
3999 if (dev->srCache[i].data == buffer)
4000 return 1;
4001 }
4002 @@ -299,6374 +287,4183 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
4003 return 0;
4004 }
4005
4006 -
4007 -
4008 /*
4009 - * Chunk bitmap manipulations
4010 + * Verification code
4011 */
4012
4013 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
4014 -{
4015 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4016 - T(YAFFS_TRACE_ERROR,
4017 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4018 - blk));
4019 - YBUG();
4020 - }
4021 - return dev->chunkBits +
4022 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4023 -}
4024
4025 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4026 -{
4027 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4028 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4029 - T(YAFFS_TRACE_ERROR,
4030 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4031 - blk, chunk));
4032 - YBUG();
4033 - }
4034 -}
4035
4036 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4037 -{
4038 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4039
4040 - memset(blkBits, 0, dev->chunkBitmapStride);
4041 -}
4042 +/*
4043 + * Simple hash function. Needs to have a reasonable spread
4044 + */
4045
4046 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4047 +static Y_INLINE int yaffs_HashFunction(int n)
4048 {
4049 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4050 -
4051 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4052 -
4053 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4054 + n = abs(n);
4055 + return n % YAFFS_NOBJECT_BUCKETS;
4056 }
4057
4058 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4059 -{
4060 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4061 -
4062 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4063 -
4064 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4065 -}
4066 +/*
4067 + * Access functions to useful fake objects.
4068 + * Note that root might have a presence in NAND if permissions are set.
4069 + */
4070
4071 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4072 +yaffs_Object *yaffs_Root(yaffs_Device *dev)
4073 {
4074 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4075 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4076 -
4077 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4078 + return dev->rootDir;
4079 }
4080
4081 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4082 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4083 {
4084 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4085 - int i;
4086 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4087 - if (*blkBits)
4088 - return 1;
4089 - blkBits++;
4090 - }
4091 - return 0;
4092 + return dev->lostNFoundDir;
4093 }
4094
4095 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4096 -{
4097 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4098 - int i;
4099 - int n = 0;
4100 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4101 - __u8 x = *blkBits;
4102 - while (x) {
4103 - if (x & 1)
4104 - n++;
4105 - x >>= 1;
4106 - }
4107 -
4108 - blkBits++;
4109 - }
4110 - return n;
4111 -}
4112
4113 /*
4114 - * Verification code
4115 + * Erased NAND checking functions
4116 */
4117
4118 -static int yaffs_SkipVerification(yaffs_Device *dev)
4119 -{
4120 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4121 -}
4122 -
4123 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4124 -{
4125 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4126 -}
4127 -
4128 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4129 +int yaffs_CheckFF(__u8 *buffer, int nBytes)
4130 {
4131 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4132 + /* Horrible, slow implementation */
4133 + while (nBytes--) {
4134 + if (*buffer != 0xFF)
4135 + return 0;
4136 + buffer++;
4137 + }
4138 + return 1;
4139 }
4140
4141 -static const char *blockStateName[] = {
4142 -"Unknown",
4143 -"Needs scanning",
4144 -"Scanning",
4145 -"Empty",
4146 -"Allocating",
4147 -"Full",
4148 -"Dirty",
4149 -"Checkpoint",
4150 -"Collecting",
4151 -"Dead"
4152 -};
4153 -
4154 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4155 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4156 + int chunkInNAND)
4157 {
4158 - int actuallyUsed;
4159 - int inUse;
4160 + int retval = YAFFS_OK;
4161 + __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4162 + yaffs_ExtendedTags tags;
4163 + int result;
4164
4165 - if (yaffs_SkipVerification(dev))
4166 - return;
4167 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4168
4169 - /* Report illegal runtime states */
4170 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4171 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4172 + if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4173 + retval = YAFFS_FAIL;
4174
4175 - switch (bi->blockState) {
4176 - case YAFFS_BLOCK_STATE_UNKNOWN:
4177 - case YAFFS_BLOCK_STATE_SCANNING:
4178 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4179 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4180 - n, blockStateName[bi->blockState]));
4181 + if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4182 + T(YAFFS_TRACE_NANDACCESS,
4183 + (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
4184 + retval = YAFFS_FAIL;
4185 }
4186
4187 - /* Check pages in use and soft deletions are legal */
4188 -
4189 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4190 -
4191 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4192 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4193 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4194 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4195 - n, bi->pagesInUse, bi->softDeletions));
4196 -
4197 + yaffs_ReleaseTempBuffer(dev, data, __LINE__);
4198
4199 - /* Check chunk bitmap legal */
4200 - inUse = yaffs_CountChunkBits(dev, n);
4201 - if (inUse != bi->pagesInUse)
4202 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4203 - n, bi->pagesInUse, inUse));
4204 + return retval;
4205
4206 - /* Check that the sequence number is valid.
4207 - * Ten million is legal, but is very unlikely
4208 - */
4209 - if (dev->isYaffs2 &&
4210 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4211 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4212 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4213 - n, bi->sequenceNumber));
4214 }
4215
4216 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4217 - int n)
4218 +
4219 +static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
4220 + int chunkInNAND,
4221 + const __u8 *data,
4222 + yaffs_ExtendedTags *tags)
4223 {
4224 - yaffs_VerifyBlock(dev, bi, n);
4225 + int retval = YAFFS_OK;
4226 + yaffs_ExtendedTags tempTags;
4227 + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
4228 + int result;
4229 +
4230 + result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
4231 + if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
4232 + tempTags.objectId != tags->objectId ||
4233 + tempTags.chunkId != tags->chunkId ||
4234 + tempTags.byteCount != tags->byteCount)
4235 + retval = YAFFS_FAIL;
4236
4237 - /* After collection the block should be in the erased state */
4238 - /* This will need to change if we do partial gc */
4239 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4240
4241 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4242 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4243 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4244 - n, bi->blockState));
4245 - }
4246 + return retval;
4247 }
4248
4249 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4250 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
4251 + const __u8 *data,
4252 + yaffs_ExtendedTags *tags,
4253 + int useReserve)
4254 {
4255 - int i;
4256 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4257 - int nIllegalBlockStates = 0;
4258 -
4259 - if (yaffs_SkipVerification(dev))
4260 - return;
4261 -
4262 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4263 -
4264 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4265 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4266 - yaffs_VerifyBlock(dev, bi, i);
4267 -
4268 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4269 - nBlocksPerState[bi->blockState]++;
4270 - else
4271 - nIllegalBlockStates++;
4272 - }
4273 + int attempts = 0;
4274 + int writeOk = 0;
4275 + int chunk;
4276
4277 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4278 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4279 + yaffs2_InvalidateCheckpoint(dev);
4280
4281 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4282 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4283 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4284 + do {
4285 + yaffs_BlockInfo *bi = 0;
4286 + int erasedOk = 0;
4287
4288 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4289 - T(YAFFS_TRACE_VERIFY,
4290 - (TSTR("%s %d blocks"TENDSTR),
4291 - blockStateName[i], nBlocksPerState[i]));
4292 + chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
4293 + if (chunk < 0) {
4294 + /* no space */
4295 + break;
4296 + }
4297
4298 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4299 - T(YAFFS_TRACE_VERIFY,
4300 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4301 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4302 + /* First check this chunk is erased, if it needs
4303 + * checking. The checking policy (unless forced
4304 + * always on) is as follows:
4305 + *
4306 + * Check the first page we try to write in a block.
4307 + * If the check passes then we don't need to check any
4308 + * more. If the check fails, we check again...
4309 + * If the block has been erased, we don't need to check.
4310 + *
4311 + * However, if the block has been prioritised for gc,
4312 + * then we think there might be something odd about
4313 + * this block and stop using it.
4314 + *
4315 + * Rationale: We should only ever see chunks that have
4316 + * not been erased if there was a partially written
4317 + * chunk due to power loss. This checking policy should
4318 + * catch that case with very few checks and thus save a
4319 + * lot of checks that are most likely not needed.
4320 + *
4321 + * Mods to the above
4322 + * If an erase check fails or the write fails we skip the
4323 + * rest of the block.
4324 + */
4325
4326 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4327 - T(YAFFS_TRACE_VERIFY,
4328 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4329 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4330 + /* let's give it a try */
4331 + attempts++;
4332
4333 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4334 - T(YAFFS_TRACE_VERIFY,
4335 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4336 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4337 + if(dev->param.alwaysCheckErased)
4338 + bi->skipErasedCheck = 0;
4339
4340 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4341 + if (!bi->skipErasedCheck) {
4342 + erasedOk = yaffs_CheckChunkErased(dev, chunk);
4343 + if (erasedOk != YAFFS_OK) {
4344 + T(YAFFS_TRACE_ERROR,
4345 + (TSTR("**>> yaffs chunk %d was not erased"
4346 + TENDSTR), chunk));
4347
4348 -}
4349 + /* If not erased, delete this one,
4350 + * skip rest of block and
4351 + * try another chunk */
4352 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4353 + yaffs_SkipRestOfBlock(dev);
4354 + continue;
4355 + }
4356 + }
4357
4358 -/*
4359 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4360 - * case those tests will not be performed.
4361 - */
4362 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4363 -{
4364 - if (obj && yaffs_SkipVerification(obj->myDev))
4365 - return;
4366 + writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
4367 + data, tags);
4368
4369 - if (!(tags && obj && oh)) {
4370 - T(YAFFS_TRACE_VERIFY,
4371 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4372 - (__u32)tags, (__u32)obj, (__u32)oh));
4373 - return;
4374 - }
4375 + if(!bi->skipErasedCheck)
4376 + writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
4377
4378 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4379 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4380 - T(YAFFS_TRACE_VERIFY,
4381 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4382 - tags->objectId, oh->type));
4383 + if (writeOk != YAFFS_OK) {
4384 + /* Clean up aborted write, skip to next block and
4385 + * try another chunk */
4386 + yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
4387 + continue;
4388 + }
4389
4390 - if (tags->objectId != obj->objectId)
4391 - T(YAFFS_TRACE_VERIFY,
4392 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4393 - tags->objectId, obj->objectId));
4394 + bi->skipErasedCheck = 1;
4395
4396 + /* Copy the data into the robustification buffer */
4397 + yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
4398
4399 - /*
4400 - * Check that the object's parent ids match if parentCheck requested.
4401 - *
4402 - * Tests do not apply to the root object.
4403 - */
4404 + } while (writeOk != YAFFS_OK &&
4405 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4406
4407 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4408 - T(YAFFS_TRACE_VERIFY,
4409 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4410 - tags->objectId, oh->parentObjectId));
4411 + if (!writeOk)
4412 + chunk = -1;
4413
4414 - if (parentCheck && obj->parent &&
4415 - oh->parentObjectId != obj->parent->objectId &&
4416 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
4417 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
4418 - T(YAFFS_TRACE_VERIFY,
4419 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
4420 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
4421 + if (attempts > 1) {
4422 + T(YAFFS_TRACE_ERROR,
4423 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
4424 + attempts));
4425
4426 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
4427 - T(YAFFS_TRACE_VERIFY,
4428 - (TSTR("Obj %d header name is NULL"TENDSTR),
4429 - obj->objectId));
4430 + dev->nRetriedWrites += (attempts - 1);
4431 + }
4432
4433 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
4434 - T(YAFFS_TRACE_VERIFY,
4435 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
4436 - obj->objectId));
4437 + return chunk;
4438 }
4439
4440
4441 +
4442 +/*
4443 + * Block retiring for handling a broken block.
4444 + */
4445
4446 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
4447 - __u32 level, int chunkOffset)
4448 +static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
4449 {
4450 - int i;
4451 - yaffs_Device *dev = obj->myDev;
4452 - int ok = 1;
4453 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4454
4455 - if (tn) {
4456 - if (level > 0) {
4457 + yaffs2_InvalidateCheckpoint(dev);
4458 +
4459 + yaffs2_ClearOldestDirtySequence(dev,bi);
4460
4461 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
4462 - if (tn->internal[i]) {
4463 - ok = yaffs_VerifyTnodeWorker(obj,
4464 - tn->internal[i],
4465 - level - 1,
4466 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
4467 - }
4468 - }
4469 - } else if (level == 0) {
4470 + if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
4471 + if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
4472 + T(YAFFS_TRACE_ALWAYS, (TSTR(
4473 + "yaffs: Failed to mark bad and erase block %d"
4474 + TENDSTR), blockInNAND));
4475 + } else {
4476 yaffs_ExtendedTags tags;
4477 - __u32 objectId = obj->objectId;
4478 + int chunkId = blockInNAND * dev->param.nChunksPerBlock;
4479
4480 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
4481 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4482
4483 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
4484 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4485 + memset(buffer, 0xff, dev->nDataBytesPerChunk);
4486 + yaffs_InitialiseTags(&tags);
4487 + tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
4488 + if (dev->param.writeChunkWithTagsToNAND(dev, chunkId -
4489 + dev->chunkOffset, buffer, &tags) != YAFFS_OK)
4490 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
4491 + TCONT("write bad block marker to block %d")
4492 + TENDSTR), blockInNAND));
4493
4494 - if (theChunk > 0) {
4495 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
4496 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4497 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
4498 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4499 - objectId, chunkOffset, theChunk,
4500 - tags.objectId, tags.chunkId));
4501 - }
4502 - }
4503 - chunkOffset++;
4504 - }
4505 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4506 }
4507 }
4508
4509 - return ok;
4510 + bi->blockState = YAFFS_BLOCK_STATE_DEAD;
4511 + bi->gcPrioritise = 0;
4512 + bi->needsRetiring = 0;
4513
4514 + dev->nRetiredBlocks++;
4515 }
4516
4517 +/*
4518 + * Functions for robustisizing TODO
4519 + *
4520 + */
4521
4522 -static void yaffs_VerifyFile(yaffs_Object *obj)
4523 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4524 + const __u8 *data,
4525 + const yaffs_ExtendedTags *tags)
4526 {
4527 - int requiredTallness;
4528 - int actualTallness;
4529 - __u32 lastChunk;
4530 - __u32 x;
4531 - __u32 i;
4532 - yaffs_Device *dev;
4533 - yaffs_ExtendedTags tags;
4534 - yaffs_Tnode *tn;
4535 - __u32 objectId;
4536 + dev=dev;
4537 + chunkInNAND=chunkInNAND;
4538 + data=data;
4539 + tags=tags;
4540 +}
4541
4542 - if (!obj)
4543 - return;
4544 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4545 + const yaffs_ExtendedTags *tags)
4546 +{
4547 + dev=dev;
4548 + chunkInNAND=chunkInNAND;
4549 + tags=tags;
4550 +}
4551
4552 - if (yaffs_SkipVerification(obj->myDev))
4553 - return;
4554 +void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
4555 +{
4556 + if (!bi->gcPrioritise) {
4557 + bi->gcPrioritise = 1;
4558 + dev->hasPendingPrioritisedGCs = 1;
4559 + bi->chunkErrorStrikes++;
4560
4561 - dev = obj->myDev;
4562 - objectId = obj->objectId;
4563 + if (bi->chunkErrorStrikes > 3) {
4564 + bi->needsRetiring = 1; /* Too many stikes, so retire this */
4565 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
4566
4567 - /* Check file size is consistent with tnode depth */
4568 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
4569 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
4570 - requiredTallness = 0;
4571 - while (x > 0) {
4572 - x >>= YAFFS_TNODES_INTERNAL_BITS;
4573 - requiredTallness++;
4574 + }
4575 }
4576 +}
4577 +
4578 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4579 + int erasedOk)
4580 +{
4581 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
4582 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
4583
4584 - actualTallness = obj->variant.fileVariant.topLevel;
4585 + yaffs_HandleChunkError(dev, bi);
4586
4587 - if (requiredTallness > actualTallness)
4588 - T(YAFFS_TRACE_VERIFY,
4589 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
4590 - obj->objectId, actualTallness, requiredTallness));
4591 + if (erasedOk) {
4592 + /* Was an actual write failure, so mark the block for retirement */
4593 + bi->needsRetiring = 1;
4594 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4595 + (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
4596 + }
4597 +
4598 + /* Delete the chunk */
4599 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
4600 + yaffs_SkipRestOfBlock(dev);
4601 +}
4602
4603
4604 - /* Check that the chunks in the tnode tree are all correct.
4605 - * We do this by scanning through the tnode tree and
4606 - * checking the tags for every chunk match.
4607 - */
4608 +/*---------------- Name handling functions ------------*/
4609
4610 - if (yaffs_SkipNANDVerification(dev))
4611 - return;
4612 +static __u16 yaffs_CalcNameSum(const YCHAR *name)
4613 +{
4614 + __u16 sum = 0;
4615 + __u16 i = 1;
4616
4617 - for (i = 1; i <= lastChunk; i++) {
4618 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
4619 + const YUCHAR *bname = (const YUCHAR *) name;
4620 + if (bname) {
4621 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
4622
4623 - if (tn) {
4624 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
4625 - if (theChunk > 0) {
4626 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
4627 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
4628 - if (tags.objectId != objectId || tags.chunkId != i) {
4629 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
4630 - objectId, i, theChunk,
4631 - tags.objectId, tags.chunkId));
4632 - }
4633 - }
4634 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4635 + sum += yaffs_toupper(*bname) * i;
4636 +#else
4637 + sum += (*bname) * i;
4638 +#endif
4639 + i++;
4640 + bname++;
4641 }
4642 }
4643 + return sum;
4644 }
4645
4646 -
4647 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
4648 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
4649 {
4650 - if (obj && yaffs_SkipVerification(obj->myDev))
4651 - return;
4652 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
4653 + memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
4654 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
4655 + yaffs_strcpy(obj->shortName, name);
4656 + else
4657 + obj->shortName[0] = _Y('\0');
4658 +#endif
4659 + obj->sum = yaffs_CalcNameSum(name);
4660 +}
4661
4662 - /* Verify sane equivalent object */
4663 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
4664 +{
4665 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
4666 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
4667 + memset(tmpName,0,sizeof(tmpName));
4668 + yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
4669 + yaffs_SetObjectName(obj,tmpName);
4670 +#else
4671 + yaffs_SetObjectName(obj,oh->name);
4672 +#endif
4673 }
4674
4675 -static void yaffs_VerifySymlink(yaffs_Object *obj)
4676 +/*-------------------- TNODES -------------------
4677 +
4678 + * List of spare tnodes
4679 + * The list is hooked together using the first pointer
4680 + * in the tnode.
4681 + */
4682 +
4683 +
4684 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
4685 {
4686 - if (obj && yaffs_SkipVerification(obj->myDev))
4687 - return;
4688 + yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev);
4689 + if (tn){
4690 + memset(tn, 0, dev->tnodeSize);
4691 + dev->nTnodes++;
4692 + }
4693 +
4694 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4695
4696 - /* Verify symlink string */
4697 + return tn;
4698 }
4699
4700 -static void yaffs_VerifySpecial(yaffs_Object *obj)
4701 +/* FreeTnode frees up a tnode and puts it back on the free list */
4702 +static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
4703 {
4704 - if (obj && yaffs_SkipVerification(obj->myDev))
4705 - return;
4706 + yaffs_FreeRawTnode(dev,tn);
4707 + dev->nTnodes--;
4708 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
4709 }
4710
4711 -static void yaffs_VerifyObject(yaffs_Object *obj)
4712 +static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev)
4713 {
4714 - yaffs_Device *dev;
4715 -
4716 - __u32 chunkMin;
4717 - __u32 chunkMax;
4718 -
4719 - __u32 chunkIdOk;
4720 - __u32 chunkInRange;
4721 - __u32 chunkShouldNotBeDeleted;
4722 - __u32 chunkValid;
4723 -
4724 - if (!obj)
4725 - return;
4726 + yaffs_DeinitialiseRawTnodesAndObjects(dev);
4727 + dev->nObjects = 0;
4728 + dev->nTnodes = 0;
4729 +}
4730
4731 - if (obj->beingCreated)
4732 - return;
4733
4734 - dev = obj->myDev;
4735 +void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
4736 + unsigned val)
4737 +{
4738 + __u32 *map = (__u32 *)tn;
4739 + __u32 bitInMap;
4740 + __u32 bitInWord;
4741 + __u32 wordInMap;
4742 + __u32 mask;
4743
4744 - if (yaffs_SkipVerification(dev))
4745 - return;
4746 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4747 + val >>= dev->chunkGroupBits;
4748
4749 - /* Check sane object header chunk */
4750 + bitInMap = pos * dev->tnodeWidth;
4751 + wordInMap = bitInMap / 32;
4752 + bitInWord = bitInMap & (32 - 1);
4753
4754 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
4755 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
4756 + mask = dev->tnodeMask << bitInWord;
4757
4758 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
4759 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
4760 - chunkValid = chunkInRange &&
4761 - yaffs_CheckChunkBit(dev,
4762 - obj->hdrChunk / dev->nChunksPerBlock,
4763 - obj->hdrChunk % dev->nChunksPerBlock);
4764 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
4765 + map[wordInMap] &= ~mask;
4766 + map[wordInMap] |= (mask & (val << bitInWord));
4767
4768 - if (!obj->fake &&
4769 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
4770 - T(YAFFS_TRACE_VERIFY,
4771 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
4772 - obj->objectId, obj->hdrChunk,
4773 - chunkIdOk ? "" : ",out of range",
4774 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
4775 + if (dev->tnodeWidth > (32 - bitInWord)) {
4776 + bitInWord = (32 - bitInWord);
4777 + wordInMap++;;
4778 + mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
4779 + map[wordInMap] &= ~mask;
4780 + map[wordInMap] |= (mask & (val >> bitInWord));
4781 }
4782 +}
4783
4784 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
4785 - yaffs_ExtendedTags tags;
4786 - yaffs_ObjectHeader *oh;
4787 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
4788 -
4789 - oh = (yaffs_ObjectHeader *)buffer;
4790 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4791 + unsigned pos)
4792 +{
4793 + __u32 *map = (__u32 *)tn;
4794 + __u32 bitInMap;
4795 + __u32 bitInWord;
4796 + __u32 wordInMap;
4797 + __u32 val;
4798
4799 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
4800 - &tags);
4801 + pos &= YAFFS_TNODES_LEVEL0_MASK;
4802
4803 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
4804 + bitInMap = pos * dev->tnodeWidth;
4805 + wordInMap = bitInMap / 32;
4806 + bitInWord = bitInMap & (32 - 1);
4807
4808 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
4809 - }
4810 + val = map[wordInMap] >> bitInWord;
4811
4812 - /* Verify it has a parent */
4813 - if (obj && !obj->fake &&
4814 - (!obj->parent || obj->parent->myDev != dev)) {
4815 - T(YAFFS_TRACE_VERIFY,
4816 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
4817 - obj->objectId, obj->parent));
4818 + if (dev->tnodeWidth > (32 - bitInWord)) {
4819 + bitInWord = (32 - bitInWord);
4820 + wordInMap++;;
4821 + val |= (map[wordInMap] << bitInWord);
4822 }
4823
4824 - /* Verify parent is a directory */
4825 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
4826 - T(YAFFS_TRACE_VERIFY,
4827 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
4828 - obj->objectId, obj->parent->variantType));
4829 - }
4830 + val &= dev->tnodeMask;
4831 + val <<= dev->chunkGroupBits;
4832
4833 - switch (obj->variantType) {
4834 - case YAFFS_OBJECT_TYPE_FILE:
4835 - yaffs_VerifyFile(obj);
4836 - break;
4837 - case YAFFS_OBJECT_TYPE_SYMLINK:
4838 - yaffs_VerifySymlink(obj);
4839 - break;
4840 - case YAFFS_OBJECT_TYPE_DIRECTORY:
4841 - yaffs_VerifyDirectory(obj);
4842 - break;
4843 - case YAFFS_OBJECT_TYPE_HARDLINK:
4844 - yaffs_VerifyHardLink(obj);
4845 - break;
4846 - case YAFFS_OBJECT_TYPE_SPECIAL:
4847 - yaffs_VerifySpecial(obj);
4848 - break;
4849 - case YAFFS_OBJECT_TYPE_UNKNOWN:
4850 - default:
4851 - T(YAFFS_TRACE_VERIFY,
4852 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
4853 - obj->objectId, obj->variantType));
4854 - break;
4855 - }
4856 + return val;
4857 }
4858
4859 -static void yaffs_VerifyObjects(yaffs_Device *dev)
4860 +/* ------------------- End of individual tnode manipulation -----------------*/
4861 +
4862 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
4863 + * The look up tree is represented by the top tnode and the number of topLevel
4864 + * in the tree. 0 means only the level 0 tnode is in the tree.
4865 + */
4866 +
4867 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
4868 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4869 + yaffs_FileStructure *fStruct,
4870 + __u32 chunkId)
4871 {
4872 - yaffs_Object *obj;
4873 - int i;
4874 - struct ylist_head *lh;
4875 + yaffs_Tnode *tn = fStruct->top;
4876 + __u32 i;
4877 + int requiredTallness;
4878 + int level = fStruct->topLevel;
4879
4880 - if (yaffs_SkipVerification(dev))
4881 - return;
4882 + dev=dev;
4883
4884 - /* Iterate through the objects in each hash entry */
4885 + /* Check sane level and chunk Id */
4886 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
4887 + return NULL;
4888
4889 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
4890 - ylist_for_each(lh, &dev->objectBucket[i].list) {
4891 - if (lh) {
4892 - obj = ylist_entry(lh, yaffs_Object, hashLink);
4893 - yaffs_VerifyObject(obj);
4894 - }
4895 - }
4896 + if (chunkId > YAFFS_MAX_CHUNK_ID)
4897 + return NULL;
4898 +
4899 + /* First check we're tall enough (ie enough topLevel) */
4900 +
4901 + i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
4902 + requiredTallness = 0;
4903 + while (i) {
4904 + i >>= YAFFS_TNODES_INTERNAL_BITS;
4905 + requiredTallness++;
4906 }
4907 -}
4908
4909 + if (requiredTallness > fStruct->topLevel)
4910 + return NULL; /* Not tall enough, so we can't find it */
4911
4912 -/*
4913 - * Simple hash function. Needs to have a reasonable spread
4914 - */
4915 + /* Traverse down to level 0 */
4916 + while (level > 0 && tn) {
4917 + tn = tn->internal[(chunkId >>
4918 + (YAFFS_TNODES_LEVEL0_BITS +
4919 + (level - 1) *
4920 + YAFFS_TNODES_INTERNAL_BITS)) &
4921 + YAFFS_TNODES_INTERNAL_MASK];
4922 + level--;
4923 + }
4924
4925 -static Y_INLINE int yaffs_HashFunction(int n)
4926 -{
4927 - n = abs(n);
4928 - return n % YAFFS_NOBJECT_BUCKETS;
4929 + return tn;
4930 }
4931
4932 -/*
4933 - * Access functions to useful fake objects.
4934 - * Note that root might have a presence in NAND if permissions are set.
4935 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
4936 + * This happens in two steps:
4937 + * 1. If the tree isn't tall enough, then make it taller.
4938 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
4939 + *
4940 + * Used when modifying the tree.
4941 + *
4942 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
4943 + * be plugged into the ttree.
4944 */
4945
4946 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
4947 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
4948 + yaffs_FileStructure *fStruct,
4949 + __u32 chunkId,
4950 + yaffs_Tnode *passedTn)
4951 {
4952 - return dev->rootDir;
4953 -}
4954 + int requiredTallness;
4955 + int i;
4956 + int l;
4957 + yaffs_Tnode *tn;
4958
4959 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
4960 -{
4961 - return dev->lostNFoundDir;
4962 -}
4963 + __u32 x;
4964
4965
4966 -/*
4967 - * Erased NAND checking functions
4968 - */
4969 + /* Check sane level and page Id */
4970 + if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
4971 + return NULL;
4972
4973 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
4974 -{
4975 - /* Horrible, slow implementation */
4976 - while (nBytes--) {
4977 - if (*buffer != 0xFF)
4978 - return 0;
4979 - buffer++;
4980 - }
4981 - return 1;
4982 -}
4983 -
4984 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4985 - int chunkInNAND)
4986 -{
4987 - int retval = YAFFS_OK;
4988 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
4989 - yaffs_ExtendedTags tags;
4990 - int result;
4991 -
4992 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
4993 -
4994 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
4995 - retval = YAFFS_FAIL;
4996 -
4997 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
4998 - T(YAFFS_TRACE_NANDACCESS,
4999 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
5000 - retval = YAFFS_FAIL;
5001 - }
5002 -
5003 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
5004 -
5005 - return retval;
5006 -
5007 -}
5008 -
5009 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
5010 - const __u8 *data,
5011 - yaffs_ExtendedTags *tags,
5012 - int useReserve)
5013 -{
5014 - int attempts = 0;
5015 - int writeOk = 0;
5016 - int chunk;
5017 -
5018 - yaffs_InvalidateCheckpoint(dev);
5019 -
5020 - do {
5021 - yaffs_BlockInfo *bi = 0;
5022 - int erasedOk = 0;
5023 -
5024 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5025 - if (chunk < 0) {
5026 - /* no space */
5027 - break;
5028 - }
5029 -
5030 - /* First check this chunk is erased, if it needs
5031 - * checking. The checking policy (unless forced
5032 - * always on) is as follows:
5033 - *
5034 - * Check the first page we try to write in a block.
5035 - * If the check passes then we don't need to check any
5036 - * more. If the check fails, we check again...
5037 - * If the block has been erased, we don't need to check.
5038 - *
5039 - * However, if the block has been prioritised for gc,
5040 - * then we think there might be something odd about
5041 - * this block and stop using it.
5042 - *
5043 - * Rationale: We should only ever see chunks that have
5044 - * not been erased if there was a partially written
5045 - * chunk due to power loss. This checking policy should
5046 - * catch that case with very few checks and thus save a
5047 - * lot of checks that are most likely not needed.
5048 - */
5049 - if (bi->gcPrioritise) {
5050 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5051 - /* try another chunk */
5052 - continue;
5053 - }
5054 -
5055 - /* let's give it a try */
5056 - attempts++;
5057 -
5058 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5059 - bi->skipErasedCheck = 0;
5060 -#endif
5061 - if (!bi->skipErasedCheck) {
5062 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5063 - if (erasedOk != YAFFS_OK) {
5064 - T(YAFFS_TRACE_ERROR,
5065 - (TSTR("**>> yaffs chunk %d was not erased"
5066 - TENDSTR), chunk));
5067 -
5068 - /* try another chunk */
5069 - continue;
5070 - }
5071 - bi->skipErasedCheck = 1;
5072 - }
5073 -
5074 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5075 - data, tags);
5076 - if (writeOk != YAFFS_OK) {
5077 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5078 - /* try another chunk */
5079 - continue;
5080 - }
5081 -
5082 - /* Copy the data into the robustification buffer */
5083 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5084 -
5085 - } while (writeOk != YAFFS_OK &&
5086 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5087 -
5088 - if (!writeOk)
5089 - chunk = -1;
5090 -
5091 - if (attempts > 1) {
5092 - T(YAFFS_TRACE_ERROR,
5093 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5094 - attempts));
5095 -
5096 - dev->nRetriedWrites += (attempts - 1);
5097 - }
5098 -
5099 - return chunk;
5100 -}
5101 -
5102 -/*
5103 - * Block retiring for handling a broken block.
5104 - */
5105 -
5106 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5107 -{
5108 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5109 -
5110 - yaffs_InvalidateCheckpoint(dev);
5111 -
5112 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5113 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5114 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5115 - "yaffs: Failed to mark bad and erase block %d"
5116 - TENDSTR), blockInNAND));
5117 - } else {
5118 - yaffs_ExtendedTags tags;
5119 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5120 -
5121 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5122 -
5123 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5124 - yaffs_InitialiseTags(&tags);
5125 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5126 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5127 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5128 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5129 - TCONT("write bad block marker to block %d")
5130 - TENDSTR), blockInNAND));
5131 -
5132 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5133 - }
5134 - }
5135 -
5136 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5137 - bi->gcPrioritise = 0;
5138 - bi->needsRetiring = 0;
5139 -
5140 - dev->nRetiredBlocks++;
5141 -}
5142 -
5143 -/*
5144 - * Functions for robustisizing TODO
5145 - *
5146 - */
5147 -
5148 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5149 - const __u8 *data,
5150 - const yaffs_ExtendedTags *tags)
5151 -{
5152 -}
5153 -
5154 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5155 - const yaffs_ExtendedTags *tags)
5156 -{
5157 -}
5158 -
5159 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5160 -{
5161 - if (!bi->gcPrioritise) {
5162 - bi->gcPrioritise = 1;
5163 - dev->hasPendingPrioritisedGCs = 1;
5164 - bi->chunkErrorStrikes++;
5165 -
5166 - if (bi->chunkErrorStrikes > 3) {
5167 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5168 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5169 -
5170 - }
5171 - }
5172 -}
5173 -
5174 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5175 - int erasedOk)
5176 -{
5177 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5178 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5179 -
5180 - yaffs_HandleChunkError(dev, bi);
5181 -
5182 - if (erasedOk) {
5183 - /* Was an actual write failure, so mark the block for retirement */
5184 - bi->needsRetiring = 1;
5185 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5186 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5187 - }
5188 -
5189 - /* Delete the chunk */
5190 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5191 -}
5192 -
5193 -
5194 -/*---------------- Name handling functions ------------*/
5195 -
5196 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5197 -{
5198 - __u16 sum = 0;
5199 - __u16 i = 1;
5200 -
5201 - const YUCHAR *bname = (const YUCHAR *) name;
5202 - if (bname) {
5203 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5204 -
5205 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5206 - sum += yaffs_toupper(*bname) * i;
5207 -#else
5208 - sum += (*bname) * i;
5209 -#endif
5210 - i++;
5211 - bname++;
5212 - }
5213 - }
5214 - return sum;
5215 -}
5216 -
5217 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
5218 -{
5219 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5220 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5221 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
5222 - yaffs_strcpy(obj->shortName, name);
5223 - else
5224 - obj->shortName[0] = _Y('\0');
5225 -#endif
5226 - obj->sum = yaffs_CalcNameSum(name);
5227 -}
5228 -
5229 -/*-------------------- TNODES -------------------
5230 -
5231 - * List of spare tnodes
5232 - * The list is hooked together using the first pointer
5233 - * in the tnode.
5234 - */
5235 -
5236 -/* yaffs_CreateTnodes creates a bunch more tnodes and
5237 - * adds them to the tnode free list.
5238 - * Don't use this function directly
5239 - */
5240 -
5241 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
5242 -{
5243 - int i;
5244 - int tnodeSize;
5245 - yaffs_Tnode *newTnodes;
5246 - __u8 *mem;
5247 - yaffs_Tnode *curr;
5248 - yaffs_Tnode *next;
5249 - yaffs_TnodeList *tnl;
5250 -
5251 - if (nTnodes < 1)
5252 - return YAFFS_OK;
5253 -
5254 - /* Calculate the tnode size in bytes for variable width tnode support.
5255 - * Must be a multiple of 32-bits */
5256 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5257 -
5258 - if (tnodeSize < sizeof(yaffs_Tnode))
5259 - tnodeSize = sizeof(yaffs_Tnode);
5260 -
5261 - /* make these things */
5262 -
5263 - newTnodes = YMALLOC(nTnodes * tnodeSize);
5264 - mem = (__u8 *)newTnodes;
5265 -
5266 - if (!newTnodes) {
5267 - T(YAFFS_TRACE_ERROR,
5268 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
5269 - return YAFFS_FAIL;
5270 - }
5271 -
5272 - /* Hook them into the free list */
5273 -#if 0
5274 - for (i = 0; i < nTnodes - 1; i++) {
5275 - newTnodes[i].internal[0] = &newTnodes[i + 1];
5276 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5277 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5278 -#endif
5279 - }
5280 -
5281 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
5282 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5283 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5284 -#endif
5285 - dev->freeTnodes = newTnodes;
5286 -#else
5287 - /* New hookup for wide tnodes */
5288 - for (i = 0; i < nTnodes - 1; i++) {
5289 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
5290 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
5291 - curr->internal[0] = next;
5292 - }
5293 -
5294 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
5295 - curr->internal[0] = dev->freeTnodes;
5296 - dev->freeTnodes = (yaffs_Tnode *)mem;
5297 -
5298 -#endif
5299 -
5300 -
5301 - dev->nFreeTnodes += nTnodes;
5302 - dev->nTnodesCreated += nTnodes;
5303 -
5304 - /* Now add this bunch of tnodes to a list for freeing up.
5305 - * NB If we can't add this to the management list it isn't fatal
5306 - * but it just means we can't free this bunch of tnodes later.
5307 - */
5308 -
5309 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
5310 - if (!tnl) {
5311 - T(YAFFS_TRACE_ERROR,
5312 - (TSTR
5313 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
5314 - return YAFFS_FAIL;
5315 - } else {
5316 - tnl->tnodes = newTnodes;
5317 - tnl->next = dev->allocatedTnodeList;
5318 - dev->allocatedTnodeList = tnl;
5319 - }
5320 -
5321 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
5322 -
5323 - return YAFFS_OK;
5324 -}
5325 -
5326 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
5327 -
5328 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
5329 -{
5330 - yaffs_Tnode *tn = NULL;
5331 -
5332 - /* If there are none left make more */
5333 - if (!dev->freeTnodes)
5334 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
5335 -
5336 - if (dev->freeTnodes) {
5337 - tn = dev->freeTnodes;
5338 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5339 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
5340 - /* Hoosterman, this thing looks like it isn't in the list */
5341 - T(YAFFS_TRACE_ALWAYS,
5342 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
5343 - }
5344 -#endif
5345 - dev->freeTnodes = dev->freeTnodes->internal[0];
5346 - dev->nFreeTnodes--;
5347 - }
5348 -
5349 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5350 -
5351 - return tn;
5352 -}
5353 -
5354 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
5355 -{
5356 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
5357 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
5358 -
5359 - if (tnodeSize < sizeof(yaffs_Tnode))
5360 - tnodeSize = sizeof(yaffs_Tnode);
5361 -
5362 - if (tn)
5363 - memset(tn, 0, tnodeSize);
5364 -
5365 - return tn;
5366 -}
5367 -
5368 -/* FreeTnode frees up a tnode and puts it back on the free list */
5369 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
5370 -{
5371 - if (tn) {
5372 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
5373 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
5374 - /* Hoosterman, this thing looks like it is already in the list */
5375 - T(YAFFS_TRACE_ALWAYS,
5376 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
5377 - }
5378 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
5379 -#endif
5380 - tn->internal[0] = dev->freeTnodes;
5381 - dev->freeTnodes = tn;
5382 - dev->nFreeTnodes++;
5383 - }
5384 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
5385 -}
5386 -
5387 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
5388 -{
5389 - /* Free the list of allocated tnodes */
5390 - yaffs_TnodeList *tmp;
5391 -
5392 - while (dev->allocatedTnodeList) {
5393 - tmp = dev->allocatedTnodeList->next;
5394 -
5395 - YFREE(dev->allocatedTnodeList->tnodes);
5396 - YFREE(dev->allocatedTnodeList);
5397 - dev->allocatedTnodeList = tmp;
5398 -
5399 - }
5400 -
5401 - dev->freeTnodes = NULL;
5402 - dev->nFreeTnodes = 0;
5403 -}
5404 -
5405 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
5406 -{
5407 - dev->allocatedTnodeList = NULL;
5408 - dev->freeTnodes = NULL;
5409 - dev->nFreeTnodes = 0;
5410 - dev->nTnodesCreated = 0;
5411 -}
5412 -
5413 -
5414 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
5415 - unsigned val)
5416 -{
5417 - __u32 *map = (__u32 *)tn;
5418 - __u32 bitInMap;
5419 - __u32 bitInWord;
5420 - __u32 wordInMap;
5421 - __u32 mask;
5422 -
5423 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5424 - val >>= dev->chunkGroupBits;
5425 -
5426 - bitInMap = pos * dev->tnodeWidth;
5427 - wordInMap = bitInMap / 32;
5428 - bitInWord = bitInMap & (32 - 1);
5429 -
5430 - mask = dev->tnodeMask << bitInWord;
5431 -
5432 - map[wordInMap] &= ~mask;
5433 - map[wordInMap] |= (mask & (val << bitInWord));
5434 -
5435 - if (dev->tnodeWidth > (32 - bitInWord)) {
5436 - bitInWord = (32 - bitInWord);
5437 - wordInMap++;;
5438 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
5439 - map[wordInMap] &= ~mask;
5440 - map[wordInMap] |= (mask & (val >> bitInWord));
5441 - }
5442 -}
5443 -
5444 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
5445 - unsigned pos)
5446 -{
5447 - __u32 *map = (__u32 *)tn;
5448 - __u32 bitInMap;
5449 - __u32 bitInWord;
5450 - __u32 wordInMap;
5451 - __u32 val;
5452 -
5453 - pos &= YAFFS_TNODES_LEVEL0_MASK;
5454 -
5455 - bitInMap = pos * dev->tnodeWidth;
5456 - wordInMap = bitInMap / 32;
5457 - bitInWord = bitInMap & (32 - 1);
5458 -
5459 - val = map[wordInMap] >> bitInWord;
5460 -
5461 - if (dev->tnodeWidth > (32 - bitInWord)) {
5462 - bitInWord = (32 - bitInWord);
5463 - wordInMap++;;
5464 - val |= (map[wordInMap] << bitInWord);
5465 - }
5466 -
5467 - val &= dev->tnodeMask;
5468 - val <<= dev->chunkGroupBits;
5469 -
5470 - return val;
5471 -}
5472 -
5473 -/* ------------------- End of individual tnode manipulation -----------------*/
5474 -
5475 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5476 - * The look up tree is represented by the top tnode and the number of topLevel
5477 - * in the tree. 0 means only the level 0 tnode is in the tree.
5478 - */
5479 -
5480 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5481 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
5482 - yaffs_FileStructure *fStruct,
5483 - __u32 chunkId)
5484 -{
5485 - yaffs_Tnode *tn = fStruct->top;
5486 - __u32 i;
5487 - int requiredTallness;
5488 - int level = fStruct->topLevel;
5489 -
5490 - /* Check sane level and chunk Id */
5491 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5492 - return NULL;
5493 -
5494 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5495 - return NULL;
5496 -
5497 - /* First check we're tall enough (ie enough topLevel) */
5498 -
5499 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5500 - requiredTallness = 0;
5501 - while (i) {
5502 - i >>= YAFFS_TNODES_INTERNAL_BITS;
5503 - requiredTallness++;
5504 - }
5505 -
5506 - if (requiredTallness > fStruct->topLevel)
5507 - return NULL; /* Not tall enough, so we can't find it */
5508 -
5509 - /* Traverse down to level 0 */
5510 - while (level > 0 && tn) {
5511 - tn = tn->internal[(chunkId >>
5512 - (YAFFS_TNODES_LEVEL0_BITS +
5513 - (level - 1) *
5514 - YAFFS_TNODES_INTERNAL_BITS)) &
5515 - YAFFS_TNODES_INTERNAL_MASK];
5516 - level--;
5517 - }
5518 -
5519 - return tn;
5520 -}
5521 -
5522 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5523 - * This happens in two steps:
5524 - * 1. If the tree isn't tall enough, then make it taller.
5525 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5526 - *
5527 - * Used when modifying the tree.
5528 - *
5529 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5530 - * be plugged into the ttree.
5531 - */
5532 -
5533 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
5534 - yaffs_FileStructure *fStruct,
5535 - __u32 chunkId,
5536 - yaffs_Tnode *passedTn)
5537 -{
5538 - int requiredTallness;
5539 - int i;
5540 - int l;
5541 - yaffs_Tnode *tn;
5542 -
5543 - __u32 x;
5544 -
5545 -
5546 - /* Check sane level and page Id */
5547 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
5548 - return NULL;
5549 -
5550 - if (chunkId > YAFFS_MAX_CHUNK_ID)
5551 - return NULL;
5552 -
5553 - /* First check we're tall enough (ie enough topLevel) */
5554 -
5555 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
5556 - requiredTallness = 0;
5557 - while (x) {
5558 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5559 - requiredTallness++;
5560 - }
5561 -
5562 -
5563 - if (requiredTallness > fStruct->topLevel) {
5564 - /* Not tall enough, gotta make the tree taller */
5565 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
5566 -
5567 - tn = yaffs_GetTnode(dev);
5568 -
5569 - if (tn) {
5570 - tn->internal[0] = fStruct->top;
5571 - fStruct->top = tn;
5572 - } else {
5573 - T(YAFFS_TRACE_ERROR,
5574 - (TSTR("yaffs: no more tnodes" TENDSTR)));
5575 - }
5576 - }
5577 -
5578 - fStruct->topLevel = requiredTallness;
5579 - }
5580 -
5581 - /* Traverse down to level 0, adding anything we need */
5582 -
5583 - l = fStruct->topLevel;
5584 - tn = fStruct->top;
5585 -
5586 - if (l > 0) {
5587 - while (l > 0 && tn) {
5588 - x = (chunkId >>
5589 - (YAFFS_TNODES_LEVEL0_BITS +
5590 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5591 - YAFFS_TNODES_INTERNAL_MASK;
5592 -
5593 -
5594 - if ((l > 1) && !tn->internal[x]) {
5595 - /* Add missing non-level-zero tnode */
5596 - tn->internal[x] = yaffs_GetTnode(dev);
5597 -
5598 - } else if (l == 1) {
5599 - /* Looking from level 1 at level 0 */
5600 - if (passedTn) {
5601 - /* If we already have one, then release it.*/
5602 - if (tn->internal[x])
5603 - yaffs_FreeTnode(dev, tn->internal[x]);
5604 - tn->internal[x] = passedTn;
5605 -
5606 - } else if (!tn->internal[x]) {
5607 - /* Don't have one, none passed in */
5608 - tn->internal[x] = yaffs_GetTnode(dev);
5609 - }
5610 - }
5611 -
5612 - tn = tn->internal[x];
5613 - l--;
5614 - }
5615 - } else {
5616 - /* top is level 0 */
5617 - if (passedTn) {
5618 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
5619 - yaffs_FreeTnode(dev, passedTn);
5620 - }
5621 - }
5622 -
5623 - return tn;
5624 -}
5625 -
5626 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
5627 - yaffs_ExtendedTags *tags, int objectId,
5628 - int chunkInInode)
5629 -{
5630 - int j;
5631 -
5632 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
5633 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
5634 - theChunk % dev->nChunksPerBlock)) {
5635 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
5636 - tags);
5637 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
5638 - /* found it; */
5639 - return theChunk;
5640 - }
5641 - }
5642 - theChunk++;
5643 - }
5644 - return -1;
5645 -}
5646 -
5647 -
5648 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
5649 - * chunks and tnodes in the file
5650 - * Returns 1 if the tree was deleted.
5651 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5652 - */
5653 -
5654 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
5655 - int chunkOffset, int *limit)
5656 -{
5657 - int i;
5658 - int chunkInInode;
5659 - int theChunk;
5660 - yaffs_ExtendedTags tags;
5661 - int foundChunk;
5662 - yaffs_Device *dev = in->myDev;
5663 -
5664 - int allDone = 1;
5665 -
5666 - if (tn) {
5667 - if (level > 0) {
5668 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5669 - i--) {
5670 - if (tn->internal[i]) {
5671 - if (limit && (*limit) < 0) {
5672 - allDone = 0;
5673 - } else {
5674 - allDone =
5675 - yaffs_DeleteWorker(in,
5676 - tn->
5677 - internal
5678 - [i],
5679 - level -
5680 - 1,
5681 - (chunkOffset
5682 - <<
5683 - YAFFS_TNODES_INTERNAL_BITS)
5684 - + i,
5685 - limit);
5686 - }
5687 - if (allDone) {
5688 - yaffs_FreeTnode(dev,
5689 - tn->
5690 - internal[i]);
5691 - tn->internal[i] = NULL;
5692 - }
5693 - }
5694 - }
5695 - return (allDone) ? 1 : 0;
5696 - } else if (level == 0) {
5697 - int hitLimit = 0;
5698 -
5699 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5700 - i--) {
5701 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5702 - if (theChunk) {
5703 -
5704 - chunkInInode = (chunkOffset <<
5705 - YAFFS_TNODES_LEVEL0_BITS) + i;
5706 -
5707 - foundChunk =
5708 - yaffs_FindChunkInGroup(dev,
5709 - theChunk,
5710 - &tags,
5711 - in->objectId,
5712 - chunkInInode);
5713 -
5714 - if (foundChunk > 0) {
5715 - yaffs_DeleteChunk(dev,
5716 - foundChunk, 1,
5717 - __LINE__);
5718 - in->nDataChunks--;
5719 - if (limit) {
5720 - *limit = *limit - 1;
5721 - if (*limit <= 0)
5722 - hitLimit = 1;
5723 - }
5724 -
5725 - }
5726 -
5727 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5728 - }
5729 -
5730 - }
5731 - return (i < 0) ? 1 : 0;
5732 -
5733 - }
5734 -
5735 - }
5736 -
5737 - return 1;
5738 -
5739 -}
5740 -
5741 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
5742 -{
5743 - yaffs_BlockInfo *theBlock;
5744 -
5745 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5746 -
5747 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
5748 - if (theBlock) {
5749 - theBlock->softDeletions++;
5750 - dev->nFreeChunks++;
5751 - }
5752 -}
5753 -
5754 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5755 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5756 - * of the tnode.
5757 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5758 - */
5759 -
5760 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
5761 - __u32 level, int chunkOffset)
5762 -{
5763 - int i;
5764 - int theChunk;
5765 - int allDone = 1;
5766 - yaffs_Device *dev = in->myDev;
5767 -
5768 - if (tn) {
5769 - if (level > 0) {
5770 -
5771 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5772 - i--) {
5773 - if (tn->internal[i]) {
5774 - allDone =
5775 - yaffs_SoftDeleteWorker(in,
5776 - tn->
5777 - internal[i],
5778 - level - 1,
5779 - (chunkOffset
5780 - <<
5781 - YAFFS_TNODES_INTERNAL_BITS)
5782 - + i);
5783 - if (allDone) {
5784 - yaffs_FreeTnode(dev,
5785 - tn->
5786 - internal[i]);
5787 - tn->internal[i] = NULL;
5788 - } else {
5789 - /* Hoosterman... how could this happen? */
5790 - }
5791 - }
5792 - }
5793 - return (allDone) ? 1 : 0;
5794 - } else if (level == 0) {
5795 -
5796 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
5797 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5798 - if (theChunk) {
5799 - /* Note this does not find the real chunk, only the chunk group.
5800 - * We make an assumption that a chunk group is not larger than
5801 - * a block.
5802 - */
5803 - yaffs_SoftDeleteChunk(dev, theChunk);
5804 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
5805 - }
5806 -
5807 - }
5808 - return 1;
5809 -
5810 - }
5811 -
5812 - }
5813 -
5814 - return 1;
5815 -
5816 -}
5817 -
5818 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
5819 -{
5820 - if (obj->deleted &&
5821 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
5822 - if (obj->nDataChunks <= 0) {
5823 - /* Empty file with no duplicate object headers, just delete it immediately */
5824 - yaffs_FreeTnode(obj->myDev,
5825 - obj->variant.fileVariant.top);
5826 - obj->variant.fileVariant.top = NULL;
5827 - T(YAFFS_TRACE_TRACING,
5828 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
5829 - obj->objectId));
5830 - yaffs_DoGenericObjectDeletion(obj);
5831 - } else {
5832 - yaffs_SoftDeleteWorker(obj,
5833 - obj->variant.fileVariant.top,
5834 - obj->variant.fileVariant.
5835 - topLevel, 0);
5836 - obj->softDeleted = 1;
5837 - }
5838 - }
5839 -}
5840 -
5841 -/* Pruning removes any part of the file structure tree that is beyond the
5842 - * bounds of the file (ie that does not point to chunks).
5843 - *
5844 - * A file should only get pruned when its size is reduced.
5845 - *
5846 - * Before pruning, the chunks must be pulled from the tree and the
5847 - * level 0 tnode entries must be zeroed out.
5848 - * Could also use this for file deletion, but that's probably better handled
5849 - * by a special case.
5850 - */
5851 -
5852 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
5853 - __u32 level, int del0)
5854 -{
5855 - int i;
5856 - int hasData;
5857 -
5858 - if (tn) {
5859 - hasData = 0;
5860 -
5861 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
5862 - if (tn->internal[i] && level > 0) {
5863 - tn->internal[i] =
5864 - yaffs_PruneWorker(dev, tn->internal[i],
5865 - level - 1,
5866 - (i == 0) ? del0 : 1);
5867 - }
5868 -
5869 - if (tn->internal[i])
5870 - hasData++;
5871 - }
5872 -
5873 - if (hasData == 0 && del0) {
5874 - /* Free and return NULL */
5875 -
5876 - yaffs_FreeTnode(dev, tn);
5877 - tn = NULL;
5878 - }
5879 -
5880 - }
5881 -
5882 - return tn;
5883 -
5884 -}
5885 -
5886 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
5887 - yaffs_FileStructure *fStruct)
5888 -{
5889 - int i;
5890 - int hasData;
5891 - int done = 0;
5892 - yaffs_Tnode *tn;
5893 -
5894 - if (fStruct->topLevel > 0) {
5895 - fStruct->top =
5896 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
5897 -
5898 - /* Now we have a tree with all the non-zero branches NULL but the height
5899 - * is the same as it was.
5900 - * Let's see if we can trim internal tnodes to shorten the tree.
5901 - * We can do this if only the 0th element in the tnode is in use
5902 - * (ie all the non-zero are NULL)
5903 - */
5904 -
5905 - while (fStruct->topLevel && !done) {
5906 - tn = fStruct->top;
5907 -
5908 - hasData = 0;
5909 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
5910 - if (tn->internal[i])
5911 - hasData++;
5912 - }
5913 -
5914 - if (!hasData) {
5915 - fStruct->top = tn->internal[0];
5916 - fStruct->topLevel--;
5917 - yaffs_FreeTnode(dev, tn);
5918 - } else {
5919 - done = 1;
5920 - }
5921 - }
5922 - }
5923 -
5924 - return YAFFS_OK;
5925 -}
5926 -
5927 -/*-------------------- End of File Structure functions.-------------------*/
5928 -
5929 -/* yaffs_CreateFreeObjects creates a bunch more objects and
5930 - * adds them to the object free list.
5931 - */
5932 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
5933 -{
5934 - int i;
5935 - yaffs_Object *newObjects;
5936 - yaffs_ObjectList *list;
5937 -
5938 - if (nObjects < 1)
5939 - return YAFFS_OK;
5940 -
5941 - /* make these things */
5942 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
5943 - list = YMALLOC(sizeof(yaffs_ObjectList));
5944 -
5945 - if (!newObjects || !list) {
5946 - if (newObjects)
5947 - YFREE(newObjects);
5948 - if (list)
5949 - YFREE(list);
5950 - T(YAFFS_TRACE_ALLOCATE,
5951 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
5952 - return YAFFS_FAIL;
5953 - }
5954 -
5955 - /* Hook them into the free list */
5956 - for (i = 0; i < nObjects - 1; i++) {
5957 - newObjects[i].siblings.next =
5958 - (struct ylist_head *)(&newObjects[i + 1]);
5959 - }
5960 -
5961 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
5962 - dev->freeObjects = newObjects;
5963 - dev->nFreeObjects += nObjects;
5964 - dev->nObjectsCreated += nObjects;
5965 -
5966 - /* Now add this bunch of Objects to a list for freeing up. */
5967 -
5968 - list->objects = newObjects;
5969 - list->next = dev->allocatedObjectList;
5970 - dev->allocatedObjectList = list;
5971 -
5972 - return YAFFS_OK;
5973 -}
5974 -
5975 -
5976 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
5977 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
5978 -{
5979 - yaffs_Object *tn = NULL;
5980 -
5981 -#ifdef VALGRIND_TEST
5982 - tn = YMALLOC(sizeof(yaffs_Object));
5983 -#else
5984 - /* If there are none left make more */
5985 - if (!dev->freeObjects)
5986 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
5987 -
5988 - if (dev->freeObjects) {
5989 - tn = dev->freeObjects;
5990 - dev->freeObjects =
5991 - (yaffs_Object *) (dev->freeObjects->siblings.next);
5992 - dev->nFreeObjects--;
5993 - }
5994 -#endif
5995 - if (tn) {
5996 - /* Now sweeten it up... */
5997 -
5998 - memset(tn, 0, sizeof(yaffs_Object));
5999 - tn->beingCreated = 1;
6000 -
6001 - tn->myDev = dev;
6002 - tn->hdrChunk = 0;
6003 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
6004 - YINIT_LIST_HEAD(&(tn->hardLinks));
6005 - YINIT_LIST_HEAD(&(tn->hashLink));
6006 - YINIT_LIST_HEAD(&tn->siblings);
6007 -
6008 -
6009 - /* Now make the directory sane */
6010 - if (dev->rootDir) {
6011 - tn->parent = dev->rootDir;
6012 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
6013 - }
6014 -
6015 - /* Add it to the lost and found directory.
6016 - * NB Can't put root or lostNFound in lostNFound so
6017 - * check if lostNFound exists first
6018 - */
6019 - if (dev->lostNFoundDir)
6020 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
6021 -
6022 - tn->beingCreated = 0;
6023 - }
6024 -
6025 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6026 -
6027 - return tn;
6028 -}
6029 -
6030 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
6031 - __u32 mode)
6032 -{
6033 -
6034 - yaffs_Object *obj =
6035 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6036 - if (obj) {
6037 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
6038 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
6039 - obj->unlinkAllowed = 0; /* ... or unlink it */
6040 - obj->deleted = 0;
6041 - obj->unlinked = 0;
6042 - obj->yst_mode = mode;
6043 - obj->myDev = dev;
6044 - obj->hdrChunk = 0; /* Not a valid chunk. */
6045 - }
6046 -
6047 - return obj;
6048 -
6049 -}
6050 -
6051 -static void yaffs_UnhashObject(yaffs_Object *tn)
6052 -{
6053 - int bucket;
6054 - yaffs_Device *dev = tn->myDev;
6055 -
6056 - /* If it is still linked into the bucket list, free from the list */
6057 - if (!ylist_empty(&tn->hashLink)) {
6058 - ylist_del_init(&tn->hashLink);
6059 - bucket = yaffs_HashFunction(tn->objectId);
6060 - dev->objectBucket[bucket].count--;
6061 - }
6062 -}
6063 -
6064 -/* FreeObject frees up a Object and puts it back on the free list */
6065 -static void yaffs_FreeObject(yaffs_Object *tn)
6066 -{
6067 - yaffs_Device *dev = tn->myDev;
6068 -
6069 -#ifdef __KERNEL__
6070 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
6071 -#endif
6072 -
6073 - if (tn->parent)
6074 - YBUG();
6075 - if (!ylist_empty(&tn->siblings))
6076 - YBUG();
6077 -
6078 -
6079 -#ifdef __KERNEL__
6080 - if (tn->myInode) {
6081 - /* We're still hooked up to a cached inode.
6082 - * Don't delete now, but mark for later deletion
6083 - */
6084 - tn->deferedFree = 1;
6085 - return;
6086 - }
6087 -#endif
6088 -
6089 - yaffs_UnhashObject(tn);
6090 -
6091 -#ifdef VALGRIND_TEST
6092 - YFREE(tn);
6093 -#else
6094 - /* Link into the free list. */
6095 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
6096 - dev->freeObjects = tn;
6097 - dev->nFreeObjects++;
6098 -#endif
6099 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6100 -}
6101 -
6102 -#ifdef __KERNEL__
6103 -
6104 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
6105 -{
6106 - if (obj->deferedFree)
6107 - yaffs_FreeObject(obj);
6108 -}
6109 -
6110 -#endif
6111 -
6112 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
6113 -{
6114 - /* Free the list of allocated Objects */
6115 -
6116 - yaffs_ObjectList *tmp;
6117 -
6118 - while (dev->allocatedObjectList) {
6119 - tmp = dev->allocatedObjectList->next;
6120 - YFREE(dev->allocatedObjectList->objects);
6121 - YFREE(dev->allocatedObjectList);
6122 -
6123 - dev->allocatedObjectList = tmp;
6124 - }
6125 -
6126 - dev->freeObjects = NULL;
6127 - dev->nFreeObjects = 0;
6128 -}
6129 -
6130 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
6131 -{
6132 - int i;
6133 -
6134 - dev->allocatedObjectList = NULL;
6135 - dev->freeObjects = NULL;
6136 - dev->nFreeObjects = 0;
6137 -
6138 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6139 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
6140 - dev->objectBucket[i].count = 0;
6141 - }
6142 -}
6143 -
6144 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
6145 -{
6146 - static int x;
6147 - int i;
6148 - int l = 999;
6149 - int lowest = 999999;
6150 -
6151 - /* First let's see if we can find one that's empty. */
6152 -
6153 - for (i = 0; i < 10 && lowest > 0; i++) {
6154 - x++;
6155 - x %= YAFFS_NOBJECT_BUCKETS;
6156 - if (dev->objectBucket[x].count < lowest) {
6157 - lowest = dev->objectBucket[x].count;
6158 - l = x;
6159 - }
6160 -
6161 - }
6162 -
6163 - /* If we didn't find an empty list, then try
6164 - * looking a bit further for a short one
6165 - */
6166 -
6167 - for (i = 0; i < 10 && lowest > 3; i++) {
6168 - x++;
6169 - x %= YAFFS_NOBJECT_BUCKETS;
6170 - if (dev->objectBucket[x].count < lowest) {
6171 - lowest = dev->objectBucket[x].count;
6172 - l = x;
6173 - }
6174 -
6175 - }
6176 -
6177 - return l;
6178 -}
6179 -
6180 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
6181 -{
6182 - int bucket = yaffs_FindNiceObjectBucket(dev);
6183 -
6184 - /* Now find an object value that has not already been taken
6185 - * by scanning the list.
6186 - */
6187 -
6188 - int found = 0;
6189 - struct ylist_head *i;
6190 -
6191 - __u32 n = (__u32) bucket;
6192 -
6193 - /* yaffs_CheckObjectHashSanity(); */
6194 -
6195 - while (!found) {
6196 - found = 1;
6197 - n += YAFFS_NOBJECT_BUCKETS;
6198 - if (1 || dev->objectBucket[bucket].count > 0) {
6199 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6200 - /* If there is already one in the list */
6201 - if (i && ylist_entry(i, yaffs_Object,
6202 - hashLink)->objectId == n) {
6203 - found = 0;
6204 - }
6205 - }
6206 - }
6207 - }
6208 -
6209 - return n;
6210 -}
6211 -
6212 -static void yaffs_HashObject(yaffs_Object *in)
6213 -{
6214 - int bucket = yaffs_HashFunction(in->objectId);
6215 - yaffs_Device *dev = in->myDev;
6216 -
6217 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
6218 - dev->objectBucket[bucket].count++;
6219 -}
6220 -
6221 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
6222 -{
6223 - int bucket = yaffs_HashFunction(number);
6224 - struct ylist_head *i;
6225 - yaffs_Object *in;
6226 -
6227 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
6228 - /* Look if it is in the list */
6229 - if (i) {
6230 - in = ylist_entry(i, yaffs_Object, hashLink);
6231 - if (in->objectId == number) {
6232 -#ifdef __KERNEL__
6233 - /* Don't tell the VFS about this one if it is defered free */
6234 - if (in->deferedFree)
6235 - return NULL;
6236 -#endif
6237 -
6238 - return in;
6239 - }
6240 - }
6241 - }
6242 -
6243 - return NULL;
6244 -}
6245 -
6246 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
6247 - yaffs_ObjectType type)
6248 -{
6249 - yaffs_Object *theObject;
6250 - yaffs_Tnode *tn = NULL;
6251 -
6252 - if (number < 0)
6253 - number = yaffs_CreateNewObjectNumber(dev);
6254 -
6255 - theObject = yaffs_AllocateEmptyObject(dev);
6256 - if (!theObject)
6257 - return NULL;
6258 -
6259 - if (type == YAFFS_OBJECT_TYPE_FILE) {
6260 - tn = yaffs_GetTnode(dev);
6261 - if (!tn) {
6262 - yaffs_FreeObject(theObject);
6263 - return NULL;
6264 - }
6265 - }
6266 -
6267 - if (theObject) {
6268 - theObject->fake = 0;
6269 - theObject->renameAllowed = 1;
6270 - theObject->unlinkAllowed = 1;
6271 - theObject->objectId = number;
6272 - yaffs_HashObject(theObject);
6273 - theObject->variantType = type;
6274 -#ifdef CONFIG_YAFFS_WINCE
6275 - yfsd_WinFileTimeNow(theObject->win_atime);
6276 - theObject->win_ctime[0] = theObject->win_mtime[0] =
6277 - theObject->win_atime[0];
6278 - theObject->win_ctime[1] = theObject->win_mtime[1] =
6279 - theObject->win_atime[1];
6280 -
6281 -#else
6282 -
6283 - theObject->yst_atime = theObject->yst_mtime =
6284 - theObject->yst_ctime = Y_CURRENT_TIME;
6285 -#endif
6286 - switch (type) {
6287 - case YAFFS_OBJECT_TYPE_FILE:
6288 - theObject->variant.fileVariant.fileSize = 0;
6289 - theObject->variant.fileVariant.scannedFileSize = 0;
6290 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
6291 - theObject->variant.fileVariant.topLevel = 0;
6292 - theObject->variant.fileVariant.top = tn;
6293 - break;
6294 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6295 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
6296 - children);
6297 - break;
6298 - case YAFFS_OBJECT_TYPE_SYMLINK:
6299 - case YAFFS_OBJECT_TYPE_HARDLINK:
6300 - case YAFFS_OBJECT_TYPE_SPECIAL:
6301 - /* No action required */
6302 - break;
6303 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6304 - /* todo this should not happen */
6305 - break;
6306 - }
6307 - }
6308 -
6309 - return theObject;
6310 -}
6311 -
6312 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
6313 - int number,
6314 - yaffs_ObjectType type)
6315 -{
6316 - yaffs_Object *theObject = NULL;
6317 -
6318 - if (number > 0)
6319 - theObject = yaffs_FindObjectByNumber(dev, number);
6320 -
6321 - if (!theObject)
6322 - theObject = yaffs_CreateNewObject(dev, number, type);
6323 -
6324 - return theObject;
6325 -
6326 -}
6327 -
6328 -
6329 -static YCHAR *yaffs_CloneString(const YCHAR *str)
6330 -{
6331 - YCHAR *newStr = NULL;
6332 -
6333 - if (str && *str) {
6334 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
6335 - if (newStr)
6336 - yaffs_strcpy(newStr, str);
6337 - }
6338 -
6339 - return newStr;
6340 -
6341 -}
6342 -
6343 -/*
6344 - * Mknod (create) a new object.
6345 - * equivalentObject only has meaning for a hard link;
6346 - * aliasString only has meaning for a sumlink.
6347 - * rdev only has meaning for devices (a subset of special objects)
6348 - */
6349 -
6350 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
6351 - yaffs_Object *parent,
6352 - const YCHAR *name,
6353 - __u32 mode,
6354 - __u32 uid,
6355 - __u32 gid,
6356 - yaffs_Object *equivalentObject,
6357 - const YCHAR *aliasString, __u32 rdev)
6358 -{
6359 - yaffs_Object *in;
6360 - YCHAR *str = NULL;
6361 -
6362 - yaffs_Device *dev = parent->myDev;
6363 -
6364 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
6365 - if (yaffs_FindObjectByName(parent, name))
6366 - return NULL;
6367 -
6368 - in = yaffs_CreateNewObject(dev, -1, type);
6369 -
6370 - if (!in)
6371 - return YAFFS_FAIL;
6372 -
6373 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
6374 - str = yaffs_CloneString(aliasString);
6375 - if (!str) {
6376 - yaffs_FreeObject(in);
6377 - return NULL;
6378 - }
6379 - }
6380 -
6381 -
6382 -
6383 - if (in) {
6384 - in->hdrChunk = 0;
6385 - in->valid = 1;
6386 - in->variantType = type;
6387 -
6388 - in->yst_mode = mode;
6389 -
6390 -#ifdef CONFIG_YAFFS_WINCE
6391 - yfsd_WinFileTimeNow(in->win_atime);
6392 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
6393 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
6394 -
6395 -#else
6396 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
6397 -
6398 - in->yst_rdev = rdev;
6399 - in->yst_uid = uid;
6400 - in->yst_gid = gid;
6401 -#endif
6402 - in->nDataChunks = 0;
6403 -
6404 - yaffs_SetObjectName(in, name);
6405 - in->dirty = 1;
6406 -
6407 - yaffs_AddObjectToDirectory(parent, in);
6408 -
6409 - in->myDev = parent->myDev;
6410 -
6411 - switch (type) {
6412 - case YAFFS_OBJECT_TYPE_SYMLINK:
6413 - in->variant.symLinkVariant.alias = str;
6414 - break;
6415 - case YAFFS_OBJECT_TYPE_HARDLINK:
6416 - in->variant.hardLinkVariant.equivalentObject =
6417 - equivalentObject;
6418 - in->variant.hardLinkVariant.equivalentObjectId =
6419 - equivalentObject->objectId;
6420 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
6421 - break;
6422 - case YAFFS_OBJECT_TYPE_FILE:
6423 - case YAFFS_OBJECT_TYPE_DIRECTORY:
6424 - case YAFFS_OBJECT_TYPE_SPECIAL:
6425 - case YAFFS_OBJECT_TYPE_UNKNOWN:
6426 - /* do nothing */
6427 - break;
6428 - }
6429 -
6430 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
6431 - /* Could not create the object header, fail the creation */
6432 - yaffs_DeleteObject(in);
6433 - in = NULL;
6434 - }
6435 -
6436 - }
6437 -
6438 - return in;
6439 -}
6440 -
6441 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
6442 - __u32 mode, __u32 uid, __u32 gid)
6443 -{
6444 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
6445 - uid, gid, NULL, NULL, 0);
6446 -}
6447 -
6448 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
6449 - __u32 mode, __u32 uid, __u32 gid)
6450 -{
6451 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
6452 - mode, uid, gid, NULL, NULL, 0);
6453 -}
6454 -
6455 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
6456 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
6457 -{
6458 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
6459 - uid, gid, NULL, NULL, rdev);
6460 -}
6461 -
6462 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
6463 - __u32 mode, __u32 uid, __u32 gid,
6464 - const YCHAR *alias)
6465 -{
6466 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
6467 - uid, gid, NULL, alias, 0);
6468 -}
6469 -
6470 -/* yaffs_Link returns the object id of the equivalent object.*/
6471 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
6472 - yaffs_Object *equivalentObject)
6473 -{
6474 - /* Get the real object in case we were fed a hard link as an equivalent object */
6475 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
6476 -
6477 - if (yaffs_MknodObject
6478 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
6479 - equivalentObject, NULL, 0)) {
6480 - return equivalentObject;
6481 - } else {
6482 - return NULL;
6483 - }
6484 -
6485 -}
6486 -
6487 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
6488 - const YCHAR *newName, int force, int shadows)
6489 -{
6490 - int unlinkOp;
6491 - int deleteOp;
6492 -
6493 - yaffs_Object *existingTarget;
6494 -
6495 - if (newDir == NULL)
6496 - newDir = obj->parent; /* use the old directory */
6497 -
6498 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6499 - T(YAFFS_TRACE_ALWAYS,
6500 - (TSTR
6501 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
6502 - TENDSTR)));
6503 - YBUG();
6504 - }
6505 -
6506 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
6507 - if (obj->myDev->isYaffs2)
6508 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
6509 - else
6510 - unlinkOp = (newDir == obj->myDev->unlinkedDir
6511 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
6512 -
6513 - deleteOp = (newDir == obj->myDev->deletedDir);
6514 -
6515 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6516 -
6517 - /* If the object is a file going into the unlinked directory,
6518 - * then it is OK to just stuff it in since duplicate names are allowed.
6519 - * else only proceed if the new name does not exist and if we're putting
6520 - * it into a directory.
6521 - */
6522 - if ((unlinkOp ||
6523 - deleteOp ||
6524 - force ||
6525 - (shadows > 0) ||
6526 - !existingTarget) &&
6527 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
6528 - yaffs_SetObjectName(obj, newName);
6529 - obj->dirty = 1;
6530 -
6531 - yaffs_AddObjectToDirectory(newDir, obj);
6532 -
6533 - if (unlinkOp)
6534 - obj->unlinked = 1;
6535 -
6536 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
6537 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
6538 - return YAFFS_OK;
6539 - }
6540 -
6541 - return YAFFS_FAIL;
6542 -}
6543 -
6544 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
6545 - yaffs_Object *newDir, const YCHAR *newName)
6546 -{
6547 - yaffs_Object *obj = NULL;
6548 - yaffs_Object *existingTarget = NULL;
6549 - int force = 0;
6550 -
6551 -
6552 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6553 - YBUG();
6554 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6555 - YBUG();
6556 -
6557 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6558 - /* Special case for case insemsitive systems (eg. WinCE).
6559 - * While look-up is case insensitive, the name isn't.
6560 - * Therefore we might want to change x.txt to X.txt
6561 - */
6562 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
6563 - force = 1;
6564 -#endif
6565 -
6566 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
6567 - /* ENAMETOOLONG */
6568 - return YAFFS_FAIL;
6569 -
6570 - obj = yaffs_FindObjectByName(oldDir, oldName);
6571 -
6572 - if (obj && obj->renameAllowed) {
6573 -
6574 - /* Now do the handling for an existing target, if there is one */
6575 -
6576 - existingTarget = yaffs_FindObjectByName(newDir, newName);
6577 - if (existingTarget &&
6578 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
6579 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
6580 - /* There is a target that is a non-empty directory, so we fail */
6581 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
6582 - } else if (existingTarget && existingTarget != obj) {
6583 - /* Nuke the target first, using shadowing,
6584 - * but only if it isn't the same object
6585 - */
6586 - yaffs_ChangeObjectName(obj, newDir, newName, force,
6587 - existingTarget->objectId);
6588 - yaffs_UnlinkObject(existingTarget);
6589 - }
6590 -
6591 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
6592 - }
6593 - return YAFFS_FAIL;
6594 -}
6595 -
6596 -/*------------------------- Block Management and Page Allocation ----------------*/
6597 -
6598 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
6599 -{
6600 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6601 -
6602 - dev->blockInfo = NULL;
6603 - dev->chunkBits = NULL;
6604 -
6605 - dev->allocationBlock = -1; /* force it to get a new one */
6606 -
6607 - /* If the first allocation strategy fails, thry the alternate one */
6608 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
6609 - if (!dev->blockInfo) {
6610 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
6611 - dev->blockInfoAlt = 1;
6612 - } else
6613 - dev->blockInfoAlt = 0;
6614 -
6615 - if (dev->blockInfo) {
6616 - /* Set up dynamic blockinfo stuff. */
6617 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
6618 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
6619 - if (!dev->chunkBits) {
6620 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
6621 - dev->chunkBitsAlt = 1;
6622 - } else
6623 - dev->chunkBitsAlt = 0;
6624 - }
6625 -
6626 - if (dev->blockInfo && dev->chunkBits) {
6627 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
6628 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
6629 - return YAFFS_OK;
6630 - }
6631 -
6632 - return YAFFS_FAIL;
6633 -}
6634 -
6635 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
6636 -{
6637 - if (dev->blockInfoAlt && dev->blockInfo)
6638 - YFREE_ALT(dev->blockInfo);
6639 - else if (dev->blockInfo)
6640 - YFREE(dev->blockInfo);
6641 -
6642 - dev->blockInfoAlt = 0;
6643 -
6644 - dev->blockInfo = NULL;
6645 -
6646 - if (dev->chunkBitsAlt && dev->chunkBits)
6647 - YFREE_ALT(dev->chunkBits);
6648 - else if (dev->chunkBits)
6649 - YFREE(dev->chunkBits);
6650 - dev->chunkBitsAlt = 0;
6651 - dev->chunkBits = NULL;
6652 -}
6653 -
6654 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
6655 - yaffs_BlockInfo *bi)
6656 -{
6657 - int i;
6658 - __u32 seq;
6659 - yaffs_BlockInfo *b;
6660 -
6661 - if (!dev->isYaffs2)
6662 - return 1; /* disqualification only applies to yaffs2. */
6663 -
6664 - if (!bi->hasShrinkHeader)
6665 - return 1; /* can gc */
6666 -
6667 - /* Find the oldest dirty sequence number if we don't know it and save it
6668 - * so we don't have to keep recomputing it.
6669 - */
6670 - if (!dev->oldestDirtySequence) {
6671 - seq = dev->sequenceNumber;
6672 -
6673 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
6674 - i++) {
6675 - b = yaffs_GetBlockInfo(dev, i);
6676 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
6677 - (b->pagesInUse - b->softDeletions) <
6678 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
6679 - seq = b->sequenceNumber;
6680 - }
6681 - }
6682 - dev->oldestDirtySequence = seq;
6683 - }
6684 -
6685 - /* Can't do gc of this block if there are any blocks older than this one that have
6686 - * discarded pages.
6687 - */
6688 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
6689 -}
6690 -
6691 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
6692 - * for garbage collection.
6693 - */
6694 -
6695 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
6696 - int aggressive)
6697 -{
6698 - int b = dev->currentDirtyChecker;
6699 -
6700 - int i;
6701 - int iterations;
6702 - int dirtiest = -1;
6703 - int pagesInUse = 0;
6704 - int prioritised = 0;
6705 - yaffs_BlockInfo *bi;
6706 - int pendingPrioritisedExist = 0;
6707 -
6708 - /* First let's see if we need to grab a prioritised block */
6709 - if (dev->hasPendingPrioritisedGCs) {
6710 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
6711 -
6712 - bi = yaffs_GetBlockInfo(dev, i);
6713 - /* yaffs_VerifyBlock(dev,bi,i); */
6714 -
6715 - if (bi->gcPrioritise) {
6716 - pendingPrioritisedExist = 1;
6717 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6718 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6719 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6720 - dirtiest = i;
6721 - prioritised = 1;
6722 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
6723 - }
6724 - }
6725 - }
6726 -
6727 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
6728 - dev->hasPendingPrioritisedGCs = 0;
6729 - }
6730 -
6731 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
6732 - * search harder.
6733 - * else (we're doing a leasurely gc), then we only bother to do this if the
6734 - * block has only a few pages in use.
6735 - */
6736 -
6737 - dev->nonAggressiveSkip--;
6738 -
6739 - if (!aggressive && (dev->nonAggressiveSkip > 0))
6740 - return -1;
6741 -
6742 - if (!prioritised)
6743 - pagesInUse =
6744 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
6745 -
6746 - if (aggressive)
6747 - iterations =
6748 - dev->internalEndBlock - dev->internalStartBlock + 1;
6749 - else {
6750 - iterations =
6751 - dev->internalEndBlock - dev->internalStartBlock + 1;
6752 - iterations = iterations / 16;
6753 - if (iterations > 200)
6754 - iterations = 200;
6755 - }
6756 -
6757 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
6758 - b++;
6759 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
6760 - b = dev->internalStartBlock;
6761 -
6762 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
6763 - T(YAFFS_TRACE_ERROR,
6764 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
6765 - YBUG();
6766 - }
6767 -
6768 - bi = yaffs_GetBlockInfo(dev, b);
6769 -
6770 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
6771 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
6772 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
6773 - dirtiest = b;
6774 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
6775 - }
6776 - }
6777 -
6778 - dev->currentDirtyChecker = b;
6779 -
6780 - if (dirtiest > 0) {
6781 - T(YAFFS_TRACE_GC,
6782 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
6783 - dev->nChunksPerBlock - pagesInUse, prioritised));
6784 - }
6785 -
6786 - dev->oldestDirtySequence = 0;
6787 -
6788 - if (dirtiest > 0)
6789 - dev->nonAggressiveSkip = 4;
6790 -
6791 - return dirtiest;
6792 -}
6793 -
6794 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
6795 -{
6796 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
6797 -
6798 - int erasedOk = 0;
6799 -
6800 - /* If the block is still healthy erase it and mark as clean.
6801 - * If the block has had a data failure, then retire it.
6802 - */
6803 -
6804 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
6805 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
6806 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
6807 -
6808 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
6809 -
6810 - if (!bi->needsRetiring) {
6811 - yaffs_InvalidateCheckpoint(dev);
6812 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
6813 - if (!erasedOk) {
6814 - dev->nErasureFailures++;
6815 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6816 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
6817 - }
6818 - }
6819 -
6820 - if (erasedOk &&
6821 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
6822 - int i;
6823 - for (i = 0; i < dev->nChunksPerBlock; i++) {
6824 - if (!yaffs_CheckChunkErased
6825 - (dev, blockNo * dev->nChunksPerBlock + i)) {
6826 - T(YAFFS_TRACE_ERROR,
6827 - (TSTR
6828 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
6829 - TENDSTR), blockNo, i));
6830 - }
6831 - }
6832 - }
6833 -
6834 - if (erasedOk) {
6835 - /* Clean it up... */
6836 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
6837 - dev->nErasedBlocks++;
6838 - bi->pagesInUse = 0;
6839 - bi->softDeletions = 0;
6840 - bi->hasShrinkHeader = 0;
6841 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
6842 - bi->gcPrioritise = 0;
6843 - yaffs_ClearChunkBits(dev, blockNo);
6844 -
6845 - T(YAFFS_TRACE_ERASE,
6846 - (TSTR("Erased block %d" TENDSTR), blockNo));
6847 - } else {
6848 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
6849 -
6850 - yaffs_RetireBlock(dev, blockNo);
6851 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
6852 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
6853 - }
6854 -}
6855 -
6856 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
6857 -{
6858 - int i;
6859 -
6860 - yaffs_BlockInfo *bi;
6861 -
6862 - if (dev->nErasedBlocks < 1) {
6863 - /* Hoosterman we've got a problem.
6864 - * Can't get space to gc
6865 - */
6866 - T(YAFFS_TRACE_ERROR,
6867 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
6868 -
6869 - return -1;
6870 - }
6871 -
6872 - /* Find an empty block. */
6873 -
6874 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
6875 - dev->allocationBlockFinder++;
6876 - if (dev->allocationBlockFinder < dev->internalStartBlock
6877 - || dev->allocationBlockFinder > dev->internalEndBlock) {
6878 - dev->allocationBlockFinder = dev->internalStartBlock;
6879 - }
6880 -
6881 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
6882 -
6883 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
6884 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
6885 - dev->sequenceNumber++;
6886 - bi->sequenceNumber = dev->sequenceNumber;
6887 - dev->nErasedBlocks--;
6888 - T(YAFFS_TRACE_ALLOCATE,
6889 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
6890 - dev->allocationBlockFinder, dev->sequenceNumber,
6891 - dev->nErasedBlocks));
6892 - return dev->allocationBlockFinder;
6893 - }
6894 - }
6895 -
6896 - T(YAFFS_TRACE_ALWAYS,
6897 - (TSTR
6898 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
6899 - TENDSTR), dev->nErasedBlocks));
6900 -
6901 - return -1;
6902 -}
6903 -
6904 -
6905 -
6906 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
6907 -{
6908 - if (!dev->nCheckpointBlocksRequired &&
6909 - dev->isYaffs2) {
6910 - /* Not a valid value so recalculate */
6911 - int nBytes = 0;
6912 - int nBlocks;
6913 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
6914 - int tnodeSize;
6915 -
6916 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6917 -
6918 - if (tnodeSize < sizeof(yaffs_Tnode))
6919 - tnodeSize = sizeof(yaffs_Tnode);
6920 -
6921 - nBytes += sizeof(yaffs_CheckpointValidity);
6922 - nBytes += sizeof(yaffs_CheckpointDevice);
6923 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
6924 - nBytes += devBlocks * dev->chunkBitmapStride;
6925 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
6926 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
6927 - nBytes += sizeof(yaffs_CheckpointValidity);
6928 - nBytes += sizeof(__u32); /* checksum*/
6929 -
6930 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
6931 -
6932 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
6933 -
6934 - dev->nCheckpointBlocksRequired = nBlocks;
6935 - }
6936 -
6937 - return dev->nCheckpointBlocksRequired;
6938 -}
6939 -
6940 -/*
6941 - * Check if there's space to allocate...
6942 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
6943 - */
6944 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
6945 -{
6946 - int reservedChunks;
6947 - int reservedBlocks = dev->nReservedBlocks;
6948 - int checkpointBlocks;
6949 -
6950 - if (dev->isYaffs2) {
6951 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
6952 - dev->blocksInCheckpoint;
6953 - if (checkpointBlocks < 0)
6954 - checkpointBlocks = 0;
6955 - } else {
6956 - checkpointBlocks = 0;
6957 - }
6958 -
6959 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
6960 -
6961 - return (dev->nFreeChunks > reservedChunks);
6962 -}
6963 -
6964 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
6965 - yaffs_BlockInfo **blockUsedPtr)
6966 -{
6967 - int retVal;
6968 - yaffs_BlockInfo *bi;
6969 -
6970 - if (dev->allocationBlock < 0) {
6971 - /* Get next block to allocate off */
6972 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
6973 - dev->allocationPage = 0;
6974 - }
6975 -
6976 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
6977 - /* Not enough space to allocate unless we're allowed to use the reserve. */
6978 - return -1;
6979 - }
6980 -
6981 - if (dev->nErasedBlocks < dev->nReservedBlocks
6982 - && dev->allocationPage == 0) {
6983 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
6984 - }
6985 -
6986 - /* Next page please.... */
6987 - if (dev->allocationBlock >= 0) {
6988 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
6989 -
6990 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
6991 - dev->allocationPage;
6992 - bi->pagesInUse++;
6993 - yaffs_SetChunkBit(dev, dev->allocationBlock,
6994 - dev->allocationPage);
6995 -
6996 - dev->allocationPage++;
6997 -
6998 - dev->nFreeChunks--;
6999 -
7000 - /* If the block is full set the state to full */
7001 - if (dev->allocationPage >= dev->nChunksPerBlock) {
7002 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
7003 - dev->allocationBlock = -1;
7004 - }
7005 -
7006 - if (blockUsedPtr)
7007 - *blockUsedPtr = bi;
7008 -
7009 - return retVal;
7010 - }
7011 -
7012 - T(YAFFS_TRACE_ERROR,
7013 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
7014 -
7015 - return -1;
7016 -}
7017 -
7018 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
7019 -{
7020 - int n;
7021 -
7022 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
7023 -
7024 - if (dev->allocationBlock > 0)
7025 - n += (dev->nChunksPerBlock - dev->allocationPage);
7026 -
7027 - return n;
7028 -
7029 -}
7030 -
7031 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
7032 - int wholeBlock)
7033 -{
7034 - int oldChunk;
7035 - int newChunk;
7036 - int markNAND;
7037 - int retVal = YAFFS_OK;
7038 - int cleanups = 0;
7039 - int i;
7040 - int isCheckpointBlock;
7041 - int matchingChunk;
7042 - int maxCopies;
7043 -
7044 - int chunksBefore = yaffs_GetErasedChunks(dev);
7045 - int chunksAfter;
7046 -
7047 - yaffs_ExtendedTags tags;
7048 -
7049 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
7050 -
7051 - yaffs_Object *object;
7052 -
7053 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
7054 -
7055 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
7056 -
7057 - T(YAFFS_TRACE_TRACING,
7058 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
7059 - block,
7060 - bi->pagesInUse,
7061 - bi->hasShrinkHeader,
7062 - wholeBlock));
7063 -
7064 - /*yaffs_VerifyFreeChunks(dev); */
7065 -
7066 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
7067 -
7068 - /* Take off the number of soft deleted entries because
7069 - * they're going to get really deleted during GC.
7070 - */
7071 - dev->nFreeChunks -= bi->softDeletions;
7072 -
7073 - dev->isDoingGC = 1;
7074 -
7075 - if (isCheckpointBlock ||
7076 - !yaffs_StillSomeChunkBits(dev, block)) {
7077 - T(YAFFS_TRACE_TRACING,
7078 - (TSTR
7079 - ("Collecting block %d that has no chunks in use" TENDSTR),
7080 - block));
7081 - yaffs_BlockBecameDirty(dev, block);
7082 - } else {
7083 -
7084 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
7085 -
7086 - yaffs_VerifyBlock(dev, bi, block);
7087 -
7088 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
7089 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
7090 -
7091 - for (/* init already done */;
7092 - retVal == YAFFS_OK &&
7093 - dev->gcChunk < dev->nChunksPerBlock &&
7094 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
7095 - maxCopies > 0;
7096 - dev->gcChunk++, oldChunk++) {
7097 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
7098 -
7099 - /* This page is in use and might need to be copied off */
7100 -
7101 - maxCopies--;
7102 -
7103 - markNAND = 1;
7104 -
7105 - yaffs_InitialiseTags(&tags);
7106 -
7107 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
7108 - buffer, &tags);
7109 -
7110 - object =
7111 - yaffs_FindObjectByNumber(dev,
7112 - tags.objectId);
7113 -
7114 - T(YAFFS_TRACE_GC_DETAIL,
7115 - (TSTR
7116 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
7117 - dev->gcChunk, tags.objectId, tags.chunkId,
7118 - tags.byteCount));
7119 -
7120 - if (object && !yaffs_SkipVerification(dev)) {
7121 - if (tags.chunkId == 0)
7122 - matchingChunk = object->hdrChunk;
7123 - else if (object->softDeleted)
7124 - matchingChunk = oldChunk; /* Defeat the test */
7125 - else
7126 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
7127 -
7128 - if (oldChunk != matchingChunk)
7129 - T(YAFFS_TRACE_ERROR,
7130 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
7131 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
7132 -
7133 - }
7134 -
7135 - if (!object) {
7136 - T(YAFFS_TRACE_ERROR,
7137 - (TSTR
7138 - ("page %d in gc has no object: %d %d %d "
7139 - TENDSTR), oldChunk,
7140 - tags.objectId, tags.chunkId, tags.byteCount));
7141 - }
7142 -
7143 - if (object &&
7144 - object->deleted &&
7145 - object->softDeleted &&
7146 - tags.chunkId != 0) {
7147 - /* Data chunk in a soft deleted file, throw it away
7148 - * It's a soft deleted data chunk,
7149 - * No need to copy this, just forget about it and
7150 - * fix up the object.
7151 - */
7152 -
7153 - object->nDataChunks--;
7154 -
7155 - if (object->nDataChunks <= 0) {
7156 - /* remeber to clean up the object */
7157 - dev->gcCleanupList[cleanups] =
7158 - tags.objectId;
7159 - cleanups++;
7160 - }
7161 - markNAND = 0;
7162 - } else if (0) {
7163 - /* Todo object && object->deleted && object->nDataChunks == 0 */
7164 - /* Deleted object header with no data chunks.
7165 - * Can be discarded and the file deleted.
7166 - */
7167 - object->hdrChunk = 0;
7168 - yaffs_FreeTnode(object->myDev,
7169 - object->variant.
7170 - fileVariant.top);
7171 - object->variant.fileVariant.top = NULL;
7172 - yaffs_DoGenericObjectDeletion(object);
7173 -
7174 - } else if (object) {
7175 - /* It's either a data chunk in a live file or
7176 - * an ObjectHeader, so we're interested in it.
7177 - * NB Need to keep the ObjectHeaders of deleted files
7178 - * until the whole file has been deleted off
7179 - */
7180 - tags.serialNumber++;
7181 -
7182 - dev->nGCCopies++;
7183 -
7184 - if (tags.chunkId == 0) {
7185 - /* It is an object Id,
7186 - * We need to nuke the shrinkheader flags first
7187 - * We no longer want the shrinkHeader flag since its work is done
7188 - * and if it is left in place it will mess up scanning.
7189 - */
7190 -
7191 - yaffs_ObjectHeader *oh;
7192 - oh = (yaffs_ObjectHeader *)buffer;
7193 - oh->isShrink = 0;
7194 - tags.extraIsShrinkHeader = 0;
7195 -
7196 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
7197 - }
7198 -
7199 - newChunk =
7200 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
7201 -
7202 - if (newChunk < 0) {
7203 - retVal = YAFFS_FAIL;
7204 - } else {
7205 -
7206 - /* Ok, now fix up the Tnodes etc. */
7207 -
7208 - if (tags.chunkId == 0) {
7209 - /* It's a header */
7210 - object->hdrChunk = newChunk;
7211 - object->serial = tags.serialNumber;
7212 - } else {
7213 - /* It's a data chunk */
7214 - yaffs_PutChunkIntoFile
7215 - (object,
7216 - tags.chunkId,
7217 - newChunk, 0);
7218 - }
7219 - }
7220 - }
7221 -
7222 - if (retVal == YAFFS_OK)
7223 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
7224 -
7225 - }
7226 - }
7227 -
7228 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
7229 -
7230 -
7231 - /* Do any required cleanups */
7232 - for (i = 0; i < cleanups; i++) {
7233 - /* Time to delete the file too */
7234 - object =
7235 - yaffs_FindObjectByNumber(dev,
7236 - dev->gcCleanupList[i]);
7237 - if (object) {
7238 - yaffs_FreeTnode(dev,
7239 - object->variant.fileVariant.
7240 - top);
7241 - object->variant.fileVariant.top = NULL;
7242 - T(YAFFS_TRACE_GC,
7243 - (TSTR
7244 - ("yaffs: About to finally delete object %d"
7245 - TENDSTR), object->objectId));
7246 - yaffs_DoGenericObjectDeletion(object);
7247 - object->myDev->nDeletedFiles--;
7248 - }
7249 -
7250 - }
7251 -
7252 - }
7253 -
7254 - yaffs_VerifyCollectedBlock(dev, bi, block);
7255 + if (chunkId > YAFFS_MAX_CHUNK_ID)
7256 + return NULL;
7257
7258 - chunksAfter = yaffs_GetErasedChunks(dev);
7259 - if (chunksBefore >= chunksAfter) {
7260 - T(YAFFS_TRACE_GC,
7261 - (TSTR
7262 - ("gc did not increase free chunks before %d after %d"
7263 - TENDSTR), chunksBefore, chunksAfter));
7264 - }
7265 + /* First check we're tall enough (ie enough topLevel) */
7266
7267 - /* If the gc completed then clear the current gcBlock so that we find another. */
7268 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
7269 - dev->gcBlock = -1;
7270 - dev->gcChunk = 0;
7271 + x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
7272 + requiredTallness = 0;
7273 + while (x) {
7274 + x >>= YAFFS_TNODES_INTERNAL_BITS;
7275 + requiredTallness++;
7276 }
7277
7278 - dev->isDoingGC = 0;
7279 -
7280 - return retVal;
7281 -}
7282
7283 -/* New garbage collector
7284 - * If we're very low on erased blocks then we do aggressive garbage collection
7285 - * otherwise we do "leasurely" garbage collection.
7286 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
7287 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
7288 - *
7289 - * The idea is to help clear out space in a more spread-out manner.
7290 - * Dunno if it really does anything useful.
7291 - */
7292 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
7293 -{
7294 - int block;
7295 - int aggressive;
7296 - int gcOk = YAFFS_OK;
7297 - int maxTries = 0;
7298 + if (requiredTallness > fStruct->topLevel) {
7299 + /* Not tall enough, gotta make the tree taller */
7300 + for (i = fStruct->topLevel; i < requiredTallness; i++) {
7301
7302 - int checkpointBlockAdjust;
7303 + tn = yaffs_GetTnode(dev);
7304
7305 - if (dev->isDoingGC) {
7306 - /* Bail out so we don't get recursive gc */
7307 - return YAFFS_OK;
7308 + if (tn) {
7309 + tn->internal[0] = fStruct->top;
7310 + fStruct->top = tn;
7311 + fStruct->topLevel++;
7312 + } else {
7313 + T(YAFFS_TRACE_ERROR,
7314 + (TSTR("yaffs: no more tnodes" TENDSTR)));
7315 + return NULL;
7316 + }
7317 + }
7318 }
7319
7320 - /* This loop should pass the first time.
7321 - * We'll only see looping here if the erase of the collected block fails.
7322 - */
7323 -
7324 - do {
7325 - maxTries++;
7326 -
7327 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
7328 - if (checkpointBlockAdjust < 0)
7329 - checkpointBlockAdjust = 0;
7330 + /* Traverse down to level 0, adding anything we need */
7331
7332 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
7333 - /* We need a block soon...*/
7334 - aggressive = 1;
7335 - } else {
7336 - /* We're in no hurry */
7337 - aggressive = 0;
7338 - }
7339 + l = fStruct->topLevel;
7340 + tn = fStruct->top;
7341
7342 - if (dev->gcBlock <= 0) {
7343 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
7344 - dev->gcChunk = 0;
7345 - }
7346 + if (l > 0) {
7347 + while (l > 0 && tn) {
7348 + x = (chunkId >>
7349 + (YAFFS_TNODES_LEVEL0_BITS +
7350 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
7351 + YAFFS_TNODES_INTERNAL_MASK;
7352
7353 - block = dev->gcBlock;
7354
7355 - if (block > 0) {
7356 - dev->garbageCollections++;
7357 - if (!aggressive)
7358 - dev->passiveGarbageCollections++;
7359 + if ((l > 1) && !tn->internal[x]) {
7360 + /* Add missing non-level-zero tnode */
7361 + tn->internal[x] = yaffs_GetTnode(dev);
7362 + if(!tn->internal[x])
7363 + return NULL;
7364 + } else if (l == 1) {
7365 + /* Looking from level 1 at level 0 */
7366 + if (passedTn) {
7367 + /* If we already have one, then release it.*/
7368 + if (tn->internal[x])
7369 + yaffs_FreeTnode(dev, tn->internal[x]);
7370 + tn->internal[x] = passedTn;
7371
7372 - T(YAFFS_TRACE_GC,
7373 - (TSTR
7374 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
7375 - dev->nErasedBlocks, aggressive));
7376 + } else if (!tn->internal[x]) {
7377 + /* Don't have one, none passed in */
7378 + tn->internal[x] = yaffs_GetTnode(dev);
7379 + if(!tn->internal[x])
7380 + return NULL;
7381 + }
7382 + }
7383
7384 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
7385 + tn = tn->internal[x];
7386 + l--;
7387 }
7388 -
7389 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
7390 - T(YAFFS_TRACE_GC,
7391 - (TSTR
7392 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
7393 - TENDSTR), dev->nErasedBlocks, maxTries, block));
7394 + } else {
7395 + /* top is level 0 */
7396 + if (passedTn) {
7397 + memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
7398 + yaffs_FreeTnode(dev, passedTn);
7399 }
7400 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
7401 - (block > 0) &&
7402 - (maxTries < 2));
7403 + }
7404
7405 - return aggressive ? gcOk : YAFFS_OK;
7406 + return tn;
7407 }
7408
7409 -/*------------------------- TAGS --------------------------------*/
7410 -
7411 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
7412 - int chunkInObject)
7413 +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
7414 + yaffs_ExtendedTags *tags, int objectId,
7415 + int chunkInInode)
7416 {
7417 - return (tags->chunkId == chunkInObject &&
7418 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
7419 + int j;
7420
7421 + for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
7422 + if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock,
7423 + theChunk % dev->param.nChunksPerBlock)) {
7424 +
7425 + if(dev->chunkGroupSize == 1)
7426 + return theChunk;
7427 + else {
7428 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
7429 + tags);
7430 + if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
7431 + /* found it; */
7432 + return theChunk;
7433 + }
7434 + }
7435 + }
7436 + theChunk++;
7437 + }
7438 + return -1;
7439 }
7440
7441 +#if 0
7442 +/* Experimental code not being used yet. Might speed up file deletion */
7443 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
7444 + * chunks and tnodes in the file.
7445 + * Returns 1 if the tree was deleted.
7446 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
7447 + */
7448
7449 -/*-------------------- Data file manipulation -----------------*/
7450 -
7451 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
7452 - yaffs_ExtendedTags *tags)
7453 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
7454 + int chunkOffset, int *limit)
7455 {
7456 - /*Get the Tnode, then get the level 0 offset chunk offset */
7457 - yaffs_Tnode *tn;
7458 - int theChunk = -1;
7459 - yaffs_ExtendedTags localTags;
7460 - int retVal = -1;
7461 -
7462 + int i;
7463 + int chunkInInode;
7464 + int theChunk;
7465 + yaffs_ExtendedTags tags;
7466 + int foundChunk;
7467 yaffs_Device *dev = in->myDev;
7468
7469 - if (!tags) {
7470 - /* Passed a NULL, so use our own tags space */
7471 - tags = &localTags;
7472 - }
7473 -
7474 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7475 + int allDone = 1;
7476
7477 if (tn) {
7478 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7479 + if (level > 0) {
7480 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7481 + i--) {
7482 + if (tn->internal[i]) {
7483 + if (limit && (*limit) < 0) {
7484 + allDone = 0;
7485 + } else {
7486 + allDone =
7487 + yaffs_DeleteWorker(in,
7488 + tn->
7489 + internal
7490 + [i],
7491 + level -
7492 + 1,
7493 + (chunkOffset
7494 + <<
7495 + YAFFS_TNODES_INTERNAL_BITS)
7496 + + i,
7497 + limit);
7498 + }
7499 + if (allDone) {
7500 + yaffs_FreeTnode(dev,
7501 + tn->
7502 + internal[i]);
7503 + tn->internal[i] = NULL;
7504 + }
7505 + }
7506 + }
7507 + return (allDone) ? 1 : 0;
7508 + } else if (level == 0) {
7509 + int hitLimit = 0;
7510
7511 - retVal =
7512 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7513 - chunkInInode);
7514 - }
7515 - return retVal;
7516 -}
7517 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
7518 + i--) {
7519 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7520 + if (theChunk) {
7521
7522 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
7523 - yaffs_ExtendedTags *tags)
7524 -{
7525 - /* Get the Tnode, then get the level 0 offset chunk offset */
7526 - yaffs_Tnode *tn;
7527 - int theChunk = -1;
7528 - yaffs_ExtendedTags localTags;
7529 + chunkInInode = (chunkOffset <<
7530 + YAFFS_TNODES_LEVEL0_BITS) + i;
7531 +
7532 + foundChunk =
7533 + yaffs_FindChunkInGroup(dev,
7534 + theChunk,
7535 + &tags,
7536 + in->objectId,
7537 + chunkInInode);
7538 +
7539 + if (foundChunk > 0) {
7540 + yaffs_DeleteChunk(dev,
7541 + foundChunk, 1,
7542 + __LINE__);
7543 + in->nDataChunks--;
7544 + if (limit) {
7545 + *limit = *limit - 1;
7546 + if (*limit <= 0)
7547 + hitLimit = 1;
7548 + }
7549
7550 - yaffs_Device *dev = in->myDev;
7551 - int retVal = -1;
7552 + }
7553 +
7554 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7555 + }
7556 +
7557 + }
7558 + return (i < 0) ? 1 : 0;
7559 +
7560 + }
7561
7562 - if (!tags) {
7563 - /* Passed a NULL, so use our own tags space */
7564 - tags = &localTags;
7565 }
7566
7567 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
7568 + return 1;
7569
7570 - if (tn) {
7571 +}
7572
7573 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7574 +#endif
7575
7576 - retVal =
7577 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
7578 - chunkInInode);
7579 +static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
7580 +{
7581 + yaffs_BlockInfo *theBlock;
7582 + unsigned blockNo;
7583
7584 - /* Delete the entry in the filestructure (if found) */
7585 - if (retVal != -1)
7586 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
7587 - }
7588 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
7589
7590 - return retVal;
7591 + blockNo = chunk / dev->param.nChunksPerBlock;
7592 + theBlock = yaffs_GetBlockInfo(dev, blockNo);
7593 + if (theBlock) {
7594 + theBlock->softDeletions++;
7595 + dev->nFreeChunks++;
7596 + yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock);
7597 + }
7598 }
7599
7600 -#ifdef YAFFS_PARANOID
7601 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
7602 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
7603 + * of the tnode.
7604 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
7605 + */
7606
7607 -static int yaffs_CheckFileSanity(yaffs_Object *in)
7608 +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
7609 + __u32 level, int chunkOffset)
7610 {
7611 - int chunk;
7612 - int nChunks;
7613 - int fSize;
7614 - int failed = 0;
7615 - int objId;
7616 - yaffs_Tnode *tn;
7617 - yaffs_Tags localTags;
7618 - yaffs_Tags *tags = &localTags;
7619 + int i;
7620 int theChunk;
7621 - int chunkDeleted;
7622 + int allDone = 1;
7623 + yaffs_Device *dev = in->myDev;
7624
7625 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
7626 - return YAFFS_FAIL;
7627 + if (tn) {
7628 + if (level > 0) {
7629
7630 - objId = in->objectId;
7631 - fSize = in->variant.fileVariant.fileSize;
7632 - nChunks =
7633 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
7634 -
7635 - for (chunk = 1; chunk <= nChunks; chunk++) {
7636 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
7637 - chunk);
7638 -
7639 - if (tn) {
7640 -
7641 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
7642 -
7643 - if (yaffs_CheckChunkBits
7644 - (dev, theChunk / dev->nChunksPerBlock,
7645 - theChunk % dev->nChunksPerBlock)) {
7646 -
7647 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
7648 - tags,
7649 - &chunkDeleted);
7650 - if (yaffs_TagsMatch
7651 - (tags, in->objectId, chunk, chunkDeleted)) {
7652 - /* found it; */
7653 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
7654 + i--) {
7655 + if (tn->internal[i]) {
7656 + allDone =
7657 + yaffs_SoftDeleteWorker(in,
7658 + tn->
7659 + internal[i],
7660 + level - 1,
7661 + (chunkOffset
7662 + <<
7663 + YAFFS_TNODES_INTERNAL_BITS)
7664 + + i);
7665 + if (allDone) {
7666 + yaffs_FreeTnode(dev,
7667 + tn->
7668 + internal[i]);
7669 + tn->internal[i] = NULL;
7670 + } else {
7671 + /* Hoosterman... how could this happen? */
7672 + }
7673 + }
7674 + }
7675 + return (allDone) ? 1 : 0;
7676 + } else if (level == 0) {
7677
7678 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
7679 + theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
7680 + if (theChunk) {
7681 + /* Note this does not find the real chunk, only the chunk group.
7682 + * We make an assumption that a chunk group is not larger than
7683 + * a block.
7684 + */
7685 + yaffs_SoftDeleteChunk(dev, theChunk);
7686 + yaffs_LoadLevel0Tnode(dev, tn, i, 0);
7687 }
7688 - } else {
7689
7690 - failed = 1;
7691 }
7692 + return 1;
7693
7694 - } else {
7695 - /* T(("No level 0 found for %d\n", chunk)); */
7696 }
7697 +
7698 }
7699
7700 - return failed ? YAFFS_FAIL : YAFFS_OK;
7701 + return 1;
7702 +
7703 }
7704
7705 -#endif
7706 +static void yaffs_SoftDeleteFile(yaffs_Object *obj)
7707 +{
7708 + if (obj->deleted &&
7709 + obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
7710 + if (obj->nDataChunks <= 0) {
7711 + /* Empty file with no duplicate object headers, just delete it immediately */
7712 + yaffs_FreeTnode(obj->myDev,
7713 + obj->variant.fileVariant.top);
7714 + obj->variant.fileVariant.top = NULL;
7715 + T(YAFFS_TRACE_TRACING,
7716 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
7717 + obj->objectId));
7718 + yaffs_DoGenericObjectDeletion(obj);
7719 + } else {
7720 + yaffs_SoftDeleteWorker(obj,
7721 + obj->variant.fileVariant.top,
7722 + obj->variant.fileVariant.
7723 + topLevel, 0);
7724 + obj->softDeleted = 1;
7725 + }
7726 + }
7727 +}
7728
7729 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
7730 - int chunkInNAND, int inScan)
7731 +/* Pruning removes any part of the file structure tree that is beyond the
7732 + * bounds of the file (ie that does not point to chunks).
7733 + *
7734 + * A file should only get pruned when its size is reduced.
7735 + *
7736 + * Before pruning, the chunks must be pulled from the tree and the
7737 + * level 0 tnode entries must be zeroed out.
7738 + * Could also use this for file deletion, but that's probably better handled
7739 + * by a special case.
7740 + *
7741 + * This function is recursive. For levels > 0 the function is called again on
7742 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
7743 + * If there is no data in a subtree then it is pruned.
7744 + */
7745 +
7746 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7747 + __u32 level, int del0)
7748 {
7749 - /* NB inScan is zero unless scanning.
7750 - * For forward scanning, inScan is > 0;
7751 - * for backward scanning inScan is < 0
7752 - */
7753 + int i;
7754 + int hasData;
7755
7756 - yaffs_Tnode *tn;
7757 - yaffs_Device *dev = in->myDev;
7758 - int existingChunk;
7759 - yaffs_ExtendedTags existingTags;
7760 - yaffs_ExtendedTags newTags;
7761 - unsigned existingSerial, newSerial;
7762 + if (tn) {
7763 + hasData = 0;
7764
7765 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
7766 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
7767 - * If it is not during Scanning then something went wrong!
7768 - */
7769 - if (!inScan) {
7770 - T(YAFFS_TRACE_ERROR,
7771 - (TSTR
7772 - ("yaffs tragedy:attempt to put data chunk into a non-file"
7773 - TENDSTR)));
7774 - YBUG();
7775 - }
7776 + if(level > 0){
7777 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7778 + if (tn->internal[i]) {
7779 + tn->internal[i] =
7780 + yaffs_PruneWorker(dev, tn->internal[i],
7781 + level - 1,
7782 + (i == 0) ? del0 : 1);
7783 + }
7784
7785 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
7786 - return YAFFS_OK;
7787 - }
7788 + if (tn->internal[i])
7789 + hasData++;
7790 + }
7791 + } else {
7792 + int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32);
7793 + __u32 *map = (__u32 *)tn;
7794
7795 - tn = yaffs_AddOrFindLevel0Tnode(dev,
7796 - &in->variant.fileVariant,
7797 - chunkInInode,
7798 - NULL);
7799 - if (!tn)
7800 - return YAFFS_FAIL;
7801 + for(i = 0; !hasData && i < tnodeSize_u32; i++){
7802 + if(map[i])
7803 + hasData++;
7804 + }
7805 + }
7806
7807 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
7808 + if (hasData == 0 && del0) {
7809 + /* Free and return NULL */
7810
7811 - if (inScan != 0) {
7812 - /* If we're scanning then we need to test for duplicates
7813 - * NB This does not need to be efficient since it should only ever
7814 - * happen when the power fails during a write, then only one
7815 - * chunk should ever be affected.
7816 - *
7817 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
7818 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
7819 - */
7820 + yaffs_FreeTnode(dev, tn);
7821 + tn = NULL;
7822 + }
7823
7824 - if (existingChunk > 0) {
7825 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
7826 - * thus we have to do a FindChunkInFile to get the real chunk id.
7827 - *
7828 - * We have a duplicate now we need to decide which one to use:
7829 - *
7830 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
7831 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
7832 - * YAFFS1: Get both sets of tags and compare serial numbers.
7833 - */
7834 + }
7835
7836 - if (inScan > 0) {
7837 - /* Only do this for forward scanning */
7838 - yaffs_ReadChunkWithTagsFromNAND(dev,
7839 - chunkInNAND,
7840 - NULL, &newTags);
7841 + return tn;
7842
7843 - /* Do a proper find */
7844 - existingChunk =
7845 - yaffs_FindChunkInFile(in, chunkInInode,
7846 - &existingTags);
7847 - }
7848 +}
7849
7850 - if (existingChunk <= 0) {
7851 - /*Hoosterman - how did this happen? */
7852 +static int yaffs_PruneFileStructure(yaffs_Device *dev,
7853 + yaffs_FileStructure *fStruct)
7854 +{
7855 + int i;
7856 + int hasData;
7857 + int done = 0;
7858 + yaffs_Tnode *tn;
7859
7860 - T(YAFFS_TRACE_ERROR,
7861 - (TSTR
7862 - ("yaffs tragedy: existing chunk < 0 in scan"
7863 - TENDSTR)));
7864 + if (fStruct->topLevel > 0) {
7865 + fStruct->top =
7866 + yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7867
7868 - }
7869 + /* Now we have a tree with all the non-zero branches NULL but the height
7870 + * is the same as it was.
7871 + * Let's see if we can trim internal tnodes to shorten the tree.
7872 + * We can do this if only the 0th element in the tnode is in use
7873 + * (ie all the non-zero are NULL)
7874 + */
7875
7876 - /* NB The deleted flags should be false, otherwise the chunks will
7877 - * not be loaded during a scan
7878 - */
7879 + while (fStruct->topLevel && !done) {
7880 + tn = fStruct->top;
7881
7882 - if (inScan > 0) {
7883 - newSerial = newTags.serialNumber;
7884 - existingSerial = existingTags.serialNumber;
7885 + hasData = 0;
7886 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7887 + if (tn->internal[i])
7888 + hasData++;
7889 }
7890 -
7891 - if ((inScan > 0) &&
7892 - (in->myDev->isYaffs2 ||
7893 - existingChunk <= 0 ||
7894 - ((existingSerial + 1) & 3) == newSerial)) {
7895 - /* Forward scanning.
7896 - * Use new
7897 - * Delete the old one and drop through to update the tnode
7898 - */
7899 - yaffs_DeleteChunk(dev, existingChunk, 1,
7900 - __LINE__);
7901 - } else {
7902 - /* Backward scanning or we want to use the existing one
7903 - * Use existing.
7904 - * Delete the new one and return early so that the tnode isn't changed
7905 - */
7906 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
7907 - __LINE__);
7908 - return YAFFS_OK;
7909 +
7910 + if (!hasData) {
7911 + fStruct->top = tn->internal[0];
7912 + fStruct->topLevel--;
7913 + yaffs_FreeTnode(dev, tn);
7914 + } else {
7915 + done = 1;
7916 }
7917 }
7918 -
7919 }
7920
7921 - if (existingChunk == 0)
7922 - in->nDataChunks++;
7923 -
7924 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
7925 -
7926 return YAFFS_OK;
7927 }
7928
7929 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
7930 - __u8 *buffer)
7931 -{
7932 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
7933 -
7934 - if (chunkInNAND >= 0)
7935 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
7936 - buffer, NULL);
7937 - else {
7938 - T(YAFFS_TRACE_NANDACCESS,
7939 - (TSTR("Chunk %d not found zero instead" TENDSTR),
7940 - chunkInNAND));
7941 - /* get sane (zero) data if you read a hole */
7942 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
7943 - return 0;
7944 - }
7945 +/*-------------------- End of File Structure functions.-------------------*/
7946
7947 -}
7948
7949 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
7950 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7951 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7952 {
7953 - int block;
7954 - int page;
7955 - yaffs_ExtendedTags tags;
7956 - yaffs_BlockInfo *bi;
7957 + yaffs_Object *obj = yaffs_AllocateRawObject(dev);
7958
7959 - if (chunkId <= 0)
7960 - return;
7961 + if (obj) {
7962 + dev->nObjects++;
7963
7964 - dev->nDeletions++;
7965 - block = chunkId / dev->nChunksPerBlock;
7966 - page = chunkId % dev->nChunksPerBlock;
7967 + /* Now sweeten it up... */
7968
7969 + memset(obj, 0, sizeof(yaffs_Object));
7970 + obj->beingCreated = 1;
7971
7972 - if (!yaffs_CheckChunkBit(dev, block, page))
7973 - T(YAFFS_TRACE_VERIFY,
7974 - (TSTR("Deleting invalid chunk %d"TENDSTR),
7975 - chunkId));
7976 + obj->myDev = dev;
7977 + obj->hdrChunk = 0;
7978 + obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7979 + YINIT_LIST_HEAD(&(obj->hardLinks));
7980 + YINIT_LIST_HEAD(&(obj->hashLink));
7981 + YINIT_LIST_HEAD(&obj->siblings);
7982
7983 - bi = yaffs_GetBlockInfo(dev, block);
7984
7985 - T(YAFFS_TRACE_DELETION,
7986 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
7987 + /* Now make the directory sane */
7988 + if (dev->rootDir) {
7989 + obj->parent = dev->rootDir;
7990 + ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children);
7991 + }
7992
7993 - if (markNAND &&
7994 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
7995 + /* Add it to the lost and found directory.
7996 + * NB Can't put root or lostNFound in lostNFound so
7997 + * check if lostNFound exists first
7998 + */
7999 + if (dev->lostNFoundDir)
8000 + yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj);
8001
8002 - yaffs_InitialiseTags(&tags);
8003 + obj->beingCreated = 0;
8004 + }
8005
8006 - tags.chunkDeleted = 1;
8007 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
8008
8009 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
8010 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
8011 - } else {
8012 - dev->nUnmarkedDeletions++;
8013 - }
8014 + return obj;
8015 +}
8016
8017 - /* Pull out of the management area.
8018 - * If the whole block became dirty, this will kick off an erasure.
8019 - */
8020 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8021 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8022 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8023 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8024 - dev->nFreeChunks++;
8025 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
8026 + __u32 mode)
8027 +{
8028
8029 - yaffs_ClearChunkBit(dev, block, page);
8030 + yaffs_Object *obj =
8031 + yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
8032 + if (obj) {
8033 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
8034 + obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
8035 + obj->unlinkAllowed = 0; /* ... or unlink it */
8036 + obj->deleted = 0;
8037 + obj->unlinked = 0;
8038 + obj->yst_mode = mode;
8039 + obj->myDev = dev;
8040 + obj->hdrChunk = 0; /* Not a valid chunk. */
8041 + }
8042
8043 - bi->pagesInUse--;
8044 + return obj;
8045
8046 - if (bi->pagesInUse == 0 &&
8047 - !bi->hasShrinkHeader &&
8048 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8049 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8050 - yaffs_BlockBecameDirty(dev, block);
8051 - }
8052 +}
8053
8054 - }
8055 +static void yaffs_UnhashObject(yaffs_Object *obj)
8056 +{
8057 + int bucket;
8058 + yaffs_Device *dev = obj->myDev;
8059
8060 + /* If it is still linked into the bucket list, free from the list */
8061 + if (!ylist_empty(&obj->hashLink)) {
8062 + ylist_del_init(&obj->hashLink);
8063 + bucket = yaffs_HashFunction(obj->objectId);
8064 + dev->objectBucket[bucket].count--;
8065 + }
8066 }
8067
8068 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8069 - const __u8 *buffer, int nBytes,
8070 - int useReserve)
8071 +/* FreeObject frees up a Object and puts it back on the free list */
8072 +static void yaffs_FreeObject(yaffs_Object *obj)
8073 {
8074 - /* Find old chunk Need to do this to get serial number
8075 - * Write new one and patch into tree.
8076 - * Invalidate old tags.
8077 - */
8078 + yaffs_Device *dev = obj->myDev;
8079
8080 - int prevChunkId;
8081 - yaffs_ExtendedTags prevTags;
8082 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode));
8083
8084 - int newChunkId;
8085 - yaffs_ExtendedTags newTags;
8086 + if (!obj)
8087 + YBUG();
8088 + if (obj->parent)
8089 + YBUG();
8090 + if (!ylist_empty(&obj->siblings))
8091 + YBUG();
8092
8093 - yaffs_Device *dev = in->myDev;
8094
8095 - yaffs_CheckGarbageCollection(dev);
8096 + if (obj->myInode) {
8097 + /* We're still hooked up to a cached inode.
8098 + * Don't delete now, but mark for later deletion
8099 + */
8100 + obj->deferedFree = 1;
8101 + return;
8102 + }
8103 +
8104 + yaffs_UnhashObject(obj);
8105
8106 - /* Get the previous chunk at this location in the file if it exists */
8107 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8108 + yaffs_FreeRawObject(dev,obj);
8109 + dev->nObjects--;
8110 + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
8111 +}
8112
8113 - /* Set up new tags */
8114 - yaffs_InitialiseTags(&newTags);
8115
8116 - newTags.chunkId = chunkInInode;
8117 - newTags.objectId = in->objectId;
8118 - newTags.serialNumber =
8119 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8120 - newTags.byteCount = nBytes;
8121 +void yaffs_HandleDeferedFree(yaffs_Object *obj)
8122 +{
8123 + if (obj->deferedFree)
8124 + yaffs_FreeObject(obj);
8125 +}
8126
8127 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8128 - T(YAFFS_TRACE_ERROR,
8129 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8130 - YBUG();
8131 +static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev)
8132 +{
8133 + int i;
8134 +
8135 + dev->nObjects = 0;
8136 + dev->nTnodes = 0;
8137 +
8138 + yaffs_InitialiseRawTnodesAndObjects(dev);
8139 +
8140 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
8141 + YINIT_LIST_HEAD(&dev->objectBucket[i].list);
8142 + dev->objectBucket[i].count = 0;
8143 }
8144 +}
8145
8146 - newChunkId =
8147 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8148 - useReserve);
8149 +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
8150 +{
8151 + int i;
8152 + int l = 999;
8153 + int lowest = 999999;
8154
8155 - if (newChunkId >= 0) {
8156 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8157
8158 - if (prevChunkId >= 0)
8159 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8160 + /* Search for the shortest list or one that
8161 + * isn't too long.
8162 + */
8163 +
8164 + for (i = 0; i < 10 && lowest > 4; i++) {
8165 + dev->bucketFinder++;
8166 + dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS;
8167 + if (dev->objectBucket[dev->bucketFinder].count < lowest) {
8168 + lowest = dev->objectBucket[dev->bucketFinder].count;
8169 + l = dev->bucketFinder;
8170 + }
8171
8172 - yaffs_CheckFileSanity(in);
8173 }
8174 - return newChunkId;
8175
8176 + return l;
8177 }
8178
8179 -/* UpdateObjectHeader updates the header on NAND for an object.
8180 - * If name is not NULL, then that new name is used.
8181 - */
8182 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8183 - int isShrink, int shadows)
8184 +static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
8185 {
8186 + int bucket = yaffs_FindNiceObjectBucket(dev);
8187
8188 - yaffs_BlockInfo *bi;
8189 + /* Now find an object value that has not already been taken
8190 + * by scanning the list.
8191 + */
8192
8193 - yaffs_Device *dev = in->myDev;
8194 + int found = 0;
8195 + struct ylist_head *i;
8196
8197 - int prevChunkId;
8198 - int retVal = 0;
8199 - int result = 0;
8200 + __u32 n = (__u32) bucket;
8201
8202 - int newChunkId;
8203 - yaffs_ExtendedTags newTags;
8204 - yaffs_ExtendedTags oldTags;
8205 + /* yaffs_CheckObjectHashSanity(); */
8206
8207 - __u8 *buffer = NULL;
8208 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8209 + while (!found) {
8210 + found = 1;
8211 + n += YAFFS_NOBJECT_BUCKETS;
8212 + if (1 || dev->objectBucket[bucket].count > 0) {
8213 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8214 + /* If there is already one in the list */
8215 + if (i && ylist_entry(i, yaffs_Object,
8216 + hashLink)->objectId == n) {
8217 + found = 0;
8218 + }
8219 + }
8220 + }
8221 + }
8222
8223 - yaffs_ObjectHeader *oh = NULL;
8224 + return n;
8225 +}
8226
8227 - yaffs_strcpy(oldName, _Y("silly old name"));
8228 +static void yaffs_HashObject(yaffs_Object *in)
8229 +{
8230 + int bucket = yaffs_HashFunction(in->objectId);
8231 + yaffs_Device *dev = in->myDev;
8232
8233 + ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
8234 + dev->objectBucket[bucket].count++;
8235 +}
8236
8237 - if (!in->fake ||
8238 - in == dev->rootDir || /* The rootDir should also be saved */
8239 - force) {
8240 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
8241 +{
8242 + int bucket = yaffs_HashFunction(number);
8243 + struct ylist_head *i;
8244 + yaffs_Object *in;
8245
8246 - yaffs_CheckGarbageCollection(dev);
8247 - yaffs_CheckObjectDetailsLoaded(in);
8248 + ylist_for_each(i, &dev->objectBucket[bucket].list) {
8249 + /* Look if it is in the list */
8250 + if (i) {
8251 + in = ylist_entry(i, yaffs_Object, hashLink);
8252 + if (in->objectId == number) {
8253
8254 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8255 - oh = (yaffs_ObjectHeader *) buffer;
8256 + /* Don't tell the VFS about this one if it is defered free */
8257 + if (in->deferedFree)
8258 + return NULL;
8259
8260 - prevChunkId = in->hdrChunk;
8261 + return in;
8262 + }
8263 + }
8264 + }
8265
8266 - if (prevChunkId > 0) {
8267 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8268 - buffer, &oldTags);
8269 + return NULL;
8270 +}
8271
8272 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8273 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
8274 + yaffs_ObjectType type)
8275 +{
8276 + yaffs_Object *theObject=NULL;
8277 + yaffs_Tnode *tn = NULL;
8278 +
8279 + if (number < 0)
8280 + number = yaffs_CreateNewObjectNumber(dev);
8281
8282 - memcpy(oldName, oh->name, sizeof(oh->name));
8283 - }
8284 + if (type == YAFFS_OBJECT_TYPE_FILE) {
8285 + tn = yaffs_GetTnode(dev);
8286 + if (!tn)
8287 + return NULL;
8288 + }
8289
8290 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8291 + theObject = yaffs_AllocateEmptyObject(dev);
8292 + if (!theObject){
8293 + if(tn)
8294 + yaffs_FreeTnode(dev,tn);
8295 + return NULL;
8296 + }
8297
8298 - oh->type = in->variantType;
8299 - oh->yst_mode = in->yst_mode;
8300 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8301
8302 + if (theObject) {
8303 + theObject->fake = 0;
8304 + theObject->renameAllowed = 1;
8305 + theObject->unlinkAllowed = 1;
8306 + theObject->objectId = number;
8307 + yaffs_HashObject(theObject);
8308 + theObject->variantType = type;
8309 #ifdef CONFIG_YAFFS_WINCE
8310 - oh->win_atime[0] = in->win_atime[0];
8311 - oh->win_ctime[0] = in->win_ctime[0];
8312 - oh->win_mtime[0] = in->win_mtime[0];
8313 - oh->win_atime[1] = in->win_atime[1];
8314 - oh->win_ctime[1] = in->win_ctime[1];
8315 - oh->win_mtime[1] = in->win_mtime[1];
8316 -#else
8317 - oh->yst_uid = in->yst_uid;
8318 - oh->yst_gid = in->yst_gid;
8319 - oh->yst_atime = in->yst_atime;
8320 - oh->yst_mtime = in->yst_mtime;
8321 - oh->yst_ctime = in->yst_ctime;
8322 - oh->yst_rdev = in->yst_rdev;
8323 -#endif
8324 - if (in->parent)
8325 - oh->parentObjectId = in->parent->objectId;
8326 - else
8327 - oh->parentObjectId = 0;
8328 -
8329 - if (name && *name) {
8330 - memset(oh->name, 0, sizeof(oh->name));
8331 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
8332 - } else if (prevChunkId >= 0)
8333 - memcpy(oh->name, oldName, sizeof(oh->name));
8334 - else
8335 - memset(oh->name, 0, sizeof(oh->name));
8336 + yfsd_WinFileTimeNow(theObject->win_atime);
8337 + theObject->win_ctime[0] = theObject->win_mtime[0] =
8338 + theObject->win_atime[0];
8339 + theObject->win_ctime[1] = theObject->win_mtime[1] =
8340 + theObject->win_atime[1];
8341
8342 - oh->isShrink = isShrink;
8343 +#else
8344
8345 - switch (in->variantType) {
8346 - case YAFFS_OBJECT_TYPE_UNKNOWN:
8347 - /* Should not happen */
8348 - break;
8349 + theObject->yst_atime = theObject->yst_mtime =
8350 + theObject->yst_ctime = Y_CURRENT_TIME;
8351 +#endif
8352 + switch (type) {
8353 case YAFFS_OBJECT_TYPE_FILE:
8354 - oh->fileSize =
8355 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
8356 - || oh->parentObjectId ==
8357 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
8358 - fileVariant.fileSize;
8359 - break;
8360 - case YAFFS_OBJECT_TYPE_HARDLINK:
8361 - oh->equivalentObjectId =
8362 - in->variant.hardLinkVariant.equivalentObjectId;
8363 - break;
8364 - case YAFFS_OBJECT_TYPE_SPECIAL:
8365 - /* Do nothing */
8366 + theObject->variant.fileVariant.fileSize = 0;
8367 + theObject->variant.fileVariant.scannedFileSize = 0;
8368 + theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
8369 + theObject->variant.fileVariant.topLevel = 0;
8370 + theObject->variant.fileVariant.top = tn;
8371 break;
8372 case YAFFS_OBJECT_TYPE_DIRECTORY:
8373 - /* Do nothing */
8374 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8375 + children);
8376 + YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
8377 + dirty);
8378 break;
8379 case YAFFS_OBJECT_TYPE_SYMLINK:
8380 - yaffs_strncpy(oh->alias,
8381 - in->variant.symLinkVariant.alias,
8382 - YAFFS_MAX_ALIAS_LENGTH);
8383 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
8384 + case YAFFS_OBJECT_TYPE_HARDLINK:
8385 + case YAFFS_OBJECT_TYPE_SPECIAL:
8386 + /* No action required */
8387 + break;
8388 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8389 + /* todo this should not happen */
8390 break;
8391 }
8392 + }
8393
8394 - /* Tags */
8395 - yaffs_InitialiseTags(&newTags);
8396 - in->serial++;
8397 - newTags.chunkId = 0;
8398 - newTags.objectId = in->objectId;
8399 - newTags.serialNumber = in->serial;
8400 -
8401 - /* Add extra info for file header */
8402 -
8403 - newTags.extraHeaderInfoAvailable = 1;
8404 - newTags.extraParentObjectId = oh->parentObjectId;
8405 - newTags.extraFileLength = oh->fileSize;
8406 - newTags.extraIsShrinkHeader = oh->isShrink;
8407 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
8408 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
8409 - newTags.extraObjectType = in->variantType;
8410 -
8411 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
8412 + return theObject;
8413 +}
8414
8415 - /* Create new chunk in NAND */
8416 - newChunkId =
8417 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8418 - (prevChunkId >= 0) ? 1 : 0);
8419 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
8420 + int number,
8421 + yaffs_ObjectType type)
8422 +{
8423 + yaffs_Object *theObject = NULL;
8424
8425 - if (newChunkId >= 0) {
8426 + if (number > 0)
8427 + theObject = yaffs_FindObjectByNumber(dev, number);
8428
8429 - in->hdrChunk = newChunkId;
8430 + if (!theObject)
8431 + theObject = yaffs_CreateNewObject(dev, number, type);
8432
8433 - if (prevChunkId >= 0) {
8434 - yaffs_DeleteChunk(dev, prevChunkId, 1,
8435 - __LINE__);
8436 - }
8437 + return theObject;
8438
8439 - if (!yaffs_ObjectHasCachedWriteData(in))
8440 - in->dirty = 0;
8441 +}
8442
8443 - /* If this was a shrink, then mark the block that the chunk lives on */
8444 - if (isShrink) {
8445 - bi = yaffs_GetBlockInfo(in->myDev,
8446 - newChunkId / in->myDev->nChunksPerBlock);
8447 - bi->hasShrinkHeader = 1;
8448 - }
8449
8450 - }
8451 +YCHAR *yaffs_CloneString(const YCHAR *str)
8452 +{
8453 + YCHAR *newStr = NULL;
8454 + int len;
8455
8456 - retVal = newChunkId;
8457 + if (!str)
8458 + str = _Y("");
8459
8460 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
8461 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
8462 + if (newStr){
8463 + yaffs_strncpy(newStr, str,len);
8464 + newStr[len] = 0;
8465 }
8466 + return newStr;
8467
8468 - if (buffer)
8469 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8470 -
8471 - return retVal;
8472 }
8473
8474 -/*------------------------ Short Operations Cache ----------------------------------------
8475 - * In many situations where there is no high level buffering (eg WinCE) a lot of
8476 - * reads might be short sequential reads, and a lot of writes may be short
8477 - * sequential writes. eg. scanning/writing a jpeg file.
8478 - * In these cases, a short read/write cache can provide a huge perfomance benefit
8479 - * with dumb-as-a-rock code.
8480 - * In Linux, the page cache provides read buffering aand the short op cache provides write
8481 - * buffering.
8482 - *
8483 - * There are a limited number (~10) of cache chunks per device so that we don't
8484 - * need a very intelligent search.
8485 +/*
8486 + * Mknod (create) a new object.
8487 + * equivalentObject only has meaning for a hard link;
8488 + * aliasString only has meaning for a symlink.
8489 + * rdev only has meaning for devices (a subset of special objects)
8490 */
8491
8492 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
8493 +static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
8494 + yaffs_Object *parent,
8495 + const YCHAR *name,
8496 + __u32 mode,
8497 + __u32 uid,
8498 + __u32 gid,
8499 + yaffs_Object *equivalentObject,
8500 + const YCHAR *aliasString, __u32 rdev)
8501 {
8502 - yaffs_Device *dev = obj->myDev;
8503 - int i;
8504 - yaffs_ChunkCache *cache;
8505 - int nCaches = obj->myDev->nShortOpCaches;
8506 + yaffs_Object *in;
8507 + YCHAR *str = NULL;
8508
8509 - for (i = 0; i < nCaches; i++) {
8510 - cache = &dev->srCache[i];
8511 - if (cache->object == obj &&
8512 - cache->dirty)
8513 - return 1;
8514 + yaffs_Device *dev = parent->myDev;
8515 +
8516 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8517 + if (yaffs_FindObjectByName(parent, name))
8518 + return NULL;
8519 +
8520 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8521 + str = yaffs_CloneString(aliasString);
8522 + if (!str)
8523 + return NULL;
8524 }
8525
8526 - return 0;
8527 -}
8528 + in = yaffs_CreateNewObject(dev, -1, type);
8529
8530 + if (!in){
8531 + if(str)
8532 + YFREE(str);
8533 + return NULL;
8534 + }
8535
8536 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
8537 -{
8538 - yaffs_Device *dev = obj->myDev;
8539 - int lowest = -99; /* Stop compiler whining. */
8540 - int i;
8541 - yaffs_ChunkCache *cache;
8542 - int chunkWritten = 0;
8543 - int nCaches = obj->myDev->nShortOpCaches;
8544
8545 - if (nCaches > 0) {
8546 - do {
8547 - cache = NULL;
8548
8549 - /* Find the dirty cache for this object with the lowest chunk id. */
8550 - for (i = 0; i < nCaches; i++) {
8551 - if (dev->srCache[i].object == obj &&
8552 - dev->srCache[i].dirty) {
8553 - if (!cache
8554 - || dev->srCache[i].chunkId <
8555 - lowest) {
8556 - cache = &dev->srCache[i];
8557 - lowest = cache->chunkId;
8558 - }
8559 - }
8560 - }
8561
8562 - if (cache && !cache->locked) {
8563 - /* Write it out and free it up */
8564
8565 - chunkWritten =
8566 - yaffs_WriteChunkDataToObject(cache->object,
8567 - cache->chunkId,
8568 - cache->data,
8569 - cache->nBytes,
8570 - 1);
8571 - cache->dirty = 0;
8572 - cache->object = NULL;
8573 - }
8574 + if (in) {
8575 + in->hdrChunk = 0;
8576 + in->valid = 1;
8577 + in->variantType = type;
8578
8579 - } while (cache && chunkWritten > 0);
8580 + in->yst_mode = mode;
8581
8582 - if (cache) {
8583 - /* Hoosterman, disk full while writing cache out. */
8584 - T(YAFFS_TRACE_ERROR,
8585 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
8586 +#ifdef CONFIG_YAFFS_WINCE
8587 + yfsd_WinFileTimeNow(in->win_atime);
8588 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8589 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
8590 +
8591 +#else
8592 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
8593 +
8594 + in->yst_rdev = rdev;
8595 + in->yst_uid = uid;
8596 + in->yst_gid = gid;
8597 +#endif
8598 + in->nDataChunks = 0;
8599 +
8600 + yaffs_SetObjectName(in, name);
8601 + in->dirty = 1;
8602 +
8603 + yaffs_AddObjectToDirectory(parent, in);
8604 +
8605 + in->myDev = parent->myDev;
8606 +
8607 + switch (type) {
8608 + case YAFFS_OBJECT_TYPE_SYMLINK:
8609 + in->variant.symLinkVariant.alias = str;
8610 + break;
8611 + case YAFFS_OBJECT_TYPE_HARDLINK:
8612 + in->variant.hardLinkVariant.equivalentObject =
8613 + equivalentObject;
8614 + in->variant.hardLinkVariant.equivalentObjectId =
8615 + equivalentObject->objectId;
8616 + ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
8617 + break;
8618 + case YAFFS_OBJECT_TYPE_FILE:
8619 + case YAFFS_OBJECT_TYPE_DIRECTORY:
8620 + case YAFFS_OBJECT_TYPE_SPECIAL:
8621 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8622 + /* do nothing */
8623 + break;
8624 + }
8625
8626 + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) {
8627 + /* Could not create the object header, fail the creation */
8628 + yaffs_DeleteObject(in);
8629 + in = NULL;
8630 }
8631 +
8632 + yaffs_UpdateParent(parent);
8633 }
8634
8635 + return in;
8636 }
8637
8638 -/*yaffs_FlushEntireDeviceCache(dev)
8639 - *
8640 - *
8641 - */
8642 -
8643 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
8644 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
8645 + __u32 mode, __u32 uid, __u32 gid)
8646 {
8647 - yaffs_Object *obj;
8648 - int nCaches = dev->nShortOpCaches;
8649 - int i;
8650 -
8651 - /* Find a dirty object in the cache and flush it...
8652 - * until there are no further dirty objects.
8653 - */
8654 - do {
8655 - obj = NULL;
8656 - for (i = 0; i < nCaches && !obj; i++) {
8657 - if (dev->srCache[i].object &&
8658 - dev->srCache[i].dirty)
8659 - obj = dev->srCache[i].object;
8660 -
8661 - }
8662 - if (obj)
8663 - yaffs_FlushFilesChunkCache(obj);
8664 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
8665 + uid, gid, NULL, NULL, 0);
8666 +}
8667
8668 - } while (obj);
8669 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
8670 + __u32 mode, __u32 uid, __u32 gid)
8671 +{
8672 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
8673 + mode, uid, gid, NULL, NULL, 0);
8674 +}
8675
8676 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
8677 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
8678 +{
8679 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
8680 + uid, gid, NULL, NULL, rdev);
8681 }
8682
8683 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
8684 + __u32 mode, __u32 uid, __u32 gid,
8685 + const YCHAR *alias)
8686 +{
8687 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
8688 + uid, gid, NULL, alias, 0);
8689 +}
8690
8691 -/* Grab us a cache chunk for use.
8692 - * First look for an empty one.
8693 - * Then look for the least recently used non-dirty one.
8694 - * Then look for the least recently used dirty one...., flush and look again.
8695 - */
8696 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
8697 +/* yaffs_Link returns the object id of the equivalent object.*/
8698 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
8699 + yaffs_Object *equivalentObject)
8700 {
8701 - int i;
8702 + /* Get the real object in case we were fed a hard link as an equivalent object */
8703 + equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
8704
8705 - if (dev->nShortOpCaches > 0) {
8706 - for (i = 0; i < dev->nShortOpCaches; i++) {
8707 - if (!dev->srCache[i].object)
8708 - return &dev->srCache[i];
8709 - }
8710 + if (yaffs_MknodObject
8711 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
8712 + equivalentObject, NULL, 0)) {
8713 + return equivalentObject;
8714 + } else {
8715 + return NULL;
8716 }
8717
8718 - return NULL;
8719 }
8720
8721 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
8722 +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
8723 + const YCHAR *newName, int force, int shadows)
8724 {
8725 - yaffs_ChunkCache *cache;
8726 - yaffs_Object *theObj;
8727 - int usage;
8728 - int i;
8729 - int pushout;
8730 -
8731 - if (dev->nShortOpCaches > 0) {
8732 - /* Try find a non-dirty one... */
8733 + int unlinkOp;
8734 + int deleteOp;
8735
8736 - cache = yaffs_GrabChunkCacheWorker(dev);
8737 + yaffs_Object *existingTarget;
8738
8739 - if (!cache) {
8740 - /* They were all dirty, find the last recently used object and flush
8741 - * its cache, then find again.
8742 - * NB what's here is not very accurate, we actually flush the object
8743 - * the last recently used page.
8744 - */
8745 + if (newDir == NULL)
8746 + newDir = obj->parent; /* use the old directory */
8747
8748 - /* With locking we can't assume we can use entry zero */
8749 + if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
8750 + T(YAFFS_TRACE_ALWAYS,
8751 + (TSTR
8752 + ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
8753 + TENDSTR)));
8754 + YBUG();
8755 + }
8756
8757 - theObj = NULL;
8758 - usage = -1;
8759 - cache = NULL;
8760 - pushout = -1;
8761 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
8762 + if (obj->myDev->param.isYaffs2)
8763 + unlinkOp = (newDir == obj->myDev->unlinkedDir);
8764 + else
8765 + unlinkOp = (newDir == obj->myDev->unlinkedDir
8766 + && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
8767
8768 - for (i = 0; i < dev->nShortOpCaches; i++) {
8769 - if (dev->srCache[i].object &&
8770 - !dev->srCache[i].locked &&
8771 - (dev->srCache[i].lastUse < usage || !cache)) {
8772 - usage = dev->srCache[i].lastUse;
8773 - theObj = dev->srCache[i].object;
8774 - cache = &dev->srCache[i];
8775 - pushout = i;
8776 - }
8777 - }
8778 + deleteOp = (newDir == obj->myDev->deletedDir);
8779
8780 - if (!cache || cache->dirty) {
8781 - /* Flush and try again */
8782 - yaffs_FlushFilesChunkCache(theObj);
8783 - cache = yaffs_GrabChunkCacheWorker(dev);
8784 - }
8785 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8786
8787 - }
8788 - return cache;
8789 - } else
8790 - return NULL;
8791 + /* If the object is a file going into the unlinked directory,
8792 + * then it is OK to just stuff it in since duplicate names are allowed.
8793 + * else only proceed if the new name does not exist and if we're putting
8794 + * it into a directory.
8795 + */
8796 + if ((unlinkOp ||
8797 + deleteOp ||
8798 + force ||
8799 + (shadows > 0) ||
8800 + !existingTarget) &&
8801 + newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
8802 + yaffs_SetObjectName(obj, newName);
8803 + obj->dirty = 1;
8804
8805 -}
8806 + yaffs_AddObjectToDirectory(newDir, obj);
8807
8808 -/* Find a cached chunk */
8809 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
8810 - int chunkId)
8811 -{
8812 - yaffs_Device *dev = obj->myDev;
8813 - int i;
8814 - if (dev->nShortOpCaches > 0) {
8815 - for (i = 0; i < dev->nShortOpCaches; i++) {
8816 - if (dev->srCache[i].object == obj &&
8817 - dev->srCache[i].chunkId == chunkId) {
8818 - dev->cacheHits++;
8819 + if (unlinkOp)
8820 + obj->unlinked = 1;
8821
8822 - return &dev->srCache[i];
8823 - }
8824 - }
8825 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
8826 + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0)
8827 + return YAFFS_OK;
8828 }
8829 - return NULL;
8830 +
8831 + return YAFFS_FAIL;
8832 }
8833
8834 -/* Mark the chunk for the least recently used algorithym */
8835 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
8836 - int isAWrite)
8837 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
8838 + yaffs_Object *newDir, const YCHAR *newName)
8839 {
8840 + yaffs_Object *obj = NULL;
8841 + yaffs_Object *existingTarget = NULL;
8842 + int force = 0;
8843 + int result;
8844 + yaffs_Device *dev;
8845
8846 - if (dev->nShortOpCaches > 0) {
8847 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
8848 - /* Reset the cache usages */
8849 - int i;
8850 - for (i = 1; i < dev->nShortOpCaches; i++)
8851 - dev->srCache[i].lastUse = 0;
8852
8853 - dev->srLastUse = 0;
8854 - }
8855 + if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8856 + YBUG();
8857 + if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8858 + YBUG();
8859
8860 - dev->srLastUse++;
8861 + dev = oldDir->myDev;
8862
8863 - cache->lastUse = dev->srLastUse;
8864 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
8865 + /* Special case for case insemsitive systems (eg. WinCE).
8866 + * While look-up is case insensitive, the name isn't.
8867 + * Therefore we might want to change x.txt to X.txt
8868 + */
8869 + if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
8870 + force = 1;
8871 +#endif
8872
8873 - if (isAWrite)
8874 - cache->dirty = 1;
8875 - }
8876 -}
8877 + if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
8878 + /* ENAMETOOLONG */
8879 + return YAFFS_FAIL;
8880
8881 -/* Invalidate a single cache page.
8882 - * Do this when a whole page gets written,
8883 - * ie the short cache for this page is no longer valid.
8884 - */
8885 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
8886 -{
8887 - if (object->myDev->nShortOpCaches > 0) {
8888 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
8889 + obj = yaffs_FindObjectByName(oldDir, oldName);
8890
8891 - if (cache)
8892 - cache->object = NULL;
8893 - }
8894 -}
8895 + if (obj && obj->renameAllowed) {
8896
8897 -/* Invalidate all the cache pages associated with this object
8898 - * Do this whenever ther file is deleted or resized.
8899 - */
8900 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
8901 -{
8902 - int i;
8903 - yaffs_Device *dev = in->myDev;
8904 + /* Now do the handling for an existing target, if there is one */
8905
8906 - if (dev->nShortOpCaches > 0) {
8907 - /* Invalidate it. */
8908 - for (i = 0; i < dev->nShortOpCaches; i++) {
8909 - if (dev->srCache[i].object == in)
8910 - dev->srCache[i].object = NULL;
8911 + existingTarget = yaffs_FindObjectByName(newDir, newName);
8912 + if (existingTarget &&
8913 + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
8914 + !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
8915 + /* There is a target that is a non-empty directory, so we fail */
8916 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
8917 + } else if (existingTarget && existingTarget != obj) {
8918 + /* Nuke the target first, using shadowing,
8919 + * but only if it isn't the same object.
8920 + *
8921 + * Note we must disable gc otherwise it can mess up the shadowing.
8922 + *
8923 + */
8924 + dev->gcDisable=1;
8925 + yaffs_ChangeObjectName(obj, newDir, newName, force,
8926 + existingTarget->objectId);
8927 + existingTarget->isShadowed = 1;
8928 + yaffs_UnlinkObject(existingTarget);
8929 + dev->gcDisable=0;
8930 }
8931 +
8932 + result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
8933 +
8934 + yaffs_UpdateParent(oldDir);
8935 + if(newDir != oldDir)
8936 + yaffs_UpdateParent(newDir);
8937 +
8938 + return result;
8939 }
8940 + return YAFFS_FAIL;
8941 }
8942
8943 -/*--------------------- Checkpointing --------------------*/
8944 -
8945 +/*------------------------- Block Management and Page Allocation ----------------*/
8946
8947 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
8948 +static int yaffs_InitialiseBlocks(yaffs_Device *dev)
8949 {
8950 - yaffs_CheckpointValidity cp;
8951 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
8952
8953 - memset(&cp, 0, sizeof(cp));
8954 + dev->blockInfo = NULL;
8955 + dev->chunkBits = NULL;
8956
8957 - cp.structType = sizeof(cp);
8958 - cp.magic = YAFFS_MAGIC;
8959 - cp.version = YAFFS_CHECKPOINT_VERSION;
8960 - cp.head = (head) ? 1 : 0;
8961 + dev->allocationBlock = -1; /* force it to get a new one */
8962
8963 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
8964 - 1 : 0;
8965 -}
8966 + /* If the first allocation strategy fails, thry the alternate one */
8967 + dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
8968 + if (!dev->blockInfo) {
8969 + dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
8970 + dev->blockInfoAlt = 1;
8971 + } else
8972 + dev->blockInfoAlt = 0;
8973
8974 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
8975 -{
8976 - yaffs_CheckpointValidity cp;
8977 - int ok;
8978 + if (dev->blockInfo) {
8979 + /* Set up dynamic blockinfo stuff. */
8980 + dev->chunkBitmapStride = (dev->param.nChunksPerBlock + 7) / 8; /* round up bytes */
8981 + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
8982 + if (!dev->chunkBits) {
8983 + dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
8984 + dev->chunkBitsAlt = 1;
8985 + } else
8986 + dev->chunkBitsAlt = 0;
8987 + }
8988
8989 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
8990 + if (dev->blockInfo && dev->chunkBits) {
8991 + memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
8992 + memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
8993 + return YAFFS_OK;
8994 + }
8995
8996 - if (ok)
8997 - ok = (cp.structType == sizeof(cp)) &&
8998 - (cp.magic == YAFFS_MAGIC) &&
8999 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
9000 - (cp.head == ((head) ? 1 : 0));
9001 - return ok ? 1 : 0;
9002 + return YAFFS_FAIL;
9003 }
9004
9005 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
9006 - yaffs_Device *dev)
9007 +static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
9008 {
9009 - cp->nErasedBlocks = dev->nErasedBlocks;
9010 - cp->allocationBlock = dev->allocationBlock;
9011 - cp->allocationPage = dev->allocationPage;
9012 - cp->nFreeChunks = dev->nFreeChunks;
9013 + if (dev->blockInfoAlt && dev->blockInfo)
9014 + YFREE_ALT(dev->blockInfo);
9015 + else if (dev->blockInfo)
9016 + YFREE(dev->blockInfo);
9017 +
9018 + dev->blockInfoAlt = 0;
9019
9020 - cp->nDeletedFiles = dev->nDeletedFiles;
9021 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9022 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9023 - cp->sequenceNumber = dev->sequenceNumber;
9024 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9025 + dev->blockInfo = NULL;
9026
9027 + if (dev->chunkBitsAlt && dev->chunkBits)
9028 + YFREE_ALT(dev->chunkBits);
9029 + else if (dev->chunkBits)
9030 + YFREE(dev->chunkBits);
9031 + dev->chunkBitsAlt = 0;
9032 + dev->chunkBits = NULL;
9033 }
9034
9035 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9036 - yaffs_CheckpointDevice *cp)
9037 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
9038 {
9039 - dev->nErasedBlocks = cp->nErasedBlocks;
9040 - dev->allocationBlock = cp->allocationBlock;
9041 - dev->allocationPage = cp->allocationPage;
9042 - dev->nFreeChunks = cp->nFreeChunks;
9043 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
9044
9045 - dev->nDeletedFiles = cp->nDeletedFiles;
9046 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9047 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9048 - dev->sequenceNumber = cp->sequenceNumber;
9049 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9050 -}
9051 + int erasedOk = 0;
9052
9053 + /* If the block is still healthy erase it and mark as clean.
9054 + * If the block has had a data failure, then retire it.
9055 + */
9056
9057 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9058 -{
9059 - yaffs_CheckpointDevice cp;
9060 - __u32 nBytes;
9061 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9062 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9063 + (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
9064 + blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
9065
9066 - int ok;
9067 + yaffs2_ClearOldestDirtySequence(dev,bi);
9068
9069 - /* Write device runtime values*/
9070 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9071 - cp.structType = sizeof(cp);
9072 + bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
9073
9074 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9075 + /* If this is the block being garbage collected then stop gc'ing this block */
9076 + if(blockNo == dev->gcBlock)
9077 + dev->gcBlock = 0;
9078 +
9079 + /* If this block is currently the best candidate for gc then drop as a candidate */
9080 + if(blockNo == dev->gcDirtiest){
9081 + dev->gcDirtiest = 0;
9082 + dev->gcPagesInUse = 0;
9083 + }
9084
9085 - /* Write block info */
9086 - if (ok) {
9087 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9088 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9089 + if (!bi->needsRetiring) {
9090 + yaffs2_InvalidateCheckpoint(dev);
9091 + erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
9092 + if (!erasedOk) {
9093 + dev->nErasureFailures++;
9094 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9095 + (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
9096 + }
9097 }
9098
9099 - /* Write chunk bits */
9100 - if (ok) {
9101 - nBytes = nBlocks * dev->chunkBitmapStride;
9102 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9103 + if (erasedOk &&
9104 + ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
9105 + int i;
9106 + for (i = 0; i < dev->param.nChunksPerBlock; i++) {
9107 + if (!yaffs_CheckChunkErased
9108 + (dev, blockNo * dev->param.nChunksPerBlock + i)) {
9109 + T(YAFFS_TRACE_ERROR,
9110 + (TSTR
9111 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9112 + TENDSTR), blockNo, i));
9113 + }
9114 + }
9115 }
9116 - return ok ? 1 : 0;
9117
9118 + if (erasedOk) {
9119 + /* Clean it up... */
9120 + bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
9121 + bi->sequenceNumber = 0;
9122 + dev->nErasedBlocks++;
9123 + bi->pagesInUse = 0;
9124 + bi->softDeletions = 0;
9125 + bi->hasShrinkHeader = 0;
9126 + bi->skipErasedCheck = 1; /* This is clean, so no need to check */
9127 + bi->gcPrioritise = 0;
9128 + yaffs_ClearChunkBits(dev, blockNo);
9129 +
9130 + T(YAFFS_TRACE_ERASE,
9131 + (TSTR("Erased block %d" TENDSTR), blockNo));
9132 + } else {
9133 + dev->nFreeChunks -= dev->param.nChunksPerBlock; /* We lost a block of free space */
9134 +
9135 + yaffs_RetireBlock(dev, blockNo);
9136 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9137 + (TSTR("**>> Block %d retired" TENDSTR), blockNo));
9138 + }
9139 }
9140
9141 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9142 +static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
9143 {
9144 - yaffs_CheckpointDevice cp;
9145 - __u32 nBytes;
9146 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9147 -
9148 - int ok;
9149 + int i;
9150
9151 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9152 - if (!ok)
9153 - return 0;
9154 + yaffs_BlockInfo *bi;
9155
9156 - if (cp.structType != sizeof(cp))
9157 - return 0;
9158 + if (dev->nErasedBlocks < 1) {
9159 + /* Hoosterman we've got a problem.
9160 + * Can't get space to gc
9161 + */
9162 + T(YAFFS_TRACE_ERROR,
9163 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9164
9165 + return -1;
9166 + }
9167
9168 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9169 + /* Find an empty block. */
9170
9171 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9172 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
9173 + dev->allocationBlockFinder++;
9174 + if (dev->allocationBlockFinder < dev->internalStartBlock
9175 + || dev->allocationBlockFinder > dev->internalEndBlock) {
9176 + dev->allocationBlockFinder = dev->internalStartBlock;
9177 + }
9178
9179 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9180 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
9181
9182 - if (!ok)
9183 - return 0;
9184 - nBytes = nBlocks * dev->chunkBitmapStride;
9185 + if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
9186 + bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
9187 + dev->sequenceNumber++;
9188 + bi->sequenceNumber = dev->sequenceNumber;
9189 + dev->nErasedBlocks--;
9190 + T(YAFFS_TRACE_ALLOCATE,
9191 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9192 + dev->allocationBlockFinder, dev->sequenceNumber,
9193 + dev->nErasedBlocks));
9194 + return dev->allocationBlockFinder;
9195 + }
9196 + }
9197
9198 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9199 + T(YAFFS_TRACE_ALWAYS,
9200 + (TSTR
9201 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9202 + TENDSTR), dev->nErasedBlocks));
9203
9204 - return ok ? 1 : 0;
9205 + return -1;
9206 }
9207
9208 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9209 - yaffs_Object *obj)
9210 +
9211 +/*
9212 + * Check if there's space to allocate...
9213 + * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
9214 + */
9215 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks)
9216 {
9217 + int reservedChunks;
9218 + int reservedBlocks = dev->param.nReservedBlocks;
9219 + int checkpointBlocks;
9220
9221 - cp->objectId = obj->objectId;
9222 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9223 - cp->hdrChunk = obj->hdrChunk;
9224 - cp->variantType = obj->variantType;
9225 - cp->deleted = obj->deleted;
9226 - cp->softDeleted = obj->softDeleted;
9227 - cp->unlinked = obj->unlinked;
9228 - cp->fake = obj->fake;
9229 - cp->renameAllowed = obj->renameAllowed;
9230 - cp->unlinkAllowed = obj->unlinkAllowed;
9231 - cp->serial = obj->serial;
9232 - cp->nDataChunks = obj->nDataChunks;
9233 + checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev);
9234
9235 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9236 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9237 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9238 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9239 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
9240 +
9241 + return (dev->nFreeChunks > (reservedChunks + nChunks));
9242 }
9243
9244 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9245 +static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
9246 + yaffs_BlockInfo **blockUsedPtr)
9247 {
9248 + int retVal;
9249 + yaffs_BlockInfo *bi;
9250
9251 - yaffs_Object *parent;
9252 + if (dev->allocationBlock < 0) {
9253 + /* Get next block to allocate off */
9254 + dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
9255 + dev->allocationPage = 0;
9256 + }
9257
9258 - if (obj->variantType != cp->variantType) {
9259 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9260 - TCONT("chunk %d does not match existing object type %d")
9261 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9262 - obj->variantType));
9263 - return 0;
9264 + if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) {
9265 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9266 + return -1;
9267 }
9268
9269 - obj->objectId = cp->objectId;
9270 + if (dev->nErasedBlocks < dev->param.nReservedBlocks
9271 + && dev->allocationPage == 0) {
9272 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9273 + }
9274
9275 - if (cp->parentId)
9276 - parent = yaffs_FindOrCreateObjectByNumber(
9277 - obj->myDev,
9278 - cp->parentId,
9279 - YAFFS_OBJECT_TYPE_DIRECTORY);
9280 - else
9281 - parent = NULL;
9282 + /* Next page please.... */
9283 + if (dev->allocationBlock >= 0) {
9284 + bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9285
9286 - if (parent) {
9287 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9288 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9289 - TCONT(" chunk %d Parent type, %d, not directory")
9290 - TENDSTR),
9291 - cp->objectId, cp->parentId, cp->variantType,
9292 - cp->hdrChunk, parent->variantType));
9293 - return 0;
9294 - }
9295 - yaffs_AddObjectToDirectory(parent, obj);
9296 - }
9297 + retVal = (dev->allocationBlock * dev->param.nChunksPerBlock) +
9298 + dev->allocationPage;
9299 + bi->pagesInUse++;
9300 + yaffs_SetChunkBit(dev, dev->allocationBlock,
9301 + dev->allocationPage);
9302
9303 - obj->hdrChunk = cp->hdrChunk;
9304 - obj->variantType = cp->variantType;
9305 - obj->deleted = cp->deleted;
9306 - obj->softDeleted = cp->softDeleted;
9307 - obj->unlinked = cp->unlinked;
9308 - obj->fake = cp->fake;
9309 - obj->renameAllowed = cp->renameAllowed;
9310 - obj->unlinkAllowed = cp->unlinkAllowed;
9311 - obj->serial = cp->serial;
9312 - obj->nDataChunks = cp->nDataChunks;
9313 + dev->allocationPage++;
9314
9315 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9316 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9317 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9318 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9319 + dev->nFreeChunks--;
9320
9321 - if (obj->hdrChunk > 0)
9322 - obj->lazyLoaded = 1;
9323 - return 1;
9324 -}
9325 + /* If the block is full set the state to full */
9326 + if (dev->allocationPage >= dev->param.nChunksPerBlock) {
9327 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9328 + dev->allocationBlock = -1;
9329 + }
9330
9331 + if (blockUsedPtr)
9332 + *blockUsedPtr = bi;
9333
9334 + return retVal;
9335 + }
9336
9337 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9338 - __u32 level, int chunkOffset)
9339 -{
9340 - int i;
9341 - yaffs_Device *dev = in->myDev;
9342 - int ok = 1;
9343 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9344 + T(YAFFS_TRACE_ERROR,
9345 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9346
9347 - if (tnodeSize < sizeof(yaffs_Tnode))
9348 - tnodeSize = sizeof(yaffs_Tnode);
9349 + return -1;
9350 +}
9351
9352 +static int yaffs_GetErasedChunks(yaffs_Device *dev)
9353 +{
9354 + int n;
9355
9356 - if (tn) {
9357 - if (level > 0) {
9358 + n = dev->nErasedBlocks * dev->param.nChunksPerBlock;
9359
9360 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9361 - if (tn->internal[i]) {
9362 - ok = yaffs_CheckpointTnodeWorker(in,
9363 - tn->internal[i],
9364 - level - 1,
9365 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9366 - }
9367 - }
9368 - } else if (level == 0) {
9369 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9370 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9371 - if (ok)
9372 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9373 - }
9374 - }
9375 + if (dev->allocationBlock > 0)
9376 + n += (dev->param.nChunksPerBlock - dev->allocationPage);
9377
9378 - return ok;
9379 + return n;
9380
9381 }
9382
9383 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9384 +/*
9385 + * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
9386 + * if we don't want to write to it.
9387 + */
9388 +void yaffs_SkipRestOfBlock(yaffs_Device *dev)
9389 {
9390 - __u32 endMarker = ~0;
9391 - int ok = 1;
9392 -
9393 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9394 - ok = yaffs_CheckpointTnodeWorker(obj,
9395 - obj->variant.fileVariant.top,
9396 - obj->variant.fileVariant.topLevel,
9397 - 0);
9398 - if (ok)
9399 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
9400 - sizeof(endMarker));
9401 + if(dev->allocationBlock > 0){
9402 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
9403 + if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
9404 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9405 + dev->allocationBlock = -1;
9406 + }
9407 }
9408 -
9409 - return ok ? 1 : 0;
9410 }
9411
9412 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
9413 -{
9414 - __u32 baseChunk;
9415 - int ok = 1;
9416 - yaffs_Device *dev = obj->myDev;
9417 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
9418 - yaffs_Tnode *tn;
9419 - int nread = 0;
9420 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9421
9422 - if (tnodeSize < sizeof(yaffs_Tnode))
9423 - tnodeSize = sizeof(yaffs_Tnode);
9424 +static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
9425 + int wholeBlock)
9426 +{
9427 + int oldChunk;
9428 + int newChunk;
9429 + int markNAND;
9430 + int retVal = YAFFS_OK;
9431 + int i;
9432 + int isCheckpointBlock;
9433 + int matchingChunk;
9434 + int maxCopies;
9435
9436 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9437 + int chunksBefore = yaffs_GetErasedChunks(dev);
9438 + int chunksAfter;
9439
9440 - while (ok && (~baseChunk)) {
9441 - nread++;
9442 - /* Read level 0 tnode */
9443 + yaffs_ExtendedTags tags;
9444
9445 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
9446
9447 - tn = yaffs_GetTnodeRaw(dev);
9448 - if (tn)
9449 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
9450 - else
9451 - ok = 0;
9452 + yaffs_Object *object;
9453
9454 - if (tn && ok)
9455 - ok = yaffs_AddOrFindLevel0Tnode(dev,
9456 - fileStructPtr,
9457 - baseChunk,
9458 - tn) ? 1 : 0;
9459 + isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
9460
9461 - if (ok)
9462 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
9463
9464 - }
9465 + T(YAFFS_TRACE_TRACING,
9466 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
9467 + block,
9468 + bi->pagesInUse,
9469 + bi->hasShrinkHeader,
9470 + wholeBlock));
9471
9472 - T(YAFFS_TRACE_CHECKPOINT, (
9473 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
9474 - nread, baseChunk, ok));
9475 + /*yaffs_VerifyFreeChunks(dev); */
9476
9477 - return ok ? 1 : 0;
9478 -}
9479 + if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
9480 + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
9481 +
9482 + bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
9483
9484 + dev->gcDisable = 1;
9485
9486 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
9487 -{
9488 - yaffs_Object *obj;
9489 - yaffs_CheckpointObject cp;
9490 - int i;
9491 - int ok = 1;
9492 - struct ylist_head *lh;
9493 + if (isCheckpointBlock ||
9494 + !yaffs_StillSomeChunkBits(dev, block)) {
9495 + T(YAFFS_TRACE_TRACING,
9496 + (TSTR
9497 + ("Collecting block %d that has no chunks in use" TENDSTR),
9498 + block));
9499 + yaffs_BlockBecameDirty(dev, block);
9500 + } else {
9501
9502 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
9503
9504 - /* Iterate through the objects in each hash entry,
9505 - * dumping them to the checkpointing stream.
9506 - */
9507 + yaffs_VerifyBlock(dev, bi, block);
9508
9509 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
9510 - ylist_for_each(lh, &dev->objectBucket[i].list) {
9511 - if (lh) {
9512 - obj = ylist_entry(lh, yaffs_Object, hashLink);
9513 - if (!obj->deferedFree) {
9514 - yaffs_ObjectToCheckpointObject(&cp, obj);
9515 - cp.structType = sizeof(cp);
9516 -
9517 - T(YAFFS_TRACE_CHECKPOINT, (
9518 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
9519 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
9520 + maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5;
9521 + oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk;
9522
9523 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9524 + for (/* init already done */;
9525 + retVal == YAFFS_OK &&
9526 + dev->gcChunk < dev->param.nChunksPerBlock &&
9527 + (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
9528 + maxCopies > 0;
9529 + dev->gcChunk++, oldChunk++) {
9530 + if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
9531
9532 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9533 - ok = yaffs_WriteCheckpointTnodes(obj);
9534 - }
9535 - }
9536 - }
9537 - }
9538 + /* This page is in use and might need to be copied off */
9539
9540 - /* Dump end of list */
9541 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
9542 - cp.structType = sizeof(cp);
9543 + maxCopies--;
9544
9545 - if (ok)
9546 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9547 + markNAND = 1;
9548
9549 - return ok ? 1 : 0;
9550 -}
9551 + yaffs_InitialiseTags(&tags);
9552
9553 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
9554 -{
9555 - yaffs_Object *obj;
9556 - yaffs_CheckpointObject cp;
9557 - int ok = 1;
9558 - int done = 0;
9559 - yaffs_Object *hardList = NULL;
9560 + yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
9561 + buffer, &tags);
9562
9563 - while (ok && !done) {
9564 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9565 - if (cp.structType != sizeof(cp)) {
9566 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
9567 - cp.structType, sizeof(cp), ok));
9568 - ok = 0;
9569 - }
9570 -
9571 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
9572 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
9573 -
9574 - if (ok && cp.objectId == ~0)
9575 - done = 1;
9576 - else if (ok) {
9577 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
9578 - if (obj) {
9579 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
9580 - if (!ok)
9581 - break;
9582 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9583 - ok = yaffs_ReadCheckpointTnodes(obj);
9584 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
9585 - obj->hardLinks.next =
9586 - (struct ylist_head *) hardList;
9587 - hardList = obj;
9588 - }
9589 - } else
9590 - ok = 0;
9591 - }
9592 - }
9593 + object =
9594 + yaffs_FindObjectByNumber(dev,
9595 + tags.objectId);
9596
9597 - if (ok)
9598 - yaffs_HardlinkFixup(dev, hardList);
9599 + T(YAFFS_TRACE_GC_DETAIL,
9600 + (TSTR
9601 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
9602 + dev->gcChunk, tags.objectId, tags.chunkId,
9603 + tags.byteCount));
9604
9605 - return ok ? 1 : 0;
9606 -}
9607 + if (object && !yaffs_SkipVerification(dev)) {
9608 + if (tags.chunkId == 0)
9609 + matchingChunk = object->hdrChunk;
9610 + else if (object->softDeleted)
9611 + matchingChunk = oldChunk; /* Defeat the test */
9612 + else
9613 + matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
9614
9615 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
9616 -{
9617 - __u32 checkpointSum;
9618 - int ok;
9619 + if (oldChunk != matchingChunk)
9620 + T(YAFFS_TRACE_ERROR,
9621 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
9622 + oldChunk, matchingChunk, tags.objectId, tags.chunkId));
9623
9624 - yaffs_GetCheckpointSum(dev, &checkpointSum);
9625 + }
9626
9627 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
9628 + if (!object) {
9629 + T(YAFFS_TRACE_ERROR,
9630 + (TSTR
9631 + ("page %d in gc has no object: %d %d %d "
9632 + TENDSTR), oldChunk,
9633 + tags.objectId, tags.chunkId, tags.byteCount));
9634 + }
9635
9636 - if (!ok)
9637 - return 0;
9638 + if (object &&
9639 + object->deleted &&
9640 + object->softDeleted &&
9641 + tags.chunkId != 0) {
9642 + /* Data chunk in a soft deleted file, throw it away
9643 + * It's a soft deleted data chunk,
9644 + * No need to copy this, just forget about it and
9645 + * fix up the object.
9646 + */
9647 +
9648 + /* Free chunks already includes softdeleted chunks.
9649 + * How ever this chunk is going to soon be really deleted
9650 + * which will increment free chunks.
9651 + * We have to decrement free chunks so this works out properly.
9652 + */
9653 + dev->nFreeChunks--;
9654 + bi->softDeletions--;
9655
9656 - return 1;
9657 -}
9658 + object->nDataChunks--;
9659
9660 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
9661 -{
9662 - __u32 checkpointSum0;
9663 - __u32 checkpointSum1;
9664 - int ok;
9665 + if (object->nDataChunks <= 0) {
9666 + /* remeber to clean up the object */
9667 + dev->gcCleanupList[dev->nCleanups] =
9668 + tags.objectId;
9669 + dev->nCleanups++;
9670 + }
9671 + markNAND = 0;
9672 + } else if (0) {
9673 + /* Todo object && object->deleted && object->nDataChunks == 0 */
9674 + /* Deleted object header with no data chunks.
9675 + * Can be discarded and the file deleted.
9676 + */
9677 + object->hdrChunk = 0;
9678 + yaffs_FreeTnode(object->myDev,
9679 + object->variant.
9680 + fileVariant.top);
9681 + object->variant.fileVariant.top = NULL;
9682 + yaffs_DoGenericObjectDeletion(object);
9683
9684 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
9685 + } else if (object) {
9686 + /* It's either a data chunk in a live file or
9687 + * an ObjectHeader, so we're interested in it.
9688 + * NB Need to keep the ObjectHeaders of deleted files
9689 + * until the whole file has been deleted off
9690 + */
9691 + tags.serialNumber++;
9692
9693 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
9694 + dev->nGCCopies++;
9695
9696 - if (!ok)
9697 - return 0;
9698 + if (tags.chunkId == 0) {
9699 + /* It is an object Id,
9700 + * We need to nuke the shrinkheader flags first
9701 + * Also need to clean up shadowing.
9702 + * We no longer want the shrinkHeader flag since its work is done
9703 + * and if it is left in place it will mess up scanning.
9704 + */
9705
9706 - if (checkpointSum0 != checkpointSum1)
9707 - return 0;
9708 + yaffs_ObjectHeader *oh;
9709 + oh = (yaffs_ObjectHeader *)buffer;
9710
9711 - return 1;
9712 -}
9713 + oh->isShrink = 0;
9714 + tags.extraIsShrinkHeader = 0;
9715
9716 + oh->shadowsObject = 0;
9717 + oh->inbandShadowsObject = 0;
9718 + tags.extraShadows = 0;
9719 +
9720 + /* Update file size */
9721 + if(object->variantType == YAFFS_OBJECT_TYPE_FILE){
9722 + oh->fileSize = object->variant.fileVariant.fileSize;
9723 + tags.extraFileLength = oh->fileSize;
9724 + }
9725
9726 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
9727 -{
9728 - int ok = 1;
9729 + yaffs_VerifyObjectHeader(object, oh, &tags, 1);
9730 + newChunk =
9731 + yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1);
9732 + } else
9733 + newChunk =
9734 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
9735
9736 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
9737 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
9738 - ok = 0;
9739 - }
9740 + if (newChunk < 0) {
9741 + retVal = YAFFS_FAIL;
9742 + } else {
9743
9744 - if (ok)
9745 - ok = yaffs_CheckpointOpen(dev, 1);
9746 + /* Ok, now fix up the Tnodes etc. */
9747
9748 - if (ok) {
9749 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9750 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
9751 - }
9752 - if (ok) {
9753 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
9754 - ok = yaffs_WriteCheckpointDevice(dev);
9755 - }
9756 - if (ok) {
9757 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
9758 - ok = yaffs_WriteCheckpointObjects(dev);
9759 - }
9760 - if (ok) {
9761 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
9762 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
9763 - }
9764 + if (tags.chunkId == 0) {
9765 + /* It's a header */
9766 + object->hdrChunk = newChunk;
9767 + object->serial = tags.serialNumber;
9768 + } else {
9769 + /* It's a data chunk */
9770 + int ok;
9771 + ok = yaffs_PutChunkIntoFile
9772 + (object,
9773 + tags.chunkId,
9774 + newChunk, 0);
9775 + }
9776 + }
9777 + }
9778
9779 - if (ok)
9780 - ok = yaffs_WriteCheckpointSum(dev);
9781 + if (retVal == YAFFS_OK)
9782 + yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
9783
9784 - if (!yaffs_CheckpointClose(dev))
9785 - ok = 0;
9786 + }
9787 + }
9788
9789 - if (ok)
9790 - dev->isCheckpointed = 1;
9791 - else
9792 - dev->isCheckpointed = 0;
9793 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9794
9795 - return dev->isCheckpointed;
9796 -}
9797
9798 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
9799 -{
9800 - int ok = 1;
9801
9802 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
9803 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
9804 - ok = 0;
9805 }
9806
9807 - if (ok)
9808 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
9809 -
9810 - if (ok) {
9811 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9812 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
9813 - }
9814 - if (ok) {
9815 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
9816 - ok = yaffs_ReadCheckpointDevice(dev);
9817 - }
9818 - if (ok) {
9819 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
9820 - ok = yaffs_ReadCheckpointObjects(dev);
9821 - }
9822 - if (ok) {
9823 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
9824 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
9825 - }
9826 + yaffs_VerifyCollectedBlock(dev, bi, block);
9827
9828 - if (ok) {
9829 - ok = yaffs_ReadCheckpointSum(dev);
9830 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
9831 - }
9832
9833 - if (!yaffs_CheckpointClose(dev))
9834 - ok = 0;
9835
9836 - if (ok)
9837 - dev->isCheckpointed = 1;
9838 - else
9839 - dev->isCheckpointed = 0;
9840 + if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
9841 + /*
9842 + * The gc did not complete. Set block state back to FULL
9843 + * because checkpointing does not restore gc.
9844 + */
9845 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
9846 + } else {
9847 + /* The gc completed. */
9848 + /* Do any required cleanups */
9849 + for (i = 0; i < dev->nCleanups; i++) {
9850 + /* Time to delete the file too */
9851 + object =
9852 + yaffs_FindObjectByNumber(dev,
9853 + dev->gcCleanupList[i]);
9854 + if (object) {
9855 + yaffs_FreeTnode(dev,
9856 + object->variant.fileVariant.
9857 + top);
9858 + object->variant.fileVariant.top = NULL;
9859 + T(YAFFS_TRACE_GC,
9860 + (TSTR
9861 + ("yaffs: About to finally delete object %d"
9862 + TENDSTR), object->objectId));
9863 + yaffs_DoGenericObjectDeletion(object);
9864 + object->myDev->nDeletedFiles--;
9865 + }
9866
9867 - return ok ? 1 : 0;
9868 + }
9869
9870 -}
9871
9872 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
9873 -{
9874 - if (dev->isCheckpointed ||
9875 - dev->blocksInCheckpoint > 0) {
9876 - dev->isCheckpointed = 0;
9877 - yaffs_CheckpointInvalidateStream(dev);
9878 - if (dev->superBlock && dev->markSuperBlockDirty)
9879 - dev->markSuperBlockDirty(dev->superBlock);
9880 + chunksAfter = yaffs_GetErasedChunks(dev);
9881 + if (chunksBefore >= chunksAfter) {
9882 + T(YAFFS_TRACE_GC,
9883 + (TSTR
9884 + ("gc did not increase free chunks before %d after %d"
9885 + TENDSTR), chunksBefore, chunksAfter));
9886 + }
9887 + dev->gcBlock = 0;
9888 + dev->gcChunk = 0;
9889 + dev->nCleanups = 0;
9890 }
9891 -}
9892
9893 + dev->gcDisable = 0;
9894
9895 -int yaffs_CheckpointSave(yaffs_Device *dev)
9896 -{
9897 -
9898 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9899 + return retVal;
9900 +}
9901
9902 - yaffs_VerifyObjects(dev);
9903 - yaffs_VerifyBlocks(dev);
9904 - yaffs_VerifyFreeChunks(dev);
9905 +/*
9906 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
9907 + * for garbage collection.
9908 + */
9909
9910 - if (!dev->isCheckpointed) {
9911 - yaffs_InvalidateCheckpoint(dev);
9912 - yaffs_WriteCheckpointData(dev);
9913 - }
9914 +static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
9915 + int aggressive,
9916 + int background)
9917 +{
9918 + int i;
9919 + int iterations;
9920 + unsigned selected = 0;
9921 + int prioritised = 0;
9922 + int prioritisedExists = 0;
9923 + yaffs_BlockInfo *bi;
9924 + int threshold;
9925
9926 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9927 + /* First let's see if we need to grab a prioritised block */
9928 + if (dev->hasPendingPrioritisedGCs && !aggressive) {
9929 + dev->gcDirtiest = 0;
9930 + bi = dev->blockInfo;
9931 + for (i = dev->internalStartBlock;
9932 + i <= dev->internalEndBlock && !selected;
9933 + i++) {
9934
9935 - return dev->isCheckpointed;
9936 -}
9937 + if (bi->gcPrioritise) {
9938 + prioritisedExists = 1;
9939 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
9940 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
9941 + selected = i;
9942 + prioritised = 1;
9943 + }
9944 + }
9945 + bi++;
9946 + }
9947
9948 -int yaffs_CheckpointRestore(yaffs_Device *dev)
9949 -{
9950 - int retval;
9951 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9952 + /*
9953 + * If there is a prioritised block and none was selected then
9954 + * this happened because there is at least one old dirty block gumming
9955 + * up the works. Let's gc the oldest dirty block.
9956 + */
9957
9958 - retval = yaffs_ReadCheckpointData(dev);
9959 + if(prioritisedExists &&
9960 + !selected &&
9961 + dev->oldestDirtyBlock > 0)
9962 + selected = dev->oldestDirtyBlock;
9963
9964 - if (dev->isCheckpointed) {
9965 - yaffs_VerifyObjects(dev);
9966 - yaffs_VerifyBlocks(dev);
9967 - yaffs_VerifyFreeChunks(dev);
9968 + if (!prioritisedExists) /* None found, so we can clear this */
9969 + dev->hasPendingPrioritisedGCs = 0;
9970 }
9971
9972 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
9973 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
9974 + * search harder.
9975 + * else (we're doing a leasurely gc), then we only bother to do this if the
9976 + * block has only a few pages in use.
9977 + */
9978
9979 - return retval;
9980 -}
9981 + if (!selected){
9982 + int pagesUsed;
9983 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
9984 + if (aggressive){
9985 + threshold = dev->param.nChunksPerBlock;
9986 + iterations = nBlocks;
9987 + } else {
9988 + int maxThreshold;
9989
9990 -/*--------------------- File read/write ------------------------
9991 - * Read and write have very similar structures.
9992 - * In general the read/write has three parts to it
9993 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
9994 - * Some complete chunks
9995 - * An incomplete chunk to end off with
9996 - *
9997 - * Curve-balls: the first chunk might also be the last chunk.
9998 - */
9999 + if(background)
10000 + maxThreshold = dev->param.nChunksPerBlock/2;
10001 + else
10002 + maxThreshold = dev->param.nChunksPerBlock/8;
10003
10004 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
10005 - int nBytes)
10006 -{
10007 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
10008 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
10009
10010 - int chunk;
10011 - __u32 start;
10012 - int nToCopy;
10013 - int n = nBytes;
10014 - int nDone = 0;
10015 - yaffs_ChunkCache *cache;
10016 + threshold = background ?
10017 + (dev->gcNotDone + 2) * 2 : 0;
10018 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10019 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10020 + if(threshold > maxThreshold)
10021 + threshold = maxThreshold;
10022
10023 - yaffs_Device *dev;
10024 + iterations = nBlocks / 16 + 1;
10025 + if (iterations > 100)
10026 + iterations = 100;
10027 + }
10028
10029 - dev = in->myDev;
10030 + for (i = 0;
10031 + i < iterations &&
10032 + (dev->gcDirtiest < 1 ||
10033 + dev->gcPagesInUse > YAFFS_GC_GOOD_ENOUGH);
10034 + i++) {
10035 + dev->gcBlockFinder++;
10036 + if (dev->gcBlockFinder < dev->internalStartBlock ||
10037 + dev->gcBlockFinder > dev->internalEndBlock)
10038 + dev->gcBlockFinder = dev->internalStartBlock;
10039
10040 - while (n > 0) {
10041 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10042 - /* start = offset % dev->nDataBytesPerChunk; */
10043 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10044 - chunk++;
10045 + bi = yaffs_GetBlockInfo(dev, dev->gcBlockFinder);
10046
10047 - /* OK now check for the curveball where the start and end are in
10048 - * the same chunk.
10049 - */
10050 - if ((start + n) < dev->nDataBytesPerChunk)
10051 - nToCopy = n;
10052 - else
10053 - nToCopy = dev->nDataBytesPerChunk - start;
10054 + pagesUsed = bi->pagesInUse - bi->softDeletions;
10055
10056 - cache = yaffs_FindChunkCache(in, chunk);
10057 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
10058 + pagesUsed < dev->param.nChunksPerBlock &&
10059 + (dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) &&
10060 + yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
10061 + dev->gcDirtiest = dev->gcBlockFinder;
10062 + dev->gcPagesInUse = pagesUsed;
10063 + }
10064 + }
10065
10066 - /* If the chunk is already in the cache or it is less than a whole chunk
10067 - * or we're using inband tags then use the cache (if there is caching)
10068 - * else bypass the cache.
10069 - */
10070 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10071 - if (dev->nShortOpCaches > 0) {
10072 + if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold)
10073 + selected = dev->gcDirtiest;
10074 + }
10075 +
10076 + /*
10077 + * If nothing has been selected for a while, try selecting the oldest dirty
10078 + * because that's gumming up the works.
10079 + */
10080
10081 - /* If we can't find the data in the cache, then load it up. */
10082 + if(!selected && dev->param.isYaffs2 &&
10083 + dev->gcNotDone >= ( background ? 10 : 20)){
10084 + yaffs2_FindOldestDirtySequence(dev);
10085 + if(dev->oldestDirtyBlock > 0) {
10086 + selected = dev->oldestDirtyBlock;
10087 + dev->gcDirtiest = selected;
10088 + dev->oldestDirtyGCs++;
10089 + bi = yaffs_GetBlockInfo(dev, selected);
10090 + dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions;
10091 + } else
10092 + dev->gcNotDone = 0;
10093 + }
10094
10095 - if (!cache) {
10096 - cache = yaffs_GrabChunkCache(in->myDev);
10097 - cache->object = in;
10098 - cache->chunkId = chunk;
10099 - cache->dirty = 0;
10100 - cache->locked = 0;
10101 - yaffs_ReadChunkDataFromObject(in, chunk,
10102 - cache->
10103 - data);
10104 - cache->nBytes = 0;
10105 - }
10106 + if(selected){
10107 + T(YAFFS_TRACE_GC,
10108 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10109 + selected,
10110 + dev->param.nChunksPerBlock - dev->gcPagesInUse,
10111 + prioritised));
10112 +
10113 + dev->nGCBlocks++;
10114 + if(background)
10115 + dev->backgroundGCs++;
10116 +
10117 + dev->gcDirtiest = 0;
10118 + dev->gcPagesInUse = 0;
10119 + dev->gcNotDone = 0;
10120 + if(dev->refreshSkip > 0)
10121 + dev->refreshSkip--;
10122 + } else{
10123 + dev->gcNotDone++;
10124 + T(YAFFS_TRACE_GC,
10125 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10126 + dev->gcBlockFinder, dev->gcNotDone,
10127 + threshold,
10128 + dev->gcDirtiest, dev->gcPagesInUse,
10129 + dev->oldestDirtyBlock,
10130 + background ? " bg" : ""));
10131 + }
10132
10133 - yaffs_UseChunkCache(dev, cache, 0);
10134 + return selected;
10135 +}
10136
10137 - cache->locked = 1;
10138 +/* New garbage collector
10139 + * If we're very low on erased blocks then we do aggressive garbage collection
10140 + * otherwise we do "leasurely" garbage collection.
10141 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10142 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10143 + *
10144 + * The idea is to help clear out space in a more spread-out manner.
10145 + * Dunno if it really does anything useful.
10146 + */
10147 +static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
10148 +{
10149 + int aggressive = 0;
10150 + int gcOk = YAFFS_OK;
10151 + int maxTries = 0;
10152 + int minErased;
10153 + int erasedChunks;
10154 + int checkpointBlockAdjust;
10155
10156 + if(dev->param.gcControl &&
10157 + (dev->param.gcControl(dev) & 1) == 0)
10158 + return YAFFS_OK;
10159
10160 - memcpy(buffer, &cache->data[start], nToCopy);
10161 + if (dev->gcDisable) {
10162 + /* Bail out so we don't get recursive gc */
10163 + return YAFFS_OK;
10164 + }
10165
10166 - cache->locked = 0;
10167 - } else {
10168 - /* Read into the local buffer then copy..*/
10169 + /* This loop should pass the first time.
10170 + * We'll only see looping here if the collection does not increase space.
10171 + */
10172
10173 - __u8 *localBuffer =
10174 - yaffs_GetTempBuffer(dev, __LINE__);
10175 - yaffs_ReadChunkDataFromObject(in, chunk,
10176 - localBuffer);
10177 + do {
10178 + maxTries++;
10179
10180 - memcpy(buffer, &localBuffer[start], nToCopy);
10181 + checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev);
10182
10183 + minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1;
10184 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10185
10186 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10187 - __LINE__);
10188 + /* If we need a block soon then do aggressive gc.*/
10189 + if (dev->nErasedBlocks < minErased)
10190 + aggressive = 1;
10191 + else {
10192 + if(!background && erasedChunks > (dev->nFreeChunks / 4))
10193 + break;
10194 +
10195 + if(dev->gcSkip > 20)
10196 + dev->gcSkip = 20;
10197 + if(erasedChunks < dev->nFreeChunks/2 ||
10198 + dev->gcSkip < 1 ||
10199 + background)
10200 + aggressive = 0;
10201 + else {
10202 + dev->gcSkip--;
10203 + break;
10204 }
10205 + }
10206
10207 - } else {
10208 + dev->gcSkip = 5;
10209
10210 - /* A full chunk. Read directly into the supplied buffer. */
10211 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10212 + /* If we don't already have a block being gc'd then see if we should start another */
10213
10214 + if (dev->gcBlock < 1 && !aggressive) {
10215 + dev->gcBlock = yaffs2_FindRefreshBlock(dev);
10216 + dev->gcChunk = 0;
10217 + dev->nCleanups=0;
10218 + }
10219 + if (dev->gcBlock < 1) {
10220 + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
10221 + dev->gcChunk = 0;
10222 + dev->nCleanups=0;
10223 }
10224
10225 - n -= nToCopy;
10226 - offset += nToCopy;
10227 - buffer += nToCopy;
10228 - nDone += nToCopy;
10229 + if (dev->gcBlock > 0) {
10230 + dev->allGCs++;
10231 + if (!aggressive)
10232 + dev->passiveGCs++;
10233
10234 - }
10235 + T(YAFFS_TRACE_GC,
10236 + (TSTR
10237 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10238 + dev->nErasedBlocks, aggressive));
10239
10240 - return nDone;
10241 + gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive);
10242 + }
10243 +
10244 + if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) {
10245 + T(YAFFS_TRACE_GC,
10246 + (TSTR
10247 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10248 + TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock));
10249 + }
10250 + } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) &&
10251 + (dev->gcBlock > 0) &&
10252 + (maxTries < 2));
10253 +
10254 + return aggressive ? gcOk : YAFFS_OK;
10255 }
10256
10257 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10258 - int nBytes, int writeThrough)
10259 +/*
10260 + * yaffs_BackgroundGarbageCollect()
10261 + * Garbage collects. Intended to be called from a background thread.
10262 + * Returns non-zero if at least half the free chunks are erased.
10263 + */
10264 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency)
10265 {
10266 + int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
10267
10268 - int chunk;
10269 - __u32 start;
10270 - int nToCopy;
10271 - int n = nBytes;
10272 - int nDone = 0;
10273 - int nToWriteBack;
10274 - int startOfWrite = offset;
10275 - int chunkWritten = 0;
10276 - __u32 nBytesRead;
10277 - __u32 chunkStart;
10278 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10279
10280 - yaffs_Device *dev;
10281 + yaffs_CheckGarbageCollection(dev, 1);
10282 + return erasedChunks > dev->nFreeChunks/2;
10283 +}
10284
10285 - dev = in->myDev;
10286 +/*------------------------- TAGS --------------------------------*/
10287
10288 - while (n > 0 && chunkWritten >= 0) {
10289 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10290 - /* start = offset % dev->nDataBytesPerChunk; */
10291 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10292 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
10293 + int chunkInObject)
10294 +{
10295 + return (tags->chunkId == chunkInObject &&
10296 + tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
10297
10298 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10299 - start >= dev->nDataBytesPerChunk) {
10300 - T(YAFFS_TRACE_ERROR, (
10301 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10302 - TENDSTR),
10303 - (int)offset, chunk, start));
10304 - }
10305 - chunk++;
10306 +}
10307
10308 - /* OK now check for the curveball where the start and end are in
10309 - * the same chunk.
10310 - */
10311
10312 - if ((start + n) < dev->nDataBytesPerChunk) {
10313 - nToCopy = n;
10314 +/*-------------------- Data file manipulation -----------------*/
10315
10316 - /* Now folks, to calculate how many bytes to write back....
10317 - * If we're overwriting and not writing to then end of file then
10318 - * we need to write back as much as was there before.
10319 - */
10320 +static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
10321 + yaffs_ExtendedTags *tags)
10322 +{
10323 + /*Get the Tnode, then get the level 0 offset chunk offset */
10324 + yaffs_Tnode *tn;
10325 + int theChunk = -1;
10326 + yaffs_ExtendedTags localTags;
10327 + int retVal = -1;
10328
10329 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10330 + yaffs_Device *dev = in->myDev;
10331
10332 - if (chunkStart > in->variant.fileVariant.fileSize)
10333 - nBytesRead = 0; /* Past end of file */
10334 - else
10335 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10336 + if (!tags) {
10337 + /* Passed a NULL, so use our own tags space */
10338 + tags = &localTags;
10339 + }
10340
10341 - if (nBytesRead > dev->nDataBytesPerChunk)
10342 - nBytesRead = dev->nDataBytesPerChunk;
10343 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10344
10345 - nToWriteBack =
10346 - (nBytesRead >
10347 - (start + n)) ? nBytesRead : (start + n);
10348 + if (tn) {
10349 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10350
10351 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10352 - YBUG();
10353 + retVal =
10354 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10355 + chunkInInode);
10356 + }
10357 + return retVal;
10358 +}
10359
10360 - } else {
10361 - nToCopy = dev->nDataBytesPerChunk - start;
10362 - nToWriteBack = dev->nDataBytesPerChunk;
10363 - }
10364 +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
10365 + yaffs_ExtendedTags *tags)
10366 +{
10367 + /* Get the Tnode, then get the level 0 offset chunk offset */
10368 + yaffs_Tnode *tn;
10369 + int theChunk = -1;
10370 + yaffs_ExtendedTags localTags;
10371
10372 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10373 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10374 - * or we're using inband tags, so we want to use the cache buffers.
10375 - */
10376 - if (dev->nShortOpCaches > 0) {
10377 - yaffs_ChunkCache *cache;
10378 - /* If we can't find the data in the cache, then load the cache */
10379 - cache = yaffs_FindChunkCache(in, chunk);
10380 + yaffs_Device *dev = in->myDev;
10381 + int retVal = -1;
10382
10383 - if (!cache
10384 - && yaffs_CheckSpaceForAllocation(in->
10385 - myDev)) {
10386 - cache = yaffs_GrabChunkCache(in->myDev);
10387 - cache->object = in;
10388 - cache->chunkId = chunk;
10389 - cache->dirty = 0;
10390 - cache->locked = 0;
10391 - yaffs_ReadChunkDataFromObject(in, chunk,
10392 - cache->
10393 - data);
10394 - } else if (cache &&
10395 - !cache->dirty &&
10396 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10397 - /* Drop the cache if it was a read cache item and
10398 - * no space check has been made for it.
10399 - */
10400 - cache = NULL;
10401 - }
10402 + if (!tags) {
10403 + /* Passed a NULL, so use our own tags space */
10404 + tags = &localTags;
10405 + }
10406
10407 - if (cache) {
10408 - yaffs_UseChunkCache(dev, cache, 1);
10409 - cache->locked = 1;
10410 + tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
10411
10412 + if (tn) {
10413
10414 - memcpy(&cache->data[start], buffer,
10415 - nToCopy);
10416 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10417
10418 + retVal =
10419 + yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
10420 + chunkInInode);
10421
10422 - cache->locked = 0;
10423 - cache->nBytes = nToWriteBack;
10424 + /* Delete the entry in the filestructure (if found) */
10425 + if (retVal != -1)
10426 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
10427 + }
10428
10429 - if (writeThrough) {
10430 - chunkWritten =
10431 - yaffs_WriteChunkDataToObject
10432 - (cache->object,
10433 - cache->chunkId,
10434 - cache->data, cache->nBytes,
10435 - 1);
10436 - cache->dirty = 0;
10437 - }
10438 + return retVal;
10439 +}
10440
10441 - } else {
10442 - chunkWritten = -1; /* fail the write */
10443 - }
10444 - } else {
10445 - /* An incomplete start or end chunk (or maybe both start and end chunk)
10446 - * Read into the local buffer then copy, then copy over and write back.
10447 - */
10448
10449 - __u8 *localBuffer =
10450 - yaffs_GetTempBuffer(dev, __LINE__);
10451 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
10452 + int chunkInNAND, int inScan)
10453 +{
10454 + /* NB inScan is zero unless scanning.
10455 + * For forward scanning, inScan is > 0;
10456 + * for backward scanning inScan is < 0
10457 + *
10458 + * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
10459 + */
10460 +
10461 + yaffs_Tnode *tn;
10462 + yaffs_Device *dev = in->myDev;
10463 + int existingChunk;
10464 + yaffs_ExtendedTags existingTags;
10465 + yaffs_ExtendedTags newTags;
10466 + unsigned existingSerial, newSerial;
10467 +
10468 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
10469 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
10470 + * If it is not during Scanning then something went wrong!
10471 + */
10472 + if (!inScan) {
10473 + T(YAFFS_TRACE_ERROR,
10474 + (TSTR
10475 + ("yaffs tragedy:attempt to put data chunk into a non-file"
10476 + TENDSTR)));
10477 + YBUG();
10478 + }
10479
10480 - yaffs_ReadChunkDataFromObject(in, chunk,
10481 - localBuffer);
10482 + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
10483 + return YAFFS_OK;
10484 + }
10485
10486 + tn = yaffs_AddOrFindLevel0Tnode(dev,
10487 + &in->variant.fileVariant,
10488 + chunkInInode,
10489 + NULL);
10490 + if (!tn)
10491 + return YAFFS_FAIL;
10492 +
10493 + if(!chunkInNAND)
10494 + /* Dummy insert, bail now */
10495 + return YAFFS_OK;
10496
10497 + existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
10498
10499 - memcpy(&localBuffer[start], buffer, nToCopy);
10500 + if (inScan != 0) {
10501 + /* If we're scanning then we need to test for duplicates
10502 + * NB This does not need to be efficient since it should only ever
10503 + * happen when the power fails during a write, then only one
10504 + * chunk should ever be affected.
10505 + *
10506 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
10507 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
10508 + */
10509
10510 - chunkWritten =
10511 - yaffs_WriteChunkDataToObject(in, chunk,
10512 - localBuffer,
10513 - nToWriteBack,
10514 - 0);
10515 + if (existingChunk > 0) {
10516 + /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1
10517 + * thus we have to do a FindChunkInFile to get the real chunk id.
10518 + *
10519 + * We have a duplicate now we need to decide which one to use:
10520 + *
10521 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
10522 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
10523 + * YAFFS1: Get both sets of tags and compare serial numbers.
10524 + */
10525
10526 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10527 - __LINE__);
10528 + if (inScan > 0) {
10529 + /* Only do this for forward scanning */
10530 + yaffs_ReadChunkWithTagsFromNAND(dev,
10531 + chunkInNAND,
10532 + NULL, &newTags);
10533
10534 + /* Do a proper find */
10535 + existingChunk =
10536 + yaffs_FindChunkInFile(in, chunkInInode,
10537 + &existingTags);
10538 }
10539
10540 - } else {
10541 - /* A full chunk. Write directly from the supplied buffer. */
10542 + if (existingChunk <= 0) {
10543 + /*Hoosterman - how did this happen? */
10544
10545 + T(YAFFS_TRACE_ERROR,
10546 + (TSTR
10547 + ("yaffs tragedy: existing chunk < 0 in scan"
10548 + TENDSTR)));
10549
10550 + }
10551
10552 - chunkWritten =
10553 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
10554 - dev->nDataBytesPerChunk,
10555 - 0);
10556 + /* NB The deleted flags should be false, otherwise the chunks will
10557 + * not be loaded during a scan
10558 + */
10559
10560 - /* Since we've overwritten the cached data, we better invalidate it. */
10561 - yaffs_InvalidateChunkCache(in, chunk);
10562 - }
10563 + if (inScan > 0) {
10564 + newSerial = newTags.serialNumber;
10565 + existingSerial = existingTags.serialNumber;
10566 + }
10567
10568 - if (chunkWritten >= 0) {
10569 - n -= nToCopy;
10570 - offset += nToCopy;
10571 - buffer += nToCopy;
10572 - nDone += nToCopy;
10573 + if ((inScan > 0) &&
10574 + (existingChunk <= 0 ||
10575 + ((existingSerial + 1) & 3) == newSerial)) {
10576 + /* Forward scanning.
10577 + * Use new
10578 + * Delete the old one and drop through to update the tnode
10579 + */
10580 + yaffs_DeleteChunk(dev, existingChunk, 1,
10581 + __LINE__);
10582 + } else {
10583 + /* Backward scanning or we want to use the existing one
10584 + * Use existing.
10585 + * Delete the new one and return early so that the tnode isn't changed
10586 + */
10587 + yaffs_DeleteChunk(dev, chunkInNAND, 1,
10588 + __LINE__);
10589 + return YAFFS_OK;
10590 + }
10591 }
10592
10593 }
10594
10595 - /* Update file object */
10596 -
10597 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
10598 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
10599 + if (existingChunk == 0)
10600 + in->nDataChunks++;
10601
10602 - in->dirty = 1;
10603 + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
10604
10605 - return nDone;
10606 + return YAFFS_OK;
10607 }
10608
10609 +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
10610 + __u8 *buffer)
10611 +{
10612 + int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
10613
10614 -/* ---------------------- File resizing stuff ------------------ */
10615 + if (chunkInNAND >= 0)
10616 + return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
10617 + buffer, NULL);
10618 + else {
10619 + T(YAFFS_TRACE_NANDACCESS,
10620 + (TSTR("Chunk %d not found zero instead" TENDSTR),
10621 + chunkInNAND));
10622 + /* get sane (zero) data if you read a hole */
10623 + memset(buffer, 0, in->myDev->nDataBytesPerChunk);
10624 + return 0;
10625 + }
10626
10627 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
10628 -{
10629 +}
10630
10631 - yaffs_Device *dev = in->myDev;
10632 - int oldFileSize = in->variant.fileVariant.fileSize;
10633 +void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
10634 +{
10635 + int block;
10636 + int page;
10637 + yaffs_ExtendedTags tags;
10638 + yaffs_BlockInfo *bi;
10639
10640 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
10641 + if (chunkId <= 0)
10642 + return;
10643
10644 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
10645 - dev->nDataBytesPerChunk;
10646 - int i;
10647 - int chunkId;
10648 + dev->nDeletions++;
10649 + block = chunkId / dev->param.nChunksPerBlock;
10650 + page = chunkId % dev->param.nChunksPerBlock;
10651
10652 - /* Delete backwards so that we don't end up with holes if
10653 - * power is lost part-way through the operation.
10654 - */
10655 - for (i = lastDel; i >= startDel; i--) {
10656 - /* NB this could be optimised somewhat,
10657 - * eg. could retrieve the tags and write them without
10658 - * using yaffs_DeleteChunk
10659 - */
10660
10661 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
10662 - if (chunkId > 0) {
10663 - if (chunkId <
10664 - (dev->internalStartBlock * dev->nChunksPerBlock)
10665 - || chunkId >=
10666 - ((dev->internalEndBlock +
10667 - 1) * dev->nChunksPerBlock)) {
10668 - T(YAFFS_TRACE_ALWAYS,
10669 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
10670 - chunkId, i));
10671 - } else {
10672 - in->nDataChunks--;
10673 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
10674 - }
10675 - }
10676 - }
10677 + if (!yaffs_CheckChunkBit(dev, block, page))
10678 + T(YAFFS_TRACE_VERIFY,
10679 + (TSTR("Deleting invalid chunk %d"TENDSTR),
10680 + chunkId));
10681
10682 -}
10683 + bi = yaffs_GetBlockInfo(dev, block);
10684 +
10685 + yaffs2_UpdateOldestDirtySequence(dev, block, bi);
10686
10687 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
10688 -{
10689 + T(YAFFS_TRACE_DELETION,
10690 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
10691
10692 - int oldFileSize = in->variant.fileVariant.fileSize;
10693 - __u32 newSizeOfPartialChunk;
10694 - int newFullChunks;
10695 + if (!dev->param.isYaffs2 && markNAND &&
10696 + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
10697
10698 - yaffs_Device *dev = in->myDev;
10699 + yaffs_InitialiseTags(&tags);
10700
10701 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
10702 + tags.chunkDeleted = 1;
10703
10704 - yaffs_FlushFilesChunkCache(in);
10705 - yaffs_InvalidateWholeChunkCache(in);
10706 + yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
10707 + yaffs_HandleUpdateChunk(dev, chunkId, &tags);
10708 + } else {
10709 + dev->nUnmarkedDeletions++;
10710 + }
10711
10712 - yaffs_CheckGarbageCollection(dev);
10713 + /* Pull out of the management area.
10714 + * If the whole block became dirty, this will kick off an erasure.
10715 + */
10716 + if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
10717 + bi->blockState == YAFFS_BLOCK_STATE_FULL ||
10718 + bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
10719 + bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
10720 + dev->nFreeChunks++;
10721
10722 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
10723 - return YAFFS_FAIL;
10724 + yaffs_ClearChunkBit(dev, block, page);
10725
10726 - if (newSize == oldFileSize)
10727 - return YAFFS_OK;
10728 + bi->pagesInUse--;
10729
10730 - if (newSize < oldFileSize) {
10731 + if (bi->pagesInUse == 0 &&
10732 + !bi->hasShrinkHeader &&
10733 + bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
10734 + bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
10735 + yaffs_BlockBecameDirty(dev, block);
10736 + }
10737
10738 - yaffs_PruneResizedChunks(in, newSize);
10739 + }
10740
10741 - if (newSizeOfPartialChunk != 0) {
10742 - int lastChunk = 1 + newFullChunks;
10743 +}
10744
10745 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
10746 +static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
10747 + const __u8 *buffer, int nBytes,
10748 + int useReserve)
10749 +{
10750 + /* Find old chunk Need to do this to get serial number
10751 + * Write new one and patch into tree.
10752 + * Invalidate old tags.
10753 + */
10754
10755 - /* Got to read and rewrite the last chunk with its new size and zero pad */
10756 - yaffs_ReadChunkDataFromObject(in, lastChunk,
10757 - localBuffer);
10758 + int prevChunkId;
10759 + yaffs_ExtendedTags prevTags;
10760
10761 - memset(localBuffer + newSizeOfPartialChunk, 0,
10762 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
10763 + int newChunkId;
10764 + yaffs_ExtendedTags newTags;
10765
10766 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
10767 - newSizeOfPartialChunk, 1);
10768 + yaffs_Device *dev = in->myDev;
10769
10770 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
10771 - }
10772 + yaffs_CheckGarbageCollection(dev,0);
10773
10774 - in->variant.fileVariant.fileSize = newSize;
10775 + /* Get the previous chunk at this location in the file if it exists.
10776 + * If it does not exist then put a zero into the tree. This creates
10777 + * the tnode now, rather than later when it is harder to clean up.
10778 + */
10779 + prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
10780 + if(prevChunkId < 1 &&
10781 + !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0))
10782 + return 0;
10783
10784 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
10785 - } else {
10786 - /* newsSize > oldFileSize */
10787 - in->variant.fileVariant.fileSize = newSize;
10788 - }
10789 + /* Set up new tags */
10790 + yaffs_InitialiseTags(&newTags);
10791
10792 + newTags.chunkId = chunkInInode;
10793 + newTags.objectId = in->objectId;
10794 + newTags.serialNumber =
10795 + (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
10796 + newTags.byteCount = nBytes;
10797
10798 - /* Write a new object header.
10799 - * show we've shrunk the file, if need be
10800 - * Do this only if the file is not in the deleted directories.
10801 - */
10802 - if (in->parent &&
10803 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
10804 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
10805 - yaffs_UpdateObjectHeader(in, NULL, 0,
10806 - (newSize < oldFileSize) ? 1 : 0, 0);
10807 + if (nBytes < 1 || nBytes > dev->param.totalBytesPerChunk) {
10808 + T(YAFFS_TRACE_ERROR,
10809 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
10810 + YBUG();
10811 + }
10812 +
10813 +
10814 + newChunkId =
10815 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
10816 + useReserve);
10817
10818 - return YAFFS_OK;
10819 -}
10820 + if (newChunkId > 0) {
10821 + yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
10822
10823 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
10824 -{
10825 - obj = yaffs_GetEquivalentObject(obj);
10826 + if (prevChunkId > 0)
10827 + yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
10828
10829 - switch (obj->variantType) {
10830 - case YAFFS_OBJECT_TYPE_FILE:
10831 - return obj->variant.fileVariant.fileSize;
10832 - case YAFFS_OBJECT_TYPE_SYMLINK:
10833 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
10834 - default:
10835 - return 0;
10836 + yaffs_VerifyFileSanity(in);
10837 }
10838 + return newChunkId;
10839 +
10840 }
10841
10842 +/* UpdateObjectHeader updates the header on NAND for an object.
10843 + * If name is not NULL, then that new name is used.
10844 + */
10845 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
10846 + int isShrink, int shadows, yaffs_XAttrMod *xmod)
10847 +{
10848
10849 + yaffs_BlockInfo *bi;
10850
10851 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
10852 -{
10853 - int retVal;
10854 - if (in->dirty) {
10855 - yaffs_FlushFilesChunkCache(in);
10856 - if (updateTime) {
10857 -#ifdef CONFIG_YAFFS_WINCE
10858 - yfsd_WinFileTimeNow(in->win_mtime);
10859 -#else
10860 + yaffs_Device *dev = in->myDev;
10861
10862 - in->yst_mtime = Y_CURRENT_TIME;
10863 + int prevChunkId;
10864 + int retVal = 0;
10865 + int result = 0;
10866
10867 -#endif
10868 - }
10869 + int newChunkId;
10870 + yaffs_ExtendedTags newTags;
10871 + yaffs_ExtendedTags oldTags;
10872 + const YCHAR *alias = NULL;
10873
10874 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
10875 - 0) ? YAFFS_OK : YAFFS_FAIL;
10876 - } else {
10877 - retVal = YAFFS_OK;
10878 - }
10879 + __u8 *buffer = NULL;
10880 + YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
10881
10882 - return retVal;
10883 + yaffs_ObjectHeader *oh = NULL;
10884
10885 -}
10886 + yaffs_strcpy(oldName, _Y("silly old name"));
10887
10888 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
10889 -{
10890
10891 - /* First off, invalidate the file's data in the cache, without flushing. */
10892 - yaffs_InvalidateWholeChunkCache(in);
10893 + if (!in->fake ||
10894 + in == dev->rootDir || /* The rootDir should also be saved */
10895 + force || xmod) {
10896
10897 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
10898 - /* Move to the unlinked directory so we have a record that it was deleted. */
10899 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
10900 + yaffs_CheckGarbageCollection(dev,0);
10901 + yaffs_CheckObjectDetailsLoaded(in);
10902
10903 - }
10904 + buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
10905 + oh = (yaffs_ObjectHeader *) buffer;
10906
10907 - yaffs_RemoveObjectFromDirectory(in);
10908 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
10909 - in->hdrChunk = 0;
10910 + prevChunkId = in->hdrChunk;
10911
10912 - yaffs_FreeObject(in);
10913 - return YAFFS_OK;
10914 + if (prevChunkId > 0) {
10915 + result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
10916 + buffer, &oldTags);
10917
10918 -}
10919 + yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
10920
10921 -/* yaffs_DeleteFile deletes the whole file data
10922 - * and the inode associated with the file.
10923 - * It does not delete the links associated with the file.
10924 - */
10925 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
10926 -{
10927 + memcpy(oldName, oh->name, sizeof(oh->name));
10928 + memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader));
10929 + } else
10930 + memset(buffer, 0xFF, dev->nDataBytesPerChunk);
10931
10932 - int retVal;
10933 - int immediateDeletion = 0;
10934 + oh->type = in->variantType;
10935 + oh->yst_mode = in->yst_mode;
10936 + oh->shadowsObject = oh->inbandShadowsObject = shadows;
10937
10938 -#ifdef __KERNEL__
10939 - if (!in->myInode)
10940 - immediateDeletion = 1;
10941 +#ifdef CONFIG_YAFFS_WINCE
10942 + oh->win_atime[0] = in->win_atime[0];
10943 + oh->win_ctime[0] = in->win_ctime[0];
10944 + oh->win_mtime[0] = in->win_mtime[0];
10945 + oh->win_atime[1] = in->win_atime[1];
10946 + oh->win_ctime[1] = in->win_ctime[1];
10947 + oh->win_mtime[1] = in->win_mtime[1];
10948 #else
10949 - if (in->inUse <= 0)
10950 - immediateDeletion = 1;
10951 + oh->yst_uid = in->yst_uid;
10952 + oh->yst_gid = in->yst_gid;
10953 + oh->yst_atime = in->yst_atime;
10954 + oh->yst_mtime = in->yst_mtime;
10955 + oh->yst_ctime = in->yst_ctime;
10956 + oh->yst_rdev = in->yst_rdev;
10957 #endif
10958 + if (in->parent)
10959 + oh->parentObjectId = in->parent->objectId;
10960 + else
10961 + oh->parentObjectId = 0;
10962
10963 - if (immediateDeletion) {
10964 - retVal =
10965 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
10966 - _Y("deleted"), 0, 0);
10967 - T(YAFFS_TRACE_TRACING,
10968 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
10969 - in->objectId));
10970 - in->deleted = 1;
10971 - in->myDev->nDeletedFiles++;
10972 - if (1 || in->myDev->isYaffs2)
10973 - yaffs_ResizeFile(in, 0);
10974 - yaffs_SoftDeleteFile(in);
10975 - } else {
10976 - retVal =
10977 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
10978 - _Y("unlinked"), 0, 0);
10979 - }
10980 + if (name && *name) {
10981 + memset(oh->name, 0, sizeof(oh->name));
10982 + yaffs_LoadObjectHeaderFromName(dev,oh->name,name);
10983 + } else if (prevChunkId > 0)
10984 + memcpy(oh->name, oldName, sizeof(oh->name));
10985 + else
10986 + memset(oh->name, 0, sizeof(oh->name));
10987
10988 + oh->isShrink = isShrink;
10989
10990 - return retVal;
10991 -}
10992 + switch (in->variantType) {
10993 + case YAFFS_OBJECT_TYPE_UNKNOWN:
10994 + /* Should not happen */
10995 + break;
10996 + case YAFFS_OBJECT_TYPE_FILE:
10997 + oh->fileSize =
10998 + (oh->parentObjectId == YAFFS_OBJECTID_DELETED
10999 + || oh->parentObjectId ==
11000 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
11001 + fileVariant.fileSize;
11002 + break;
11003 + case YAFFS_OBJECT_TYPE_HARDLINK:
11004 + oh->equivalentObjectId =
11005 + in->variant.hardLinkVariant.equivalentObjectId;
11006 + break;
11007 + case YAFFS_OBJECT_TYPE_SPECIAL:
11008 + /* Do nothing */
11009 + break;
11010 + case YAFFS_OBJECT_TYPE_DIRECTORY:
11011 + /* Do nothing */
11012 + break;
11013 + case YAFFS_OBJECT_TYPE_SYMLINK:
11014 + alias = in->variant.symLinkVariant.alias;
11015 + if(!alias)
11016 + alias = _Y("no alias");
11017 + yaffs_strncpy(oh->alias,
11018 + alias,
11019 + YAFFS_MAX_ALIAS_LENGTH);
11020 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11021 + break;
11022 + }
11023
11024 -int yaffs_DeleteFile(yaffs_Object *in)
11025 -{
11026 - int retVal = YAFFS_OK;
11027 - int deleted = in->deleted;
11028 + /* process any xattrib modifications */
11029 + if(xmod)
11030 + yaffs_ApplyXMod(in, (char *)buffer, xmod);
11031
11032 - yaffs_ResizeFile(in, 0);
11033
11034 - if (in->nDataChunks > 0) {
11035 - /* Use soft deletion if there is data in the file.
11036 - * That won't be the case if it has been resized to zero.
11037 - */
11038 - if (!in->unlinked)
11039 - retVal = yaffs_UnlinkFileIfNeeded(in);
11040 + /* Tags */
11041 + yaffs_InitialiseTags(&newTags);
11042 + in->serial++;
11043 + newTags.chunkId = 0;
11044 + newTags.objectId = in->objectId;
11045 + newTags.serialNumber = in->serial;
11046
11047 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11048 - in->deleted = 1;
11049 - deleted = 1;
11050 - in->myDev->nDeletedFiles++;
11051 - yaffs_SoftDeleteFile(in);
11052 - }
11053 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11054 - } else {
11055 - /* The file has no data chunks so we toss it immediately */
11056 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11057 - in->variant.fileVariant.top = NULL;
11058 - yaffs_DoGenericObjectDeletion(in);
11059 + /* Add extra info for file header */
11060
11061 - return YAFFS_OK;
11062 - }
11063 -}
11064 + newTags.extraHeaderInfoAvailable = 1;
11065 + newTags.extraParentObjectId = oh->parentObjectId;
11066 + newTags.extraFileLength = oh->fileSize;
11067 + newTags.extraIsShrinkHeader = oh->isShrink;
11068 + newTags.extraEquivalentObjectId = oh->equivalentObjectId;
11069 + newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
11070 + newTags.extraObjectType = in->variantType;
11071
11072 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11073 -{
11074 - /* First check that the directory is empty. */
11075 - if (ylist_empty(&in->variant.directoryVariant.children))
11076 - return yaffs_DoGenericObjectDeletion(in);
11077 + yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
11078
11079 - return YAFFS_FAIL;
11080 + /* Create new chunk in NAND */
11081 + newChunkId =
11082 + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
11083 + (prevChunkId > 0) ? 1 : 0);
11084
11085 -}
11086 + if (newChunkId >= 0) {
11087
11088 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11089 -{
11090 - YFREE(in->variant.symLinkVariant.alias);
11091 + in->hdrChunk = newChunkId;
11092
11093 - return yaffs_DoGenericObjectDeletion(in);
11094 -}
11095 + if (prevChunkId > 0) {
11096 + yaffs_DeleteChunk(dev, prevChunkId, 1,
11097 + __LINE__);
11098 + }
11099
11100 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11101 -{
11102 - /* remove this hardlink from the list assocaited with the equivalent
11103 - * object
11104 - */
11105 - ylist_del_init(&in->hardLinks);
11106 - return yaffs_DoGenericObjectDeletion(in);
11107 -}
11108 + if (!yaffs_ObjectHasCachedWriteData(in))
11109 + in->dirty = 0;
11110 +
11111 + /* If this was a shrink, then mark the block that the chunk lives on */
11112 + if (isShrink) {
11113 + bi = yaffs_GetBlockInfo(in->myDev,
11114 + newChunkId / in->myDev->param.nChunksPerBlock);
11115 + bi->hasShrinkHeader = 1;
11116 + }
11117 +
11118 + }
11119 +
11120 + retVal = newChunkId;
11121
11122 -int yaffs_DeleteObject(yaffs_Object *obj)
11123 -{
11124 -int retVal = -1;
11125 - switch (obj->variantType) {
11126 - case YAFFS_OBJECT_TYPE_FILE:
11127 - retVal = yaffs_DeleteFile(obj);
11128 - break;
11129 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11130 - return yaffs_DeleteDirectory(obj);
11131 - break;
11132 - case YAFFS_OBJECT_TYPE_SYMLINK:
11133 - retVal = yaffs_DeleteSymLink(obj);
11134 - break;
11135 - case YAFFS_OBJECT_TYPE_HARDLINK:
11136 - retVal = yaffs_DeleteHardLink(obj);
11137 - break;
11138 - case YAFFS_OBJECT_TYPE_SPECIAL:
11139 - retVal = yaffs_DoGenericObjectDeletion(obj);
11140 - break;
11141 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11142 - retVal = 0;
11143 - break; /* should not happen. */
11144 }
11145
11146 + if (buffer)
11147 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
11148 +
11149 return retVal;
11150 }
11151
11152 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11153 +/*------------------------ Short Operations Cache ----------------------------------------
11154 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11155 + * reads might be short sequential reads, and a lot of writes may be short
11156 + * sequential writes. eg. scanning/writing a jpeg file.
11157 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11158 + * with dumb-as-a-rock code.
11159 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11160 + * buffering.
11161 + *
11162 + * There are a limited number (~10) of cache chunks per device so that we don't
11163 + * need a very intelligent search.
11164 + */
11165 +
11166 +static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
11167 {
11168 + yaffs_Device *dev = obj->myDev;
11169 + int i;
11170 + yaffs_ChunkCache *cache;
11171 + int nCaches = obj->myDev->param.nShortOpCaches;
11172
11173 - int immediateDeletion = 0;
11174 + for (i = 0; i < nCaches; i++) {
11175 + cache = &dev->srCache[i];
11176 + if (cache->object == obj &&
11177 + cache->dirty)
11178 + return 1;
11179 + }
11180
11181 -#ifdef __KERNEL__
11182 - if (!obj->myInode)
11183 - immediateDeletion = 1;
11184 -#else
11185 - if (obj->inUse <= 0)
11186 - immediateDeletion = 1;
11187 -#endif
11188 + return 0;
11189 +}
11190
11191 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11192 - return yaffs_DeleteHardLink(obj);
11193 - } else if (!ylist_empty(&obj->hardLinks)) {
11194 - /* Curve ball: We're unlinking an object that has a hardlink.
11195 - *
11196 - * This problem arises because we are not strictly following
11197 - * The Linux link/inode model.
11198 - *
11199 - * We can't really delete the object.
11200 - * Instead, we do the following:
11201 - * - Select a hardlink.
11202 - * - Unhook it from the hard links
11203 - * - Unhook it from its parent directory (so that the rename can work)
11204 - * - Rename the object to the hardlink's name.
11205 - * - Delete the hardlink
11206 - */
11207
11208 - yaffs_Object *hl;
11209 - int retVal;
11210 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11211 +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
11212 +{
11213 + yaffs_Device *dev = obj->myDev;
11214 + int lowest = -99; /* Stop compiler whining. */
11215 + int i;
11216 + yaffs_ChunkCache *cache;
11217 + int chunkWritten = 0;
11218 + int nCaches = obj->myDev->param.nShortOpCaches;
11219
11220 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11221 + if (nCaches > 0) {
11222 + do {
11223 + cache = NULL;
11224
11225 - ylist_del_init(&hl->hardLinks);
11226 - ylist_del_init(&hl->siblings);
11227 + /* Find the dirty cache for this object with the lowest chunk id. */
11228 + for (i = 0; i < nCaches; i++) {
11229 + if (dev->srCache[i].object == obj &&
11230 + dev->srCache[i].dirty) {
11231 + if (!cache
11232 + || dev->srCache[i].chunkId <
11233 + lowest) {
11234 + cache = &dev->srCache[i];
11235 + lowest = cache->chunkId;
11236 + }
11237 + }
11238 + }
11239
11240 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11241 + if (cache && !cache->locked) {
11242 + /* Write it out and free it up */
11243
11244 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11245 + chunkWritten =
11246 + yaffs_WriteChunkDataToObject(cache->object,
11247 + cache->chunkId,
11248 + cache->data,
11249 + cache->nBytes,
11250 + 1);
11251 + cache->dirty = 0;
11252 + cache->object = NULL;
11253 + }
11254
11255 - if (retVal == YAFFS_OK)
11256 - retVal = yaffs_DoGenericObjectDeletion(hl);
11257 + } while (cache && chunkWritten > 0);
11258
11259 - return retVal;
11260 + if (cache) {
11261 + /* Hoosterman, disk full while writing cache out. */
11262 + T(YAFFS_TRACE_ERROR,
11263 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11264
11265 - } else if (immediateDeletion) {
11266 - switch (obj->variantType) {
11267 - case YAFFS_OBJECT_TYPE_FILE:
11268 - return yaffs_DeleteFile(obj);
11269 - break;
11270 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11271 - return yaffs_DeleteDirectory(obj);
11272 - break;
11273 - case YAFFS_OBJECT_TYPE_SYMLINK:
11274 - return yaffs_DeleteSymLink(obj);
11275 - break;
11276 - case YAFFS_OBJECT_TYPE_SPECIAL:
11277 - return yaffs_DoGenericObjectDeletion(obj);
11278 - break;
11279 - case YAFFS_OBJECT_TYPE_HARDLINK:
11280 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11281 - default:
11282 - return YAFFS_FAIL;
11283 }
11284 - } else
11285 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11286 - _Y("unlinked"), 0, 0);
11287 + }
11288 +
11289 }
11290
11291 +/*yaffs_FlushEntireDeviceCache(dev)
11292 + *
11293 + *
11294 + */
11295
11296 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11297 +void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
11298 {
11299 + yaffs_Object *obj;
11300 + int nCaches = dev->param.nShortOpCaches;
11301 + int i;
11302
11303 - if (obj && obj->unlinkAllowed)
11304 - return yaffs_UnlinkWorker(obj);
11305 + /* Find a dirty object in the cache and flush it...
11306 + * until there are no further dirty objects.
11307 + */
11308 + do {
11309 + obj = NULL;
11310 + for (i = 0; i < nCaches && !obj; i++) {
11311 + if (dev->srCache[i].object &&
11312 + dev->srCache[i].dirty)
11313 + obj = dev->srCache[i].object;
11314
11315 - return YAFFS_FAIL;
11316 + }
11317 + if (obj)
11318 + yaffs_FlushFilesChunkCache(obj);
11319 +
11320 + } while (obj);
11321
11322 }
11323 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11324 +
11325 +
11326 +/* Grab us a cache chunk for use.
11327 + * First look for an empty one.
11328 + * Then look for the least recently used non-dirty one.
11329 + * Then look for the least recently used dirty one...., flush and look again.
11330 + */
11331 +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
11332 {
11333 - yaffs_Object *obj;
11334 + int i;
11335
11336 - obj = yaffs_FindObjectByName(dir, name);
11337 - return yaffs_UnlinkObject(obj);
11338 -}
11339 + if (dev->param.nShortOpCaches > 0) {
11340 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11341 + if (!dev->srCache[i].object)
11342 + return &dev->srCache[i];
11343 + }
11344 + }
11345
11346 -/*----------------------- Initialisation Scanning ---------------------- */
11347 + return NULL;
11348 +}
11349
11350 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11351 - int backwardScanning)
11352 +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
11353 {
11354 - yaffs_Object *obj;
11355 + yaffs_ChunkCache *cache;
11356 + yaffs_Object *theObj;
11357 + int usage;
11358 + int i;
11359 + int pushout;
11360
11361 - if (!backwardScanning) {
11362 - /* Handle YAFFS1 forward scanning case
11363 - * For YAFFS1 we always do the deletion
11364 - */
11365 + if (dev->param.nShortOpCaches > 0) {
11366 + /* Try find a non-dirty one... */
11367
11368 - } else {
11369 - /* Handle YAFFS2 case (backward scanning)
11370 - * If the shadowed object exists then ignore.
11371 - */
11372 - if (yaffs_FindObjectByNumber(dev, objId))
11373 - return;
11374 - }
11375 + cache = yaffs_GrabChunkCacheWorker(dev);
11376
11377 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11378 - * We put it in unlinked dir to be cleaned up after the scanning
11379 - */
11380 - obj =
11381 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11382 - YAFFS_OBJECT_TYPE_FILE);
11383 - if (!obj)
11384 - return;
11385 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11386 - obj->variant.fileVariant.shrinkSize = 0;
11387 - obj->valid = 1; /* So that we don't read any other info for this file */
11388 + if (!cache) {
11389 + /* They were all dirty, find the last recently used object and flush
11390 + * its cache, then find again.
11391 + * NB what's here is not very accurate, we actually flush the object
11392 + * the last recently used page.
11393 + */
11394
11395 -}
11396 + /* With locking we can't assume we can use entry zero */
11397
11398 -typedef struct {
11399 - int seq;
11400 - int block;
11401 -} yaffs_BlockIndex;
11402 + theObj = NULL;
11403 + usage = -1;
11404 + cache = NULL;
11405 + pushout = -1;
11406
11407 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11408 + if (dev->srCache[i].object &&
11409 + !dev->srCache[i].locked &&
11410 + (dev->srCache[i].lastUse < usage || !cache)) {
11411 + usage = dev->srCache[i].lastUse;
11412 + theObj = dev->srCache[i].object;
11413 + cache = &dev->srCache[i];
11414 + pushout = i;
11415 + }
11416 + }
11417
11418 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
11419 -{
11420 - yaffs_Object *hl;
11421 - yaffs_Object *in;
11422 + if (!cache || cache->dirty) {
11423 + /* Flush and try again */
11424 + yaffs_FlushFilesChunkCache(theObj);
11425 + cache = yaffs_GrabChunkCacheWorker(dev);
11426 + }
11427
11428 - while (hardList) {
11429 - hl = hardList;
11430 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
11431 + }
11432 + return cache;
11433 + } else
11434 + return NULL;
11435
11436 - in = yaffs_FindObjectByNumber(dev,
11437 - hl->variant.hardLinkVariant.
11438 - equivalentObjectId);
11439 +}
11440
11441 - if (in) {
11442 - /* Add the hardlink pointers */
11443 - hl->variant.hardLinkVariant.equivalentObject = in;
11444 - ylist_add(&hl->hardLinks, &in->hardLinks);
11445 - } else {
11446 - /* Todo Need to report/handle this better.
11447 - * Got a problem... hardlink to a non-existant object
11448 - */
11449 - hl->variant.hardLinkVariant.equivalentObject = NULL;
11450 - YINIT_LIST_HEAD(&hl->hardLinks);
11451 +/* Find a cached chunk */
11452 +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
11453 + int chunkId)
11454 +{
11455 + yaffs_Device *dev = obj->myDev;
11456 + int i;
11457 + if (dev->param.nShortOpCaches > 0) {
11458 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11459 + if (dev->srCache[i].object == obj &&
11460 + dev->srCache[i].chunkId == chunkId) {
11461 + dev->cacheHits++;
11462
11463 + return &dev->srCache[i];
11464 + }
11465 }
11466 }
11467 + return NULL;
11468 }
11469
11470 +/* Mark the chunk for the least recently used algorithym */
11471 +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
11472 + int isAWrite)
11473 +{
11474 +
11475 + if (dev->param.nShortOpCaches > 0) {
11476 + if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
11477 + /* Reset the cache usages */
11478 + int i;
11479 + for (i = 1; i < dev->param.nShortOpCaches; i++)
11480 + dev->srCache[i].lastUse = 0;
11481
11482 + dev->srLastUse = 0;
11483 + }
11484
11485 + dev->srLastUse++;
11486
11487 + cache->lastUse = dev->srLastUse;
11488
11489 -static int ybicmp(const void *a, const void *b)
11490 -{
11491 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
11492 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
11493 - register int ablock = ((yaffs_BlockIndex *)a)->block;
11494 - register int bblock = ((yaffs_BlockIndex *)b)->block;
11495 - if (aseq == bseq)
11496 - return ablock - bblock;
11497 - else
11498 - return aseq - bseq;
11499 + if (isAWrite)
11500 + cache->dirty = 1;
11501 + }
11502 }
11503
11504 +/* Invalidate a single cache page.
11505 + * Do this when a whole page gets written,
11506 + * ie the short cache for this page is no longer valid.
11507 + */
11508 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
11509 +{
11510 + if (object->myDev->param.nShortOpCaches > 0) {
11511 + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
11512
11513 -struct yaffs_ShadowFixerStruct {
11514 - int objectId;
11515 - int shadowedId;
11516 - struct yaffs_ShadowFixerStruct *next;
11517 -};
11518 -
11519 + if (cache)
11520 + cache->object = NULL;
11521 + }
11522 +}
11523
11524 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
11525 +/* Invalidate all the cache pages associated with this object
11526 + * Do this whenever ther file is deleted or resized.
11527 + */
11528 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
11529 {
11530 - /*
11531 - * Sort out state of unlinked and deleted objects after scanning.
11532 - */
11533 - struct ylist_head *i;
11534 - struct ylist_head *n;
11535 - yaffs_Object *l;
11536 + int i;
11537 + yaffs_Device *dev = in->myDev;
11538
11539 - /* Soft delete all the unlinked files */
11540 - ylist_for_each_safe(i, n,
11541 - &dev->unlinkedDir->variant.directoryVariant.children) {
11542 - if (i) {
11543 - l = ylist_entry(i, yaffs_Object, siblings);
11544 - yaffs_DeleteObject(l);
11545 + if (dev->param.nShortOpCaches > 0) {
11546 + /* Invalidate it. */
11547 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
11548 + if (dev->srCache[i].object == in)
11549 + dev->srCache[i].object = NULL;
11550 }
11551 }
11552 +}
11553
11554 - ylist_for_each_safe(i, n,
11555 - &dev->deletedDir->variant.directoryVariant.children) {
11556 - if (i) {
11557 - l = ylist_entry(i, yaffs_Object, siblings);
11558 - yaffs_DeleteObject(l);
11559 - }
11560 - }
11561
11562 -}
11563 +/*--------------------- File read/write ------------------------
11564 + * Read and write have very similar structures.
11565 + * In general the read/write has three parts to it
11566 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
11567 + * Some complete chunks
11568 + * An incomplete chunk to end off with
11569 + *
11570 + * Curve-balls: the first chunk might also be the last chunk.
11571 + */
11572
11573 -static int yaffs_Scan(yaffs_Device *dev)
11574 +int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
11575 + int nBytes)
11576 {
11577 - yaffs_ExtendedTags tags;
11578 - int blk;
11579 - int blockIterator;
11580 - int startIterator;
11581 - int endIterator;
11582 - int result;
11583
11584 int chunk;
11585 - int c;
11586 - int deleted;
11587 - yaffs_BlockState state;
11588 - yaffs_Object *hardList = NULL;
11589 - yaffs_BlockInfo *bi;
11590 - __u32 sequenceNumber;
11591 - yaffs_ObjectHeader *oh;
11592 - yaffs_Object *in;
11593 - yaffs_Object *parent;
11594 -
11595 - int alloc_failed = 0;
11596 + __u32 start;
11597 + int nToCopy;
11598 + int n = nBytes;
11599 + int nDone = 0;
11600 + yaffs_ChunkCache *cache;
11601
11602 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
11603 + yaffs_Device *dev;
11604
11605 + dev = in->myDev;
11606
11607 - __u8 *chunkData;
11608 + while (n > 0) {
11609 + /* chunk = offset / dev->nDataBytesPerChunk + 1; */
11610 + /* start = offset % dev->nDataBytesPerChunk; */
11611 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11612 + chunk++;
11613
11614 + /* OK now check for the curveball where the start and end are in
11615 + * the same chunk.
11616 + */
11617 + if ((start + n) < dev->nDataBytesPerChunk)
11618 + nToCopy = n;
11619 + else
11620 + nToCopy = dev->nDataBytesPerChunk - start;
11621
11622 + cache = yaffs_FindChunkCache(in, chunk);
11623
11624 - T(YAFFS_TRACE_SCAN,
11625 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
11626 - dev->internalStartBlock, dev->internalEndBlock));
11627 -
11628 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
11629 -
11630 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
11631 -
11632 - /* Scan all the blocks to determine their state */
11633 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
11634 - bi = yaffs_GetBlockInfo(dev, blk);
11635 - yaffs_ClearChunkBits(dev, blk);
11636 - bi->pagesInUse = 0;
11637 - bi->softDeletions = 0;
11638 + /* If the chunk is already in the cache or it is less than a whole chunk
11639 + * or we're using inband tags then use the cache (if there is caching)
11640 + * else bypass the cache.
11641 + */
11642 + if (cache || nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11643 + if (dev->param.nShortOpCaches > 0) {
11644
11645 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
11646 + /* If we can't find the data in the cache, then load it up. */
11647
11648 - bi->blockState = state;
11649 - bi->sequenceNumber = sequenceNumber;
11650 + if (!cache) {
11651 + cache = yaffs_GrabChunkCache(in->myDev);
11652 + cache->object = in;
11653 + cache->chunkId = chunk;
11654 + cache->dirty = 0;
11655 + cache->locked = 0;
11656 + yaffs_ReadChunkDataFromObject(in, chunk,
11657 + cache->
11658 + data);
11659 + cache->nBytes = 0;
11660 + }
11661
11662 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
11663 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
11664 + yaffs_UseChunkCache(dev, cache, 0);
11665
11666 - T(YAFFS_TRACE_SCAN_DEBUG,
11667 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
11668 - state, sequenceNumber));
11669 + cache->locked = 1;
11670
11671 - if (state == YAFFS_BLOCK_STATE_DEAD) {
11672 - T(YAFFS_TRACE_BAD_BLOCKS,
11673 - (TSTR("block %d is bad" TENDSTR), blk));
11674 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
11675 - T(YAFFS_TRACE_SCAN_DEBUG,
11676 - (TSTR("Block empty " TENDSTR)));
11677 - dev->nErasedBlocks++;
11678 - dev->nFreeChunks += dev->nChunksPerBlock;
11679 - }
11680 - }
11681
11682 - startIterator = dev->internalStartBlock;
11683 - endIterator = dev->internalEndBlock;
11684 + memcpy(buffer, &cache->data[start], nToCopy);
11685
11686 - /* For each block.... */
11687 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
11688 - blockIterator++) {
11689 + cache->locked = 0;
11690 + } else {
11691 + /* Read into the local buffer then copy..*/
11692
11693 - YYIELD();
11694 + __u8 *localBuffer =
11695 + yaffs_GetTempBuffer(dev, __LINE__);
11696 + yaffs_ReadChunkDataFromObject(in, chunk,
11697 + localBuffer);
11698
11699 - YYIELD();
11700 + memcpy(buffer, &localBuffer[start], nToCopy);
11701
11702 - blk = blockIterator;
11703
11704 - bi = yaffs_GetBlockInfo(dev, blk);
11705 - state = bi->blockState;
11706 + yaffs_ReleaseTempBuffer(dev, localBuffer,
11707 + __LINE__);
11708 + }
11709
11710 - deleted = 0;
11711 + } else {
11712
11713 - /* For each chunk in each block that needs scanning....*/
11714 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
11715 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
11716 - /* Read the tags and decide what to do */
11717 - chunk = blk * dev->nChunksPerBlock + c;
11718 + /* A full chunk. Read directly into the supplied buffer. */
11719 + yaffs_ReadChunkDataFromObject(in, chunk, buffer);
11720
11721 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
11722 - &tags);
11723 + }
11724
11725 - /* Let's have a good look at this chunk... */
11726 + n -= nToCopy;
11727 + offset += nToCopy;
11728 + buffer += nToCopy;
11729 + nDone += nToCopy;
11730
11731 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
11732 - /* YAFFS1 only...
11733 - * A deleted chunk
11734 - */
11735 - deleted++;
11736 - dev->nFreeChunks++;
11737 - /*T((" %d %d deleted\n",blk,c)); */
11738 - } else if (!tags.chunkUsed) {
11739 - /* An unassigned chunk in the block
11740 - * This means that either the block is empty or
11741 - * this is the one being allocated from
11742 - */
11743 + }
11744
11745 - if (c == 0) {
11746 - /* We're looking at the first chunk in the block so the block is unused */
11747 - state = YAFFS_BLOCK_STATE_EMPTY;
11748 - dev->nErasedBlocks++;
11749 - } else {
11750 - /* this is the block being allocated from */
11751 - T(YAFFS_TRACE_SCAN,
11752 - (TSTR
11753 - (" Allocating from %d %d" TENDSTR),
11754 - blk, c));
11755 - state = YAFFS_BLOCK_STATE_ALLOCATING;
11756 - dev->allocationBlock = blk;
11757 - dev->allocationPage = c;
11758 - dev->allocationBlockFinder = blk;
11759 - /* Set it to here to encourage the allocator to go forth from here. */
11760 + return nDone;
11761 +}
11762
11763 - }
11764 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
11765 + int nBytes, int writeThrough)
11766 +{
11767
11768 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
11769 - } else if (tags.chunkId > 0) {
11770 - /* chunkId > 0 so it is a data chunk... */
11771 - unsigned int endpos;
11772 -
11773 - yaffs_SetChunkBit(dev, blk, c);
11774 - bi->pagesInUse++;
11775 -
11776 - in = yaffs_FindOrCreateObjectByNumber(dev,
11777 - tags.
11778 - objectId,
11779 - YAFFS_OBJECT_TYPE_FILE);
11780 - /* PutChunkIntoFile checks for a clash (two data chunks with
11781 - * the same chunkId).
11782 - */
11783 + int chunk;
11784 + __u32 start;
11785 + int nToCopy;
11786 + int n = nBytes;
11787 + int nDone = 0;
11788 + int nToWriteBack;
11789 + int startOfWrite = offset;
11790 + int chunkWritten = 0;
11791 + __u32 nBytesRead;
11792 + __u32 chunkStart;
11793
11794 - if (!in)
11795 - alloc_failed = 1;
11796 + yaffs_Device *dev;
11797
11798 - if (in) {
11799 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
11800 - alloc_failed = 1;
11801 - }
11802 + dev = in->myDev;
11803
11804 - endpos =
11805 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
11806 - tags.byteCount;
11807 - if (in &&
11808 - in->variantType == YAFFS_OBJECT_TYPE_FILE
11809 - && in->variant.fileVariant.scannedFileSize <
11810 - endpos) {
11811 - in->variant.fileVariant.
11812 - scannedFileSize = endpos;
11813 - if (!dev->useHeaderFileSize) {
11814 - in->variant.fileVariant.
11815 - fileSize =
11816 - in->variant.fileVariant.
11817 - scannedFileSize;
11818 - }
11819 + while (n > 0 && chunkWritten >= 0) {
11820 + yaffs_AddrToChunk(dev, offset, &chunk, &start);
11821
11822 - }
11823 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
11824 - } else {
11825 - /* chunkId == 0, so it is an ObjectHeader.
11826 - * Thus, we read in the object header and make the object
11827 - */
11828 - yaffs_SetChunkBit(dev, blk, c);
11829 - bi->pagesInUse++;
11830 + if (chunk * dev->nDataBytesPerChunk + start != offset ||
11831 + start >= dev->nDataBytesPerChunk) {
11832 + T(YAFFS_TRACE_ERROR, (
11833 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
11834 + TENDSTR),
11835 + (int)offset, chunk, start));
11836 + }
11837 + chunk++; /* File pos to chunk in file offset */
11838
11839 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
11840 - chunkData,
11841 - NULL);
11842 -
11843 - oh = (yaffs_ObjectHeader *) chunkData;
11844 -
11845 - in = yaffs_FindObjectByNumber(dev,
11846 - tags.objectId);
11847 - if (in && in->variantType != oh->type) {
11848 - /* This should not happen, but somehow
11849 - * Wev'e ended up with an objectId that has been reused but not yet
11850 - * deleted, and worse still it has changed type. Delete the old object.
11851 - */
11852 + /* OK now check for the curveball where the start and end are in
11853 + * the same chunk.
11854 + */
11855
11856 - yaffs_DeleteObject(in);
11857 + if ((start + n) < dev->nDataBytesPerChunk) {
11858 + nToCopy = n;
11859
11860 - in = 0;
11861 - }
11862 + /* Now folks, to calculate how many bytes to write back....
11863 + * If we're overwriting and not writing to then end of file then
11864 + * we need to write back as much as was there before.
11865 + */
11866
11867 - in = yaffs_FindOrCreateObjectByNumber(dev,
11868 - tags.
11869 - objectId,
11870 - oh->type);
11871 -
11872 - if (!in)
11873 - alloc_failed = 1;
11874 -
11875 - if (in && oh->shadowsObject > 0) {
11876 -
11877 - struct yaffs_ShadowFixerStruct *fixer;
11878 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
11879 - if (fixer) {
11880 - fixer->next = shadowFixerList;
11881 - shadowFixerList = fixer;
11882 - fixer->objectId = tags.objectId;
11883 - fixer->shadowedId = oh->shadowsObject;
11884 - }
11885 + chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
11886
11887 - }
11888 + if (chunkStart > in->variant.fileVariant.fileSize)
11889 + nBytesRead = 0; /* Past end of file */
11890 + else
11891 + nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
11892
11893 - if (in && in->valid) {
11894 - /* We have already filled this one. We have a duplicate and need to resolve it. */
11895 + if (nBytesRead > dev->nDataBytesPerChunk)
11896 + nBytesRead = dev->nDataBytesPerChunk;
11897
11898 - unsigned existingSerial = in->serial;
11899 - unsigned newSerial = tags.serialNumber;
11900 + nToWriteBack =
11901 + (nBytesRead >
11902 + (start + n)) ? nBytesRead : (start + n);
11903
11904 - if (((existingSerial + 1) & 3) == newSerial) {
11905 - /* Use new one - destroy the exisiting one */
11906 - yaffs_DeleteChunk(dev,
11907 - in->hdrChunk,
11908 - 1, __LINE__);
11909 - in->valid = 0;
11910 - } else {
11911 - /* Use existing - destroy this one. */
11912 - yaffs_DeleteChunk(dev, chunk, 1,
11913 - __LINE__);
11914 - }
11915 - }
11916 + if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
11917 + YBUG();
11918
11919 - if (in && !in->valid &&
11920 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
11921 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
11922 - /* We only load some info, don't fiddle with directory structure */
11923 - in->valid = 1;
11924 - in->variantType = oh->type;
11925 + } else {
11926 + nToCopy = dev->nDataBytesPerChunk - start;
11927 + nToWriteBack = dev->nDataBytesPerChunk;
11928 + }
11929
11930 - in->yst_mode = oh->yst_mode;
11931 -#ifdef CONFIG_YAFFS_WINCE
11932 - in->win_atime[0] = oh->win_atime[0];
11933 - in->win_ctime[0] = oh->win_ctime[0];
11934 - in->win_mtime[0] = oh->win_mtime[0];
11935 - in->win_atime[1] = oh->win_atime[1];
11936 - in->win_ctime[1] = oh->win_ctime[1];
11937 - in->win_mtime[1] = oh->win_mtime[1];
11938 -#else
11939 - in->yst_uid = oh->yst_uid;
11940 - in->yst_gid = oh->yst_gid;
11941 - in->yst_atime = oh->yst_atime;
11942 - in->yst_mtime = oh->yst_mtime;
11943 - in->yst_ctime = oh->yst_ctime;
11944 - in->yst_rdev = oh->yst_rdev;
11945 -#endif
11946 - in->hdrChunk = chunk;
11947 - in->serial = tags.serialNumber;
11948 + if (nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) {
11949 + /* An incomplete start or end chunk (or maybe both start and end chunk),
11950 + * or we're using inband tags, so we want to use the cache buffers.
11951 + */
11952 + if (dev->param.nShortOpCaches > 0) {
11953 + yaffs_ChunkCache *cache;
11954 + /* If we can't find the data in the cache, then load the cache */
11955 + cache = yaffs_FindChunkCache(in, chunk);
11956
11957 - } else if (in && !in->valid) {
11958 - /* we need to load this info */
11959 + if (!cache
11960 + && yaffs_CheckSpaceForAllocation(dev, 1)) {
11961 + cache = yaffs_GrabChunkCache(dev);
11962 + cache->object = in;
11963 + cache->chunkId = chunk;
11964 + cache->dirty = 0;
11965 + cache->locked = 0;
11966 + yaffs_ReadChunkDataFromObject(in, chunk,
11967 + cache->data);
11968 + } else if (cache &&
11969 + !cache->dirty &&
11970 + !yaffs_CheckSpaceForAllocation(dev, 1)) {
11971 + /* Drop the cache if it was a read cache item and
11972 + * no space check has been made for it.
11973 + */
11974 + cache = NULL;
11975 + }
11976
11977 - in->valid = 1;
11978 - in->variantType = oh->type;
11979 + if (cache) {
11980 + yaffs_UseChunkCache(dev, cache, 1);
11981 + cache->locked = 1;
11982
11983 - in->yst_mode = oh->yst_mode;
11984 -#ifdef CONFIG_YAFFS_WINCE
11985 - in->win_atime[0] = oh->win_atime[0];
11986 - in->win_ctime[0] = oh->win_ctime[0];
11987 - in->win_mtime[0] = oh->win_mtime[0];
11988 - in->win_atime[1] = oh->win_atime[1];
11989 - in->win_ctime[1] = oh->win_ctime[1];
11990 - in->win_mtime[1] = oh->win_mtime[1];
11991 -#else
11992 - in->yst_uid = oh->yst_uid;
11993 - in->yst_gid = oh->yst_gid;
11994 - in->yst_atime = oh->yst_atime;
11995 - in->yst_mtime = oh->yst_mtime;
11996 - in->yst_ctime = oh->yst_ctime;
11997 - in->yst_rdev = oh->yst_rdev;
11998 -#endif
11999 - in->hdrChunk = chunk;
12000 - in->serial = tags.serialNumber;
12001
12002 - yaffs_SetObjectName(in, oh->name);
12003 - in->dirty = 0;
12004 + memcpy(&cache->data[start], buffer,
12005 + nToCopy);
12006
12007 - /* directory stuff...
12008 - * hook up to parent
12009 - */
12010
12011 - parent =
12012 - yaffs_FindOrCreateObjectByNumber
12013 - (dev, oh->parentObjectId,
12014 - YAFFS_OBJECT_TYPE_DIRECTORY);
12015 - if (!parent)
12016 - alloc_failed = 1;
12017 - if (parent && parent->variantType ==
12018 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12019 - /* Set up as a directory */
12020 - parent->variantType =
12021 - YAFFS_OBJECT_TYPE_DIRECTORY;
12022 - YINIT_LIST_HEAD(&parent->variant.
12023 - directoryVariant.
12024 - children);
12025 - } else if (!parent || parent->variantType !=
12026 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12027 - /* Hoosterman, another problem....
12028 - * We're trying to use a non-directory as a directory
12029 - */
12030 + cache->locked = 0;
12031 + cache->nBytes = nToWriteBack;
12032
12033 - T(YAFFS_TRACE_ERROR,
12034 - (TSTR
12035 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12036 - TENDSTR)));
12037 - parent = dev->lostNFoundDir;
12038 + if (writeThrough) {
12039 + chunkWritten =
12040 + yaffs_WriteChunkDataToObject
12041 + (cache->object,
12042 + cache->chunkId,
12043 + cache->data, cache->nBytes,
12044 + 1);
12045 + cache->dirty = 0;
12046 }
12047
12048 - yaffs_AddObjectToDirectory(parent, in);
12049 + } else {
12050 + chunkWritten = -1; /* fail the write */
12051 + }
12052 + } else {
12053 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12054 + * Read into the local buffer then copy, then copy over and write back.
12055 + */
12056
12057 - if (0 && (parent == dev->deletedDir ||
12058 - parent == dev->unlinkedDir)) {
12059 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12060 - dev->nDeletedFiles++;
12061 - }
12062 - /* Note re hardlinks.
12063 - * Since we might scan a hardlink before its equivalent object is scanned
12064 - * we put them all in a list.
12065 - * After scanning is complete, we should have all the objects, so we run through this
12066 - * list and fix up all the chains.
12067 - */
12068 + __u8 *localBuffer =
12069 + yaffs_GetTempBuffer(dev, __LINE__);
12070
12071 - switch (in->variantType) {
12072 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12073 - /* Todo got a problem */
12074 - break;
12075 - case YAFFS_OBJECT_TYPE_FILE:
12076 - if (dev->useHeaderFileSize)
12077 -
12078 - in->variant.fileVariant.
12079 - fileSize =
12080 - oh->fileSize;
12081 -
12082 - break;
12083 - case YAFFS_OBJECT_TYPE_HARDLINK:
12084 - in->variant.hardLinkVariant.
12085 - equivalentObjectId =
12086 - oh->equivalentObjectId;
12087 - in->hardLinks.next =
12088 - (struct ylist_head *)
12089 - hardList;
12090 - hardList = in;
12091 - break;
12092 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12093 - /* Do nothing */
12094 - break;
12095 - case YAFFS_OBJECT_TYPE_SPECIAL:
12096 - /* Do nothing */
12097 - break;
12098 - case YAFFS_OBJECT_TYPE_SYMLINK:
12099 - in->variant.symLinkVariant.alias =
12100 - yaffs_CloneString(oh->alias);
12101 - if (!in->variant.symLinkVariant.alias)
12102 - alloc_failed = 1;
12103 - break;
12104 - }
12105 + yaffs_ReadChunkDataFromObject(in, chunk,
12106 + localBuffer);
12107
12108 -/*
12109 - if (parent == dev->deletedDir) {
12110 - yaffs_DestroyObject(in);
12111 - bi->hasShrinkHeader = 1;
12112 - }
12113 -*/
12114 - }
12115 - }
12116 - }
12117
12118 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12119 - /* If we got this far while scanning, then the block is fully allocated.*/
12120 - state = YAFFS_BLOCK_STATE_FULL;
12121 - }
12122
12123 - bi->blockState = state;
12124 + memcpy(&localBuffer[start], buffer, nToCopy);
12125
12126 - /* Now let's see if it was dirty */
12127 - if (bi->pagesInUse == 0 &&
12128 - !bi->hasShrinkHeader &&
12129 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12130 - yaffs_BlockBecameDirty(dev, blk);
12131 - }
12132 + chunkWritten =
12133 + yaffs_WriteChunkDataToObject(in, chunk,
12134 + localBuffer,
12135 + nToWriteBack,
12136 + 0);
12137
12138 - }
12139 + yaffs_ReleaseTempBuffer(dev, localBuffer,
12140 + __LINE__);
12141
12142 + }
12143
12144 - /* Ok, we've done all the scanning.
12145 - * Fix up the hard link chains.
12146 - * We should now have scanned all the objects, now it's time to add these
12147 - * hardlinks.
12148 - */
12149 + } else {
12150 + /* A full chunk. Write directly from the supplied buffer. */
12151
12152 - yaffs_HardlinkFixup(dev, hardList);
12153
12154 - /* Fix up any shadowed objects */
12155 - {
12156 - struct yaffs_ShadowFixerStruct *fixer;
12157 - yaffs_Object *obj;
12158 -
12159 - while (shadowFixerList) {
12160 - fixer = shadowFixerList;
12161 - shadowFixerList = fixer->next;
12162 - /* Complete the rename transaction by deleting the shadowed object
12163 - * then setting the object header to unshadowed.
12164 - */
12165 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12166 - if (obj)
12167 - yaffs_DeleteObject(obj);
12168
12169 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12170 + chunkWritten =
12171 + yaffs_WriteChunkDataToObject(in, chunk, buffer,
12172 + dev->nDataBytesPerChunk,
12173 + 0);
12174
12175 - if (obj)
12176 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12177 + /* Since we've overwritten the cached data, we better invalidate it. */
12178 + yaffs_InvalidateChunkCache(in, chunk);
12179 + }
12180
12181 - YFREE(fixer);
12182 + if (chunkWritten >= 0) {
12183 + n -= nToCopy;
12184 + offset += nToCopy;
12185 + buffer += nToCopy;
12186 + nDone += nToCopy;
12187 }
12188 - }
12189
12190 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12191 + }
12192
12193 - if (alloc_failed)
12194 - return YAFFS_FAIL;
12195 + /* Update file object */
12196
12197 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12198 + if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
12199 + in->variant.fileVariant.fileSize = (startOfWrite + nDone);
12200
12201 + in->dirty = 1;
12202
12203 - return YAFFS_OK;
12204 + return nDone;
12205 }
12206
12207 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12208 +int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
12209 + int nBytes, int writeThrough)
12210 {
12211 - __u8 *chunkData;
12212 - yaffs_ObjectHeader *oh;
12213 - yaffs_Device *dev;
12214 - yaffs_ExtendedTags tags;
12215 - int result;
12216 - int alloc_failed = 0;
12217 + yaffs2_HandleHole(in,offset);
12218 + return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
12219 +}
12220
12221 - if (!in)
12222 - return;
12223
12224 - dev = in->myDev;
12225
12226 -#if 0
12227 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12228 - in->objectId,
12229 - in->lazyLoaded ? "not yet" : "already"));
12230 -#endif
12231 +/* ---------------------- File resizing stuff ------------------ */
12232
12233 - if (in->lazyLoaded && in->hdrChunk > 0) {
12234 - in->lazyLoaded = 0;
12235 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12236 +static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
12237 +{
12238
12239 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12240 - oh = (yaffs_ObjectHeader *) chunkData;
12241 + yaffs_Device *dev = in->myDev;
12242 + int oldFileSize = in->variant.fileVariant.fileSize;
12243
12244 - in->yst_mode = oh->yst_mode;
12245 -#ifdef CONFIG_YAFFS_WINCE
12246 - in->win_atime[0] = oh->win_atime[0];
12247 - in->win_ctime[0] = oh->win_ctime[0];
12248 - in->win_mtime[0] = oh->win_mtime[0];
12249 - in->win_atime[1] = oh->win_atime[1];
12250 - in->win_ctime[1] = oh->win_ctime[1];
12251 - in->win_mtime[1] = oh->win_mtime[1];
12252 -#else
12253 - in->yst_uid = oh->yst_uid;
12254 - in->yst_gid = oh->yst_gid;
12255 - in->yst_atime = oh->yst_atime;
12256 - in->yst_mtime = oh->yst_mtime;
12257 - in->yst_ctime = oh->yst_ctime;
12258 - in->yst_rdev = oh->yst_rdev;
12259 + int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
12260
12261 -#endif
12262 - yaffs_SetObjectName(in, oh->name);
12263 + int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
12264 + dev->nDataBytesPerChunk;
12265 + int i;
12266 + int chunkId;
12267
12268 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12269 - in->variant.symLinkVariant.alias =
12270 - yaffs_CloneString(oh->alias);
12271 - if (!in->variant.symLinkVariant.alias)
12272 - alloc_failed = 1; /* Not returned to caller */
12273 - }
12274 + /* Delete backwards so that we don't end up with holes if
12275 + * power is lost part-way through the operation.
12276 + */
12277 + for (i = lastDel; i >= startDel; i--) {
12278 + /* NB this could be optimised somewhat,
12279 + * eg. could retrieve the tags and write them without
12280 + * using yaffs_DeleteChunk
12281 + */
12282
12283 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12284 + chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
12285 + if (chunkId > 0) {
12286 + if (chunkId <
12287 + (dev->internalStartBlock * dev->param.nChunksPerBlock)
12288 + || chunkId >=
12289 + ((dev->internalEndBlock +
12290 + 1) * dev->param.nChunksPerBlock)) {
12291 + T(YAFFS_TRACE_ALWAYS,
12292 + (TSTR("Found daft chunkId %d for %d" TENDSTR),
12293 + chunkId, i));
12294 + } else {
12295 + in->nDataChunks--;
12296 + yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
12297 + }
12298 + }
12299 }
12300 +
12301 }
12302
12303 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12304 +
12305 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize)
12306 {
12307 - yaffs_ExtendedTags tags;
12308 - int blk;
12309 - int blockIterator;
12310 - int startIterator;
12311 - int endIterator;
12312 - int nBlocksToScan = 0;
12313 + int newFullChunks;
12314 + __u32 newSizeOfPartialChunk;
12315 + yaffs_Device *dev = obj->myDev;
12316
12317 - int chunk;
12318 - int result;
12319 - int c;
12320 - int deleted;
12321 - yaffs_BlockState state;
12322 - yaffs_Object *hardList = NULL;
12323 - yaffs_BlockInfo *bi;
12324 - __u32 sequenceNumber;
12325 - yaffs_ObjectHeader *oh;
12326 - yaffs_Object *in;
12327 - yaffs_Object *parent;
12328 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12329 - int itsUnlinked;
12330 - __u8 *chunkData;
12331 + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
12332
12333 - int fileSize;
12334 - int isShrink;
12335 - int foundChunksInBlock;
12336 - int equivalentObjectId;
12337 - int alloc_failed = 0;
12338 + yaffs_PruneResizedChunks(obj, newSize);
12339
12340 + if (newSizeOfPartialChunk != 0) {
12341 + int lastChunk = 1 + newFullChunks;
12342 + __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
12343
12344 - yaffs_BlockIndex *blockIndex = NULL;
12345 - int altBlockIndex = 0;
12346 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12347 + yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer);
12348 + memset(localBuffer + newSizeOfPartialChunk, 0,
12349 + dev->nDataBytesPerChunk - newSizeOfPartialChunk);
12350
12351 - if (!dev->isYaffs2) {
12352 - T(YAFFS_TRACE_SCAN,
12353 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12354 - return YAFFS_FAIL;
12355 + yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer,
12356 + newSizeOfPartialChunk, 1);
12357 +
12358 + yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
12359 }
12360
12361 - T(YAFFS_TRACE_SCAN,
12362 - (TSTR
12363 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12364 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12365 + obj->variant.fileVariant.fileSize = newSize;
12366 +
12367 + yaffs_PruneFileStructure(dev, &obj->variant.fileVariant);
12368 +}
12369
12370
12371 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12372 +int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
12373 +{
12374 + yaffs_Device *dev = in->myDev;
12375 + int oldFileSize = in->variant.fileVariant.fileSize;
12376
12377 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12378 + yaffs_FlushFilesChunkCache(in);
12379 + yaffs_InvalidateWholeChunkCache(in);
12380
12381 - if (!blockIndex) {
12382 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12383 - altBlockIndex = 1;
12384 - }
12385 + yaffs_CheckGarbageCollection(dev,0);
12386
12387 - if (!blockIndex) {
12388 - T(YAFFS_TRACE_SCAN,
12389 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
12390 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
12391 return YAFFS_FAIL;
12392 - }
12393
12394 - dev->blocksInCheckpoint = 0;
12395 + if (newSize == oldFileSize)
12396 + return YAFFS_OK;
12397 +
12398 + if(newSize > oldFileSize){
12399 + yaffs2_HandleHole(in,newSize);
12400 + in->variant.fileVariant.fileSize = newSize;
12401 + } else {
12402 + /* newSize < oldFileSize */
12403 + yaffs_ResizeDown(in, newSize);
12404 + }
12405 +
12406 + /* Write a new object header to reflect the resize.
12407 + * show we've shrunk the file, if need be
12408 + * Do this only if the file is not in the deleted directories
12409 + * and is not shadowed.
12410 + */
12411 + if (in->parent &&
12412 + !in->isShadowed &&
12413 + in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
12414 + in->parent->objectId != YAFFS_OBJECTID_DELETED)
12415 + yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL);
12416 +
12417
12418 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12419 + return YAFFS_OK;
12420 +}
12421
12422 - /* Scan all the blocks to determine their state */
12423 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12424 - bi = yaffs_GetBlockInfo(dev, blk);
12425 - yaffs_ClearChunkBits(dev, blk);
12426 - bi->pagesInUse = 0;
12427 - bi->softDeletions = 0;
12428 +loff_t yaffs_GetFileSize(yaffs_Object *obj)
12429 +{
12430 + YCHAR *alias = NULL;
12431 + obj = yaffs_GetEquivalentObject(obj);
12432 +
12433 + switch (obj->variantType) {
12434 + case YAFFS_OBJECT_TYPE_FILE:
12435 + return obj->variant.fileVariant.fileSize;
12436 + case YAFFS_OBJECT_TYPE_SYMLINK:
12437 + alias = obj->variant.symLinkVariant.alias;
12438 + if(!alias)
12439 + return 0;
12440 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
12441 + default:
12442 + return 0;
12443 + }
12444 +}
12445
12446 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12447
12448 - bi->blockState = state;
12449 - bi->sequenceNumber = sequenceNumber;
12450
12451 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
12452 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
12453 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12454 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12455 +int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
12456 +{
12457 + int retVal;
12458 + if (in->dirty) {
12459 + yaffs_FlushFilesChunkCache(in);
12460 + if(dataSync) /* Only sync data */
12461 + retVal=YAFFS_OK;
12462 + else {
12463 + if (updateTime) {
12464 +#ifdef CONFIG_YAFFS_WINCE
12465 + yfsd_WinFileTimeNow(in->win_mtime);
12466 +#else
12467
12468 - T(YAFFS_TRACE_SCAN_DEBUG,
12469 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12470 - state, sequenceNumber));
12471 + in->yst_mtime = Y_CURRENT_TIME;
12472
12473 +#endif
12474 + }
12475
12476 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
12477 - dev->blocksInCheckpoint++;
12478 + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >=
12479 + 0) ? YAFFS_OK : YAFFS_FAIL;
12480 + }
12481 + } else {
12482 + retVal = YAFFS_OK;
12483 + }
12484
12485 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
12486 - T(YAFFS_TRACE_BAD_BLOCKS,
12487 - (TSTR("block %d is bad" TENDSTR), blk));
12488 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12489 - T(YAFFS_TRACE_SCAN_DEBUG,
12490 - (TSTR("Block empty " TENDSTR)));
12491 - dev->nErasedBlocks++;
12492 - dev->nFreeChunks += dev->nChunksPerBlock;
12493 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12494 + return retVal;
12495
12496 - /* Determine the highest sequence number */
12497 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
12498 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
12499 +}
12500
12501 - blockIndex[nBlocksToScan].seq = sequenceNumber;
12502 - blockIndex[nBlocksToScan].block = blk;
12503 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
12504 +{
12505
12506 - nBlocksToScan++;
12507 + /* First off, invalidate the file's data in the cache, without flushing. */
12508 + yaffs_InvalidateWholeChunkCache(in);
12509
12510 - if (sequenceNumber >= dev->sequenceNumber)
12511 - dev->sequenceNumber = sequenceNumber;
12512 - } else {
12513 - /* TODO: Nasty sequence number! */
12514 - T(YAFFS_TRACE_SCAN,
12515 - (TSTR
12516 - ("Block scanning block %d has bad sequence number %d"
12517 - TENDSTR), blk, sequenceNumber));
12518 + if (in->myDev->param.isYaffs2 && (in->parent != in->myDev->deletedDir)) {
12519 + /* Move to the unlinked directory so we have a record that it was deleted. */
12520 + yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
12521
12522 - }
12523 - }
12524 }
12525
12526 - T(YAFFS_TRACE_SCAN,
12527 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
12528 + yaffs_RemoveObjectFromDirectory(in);
12529 + yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
12530 + in->hdrChunk = 0;
12531
12532 + yaffs_FreeObject(in);
12533 + return YAFFS_OK;
12534
12535 +}
12536
12537 - YYIELD();
12538 +/* yaffs_DeleteFile deletes the whole file data
12539 + * and the inode associated with the file.
12540 + * It does not delete the links associated with the file.
12541 + */
12542 +static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
12543 +{
12544
12545 - /* Sort the blocks */
12546 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
12547 - {
12548 - /* Use qsort now. */
12549 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
12550 - }
12551 -#else
12552 - {
12553 - /* Dungy old bubble sort... */
12554 + int retVal;
12555 + int immediateDeletion = 0;
12556 + yaffs_Device *dev = in->myDev;
12557
12558 - yaffs_BlockIndex temp;
12559 - int i;
12560 - int j;
12561 + if (!in->myInode)
12562 + immediateDeletion = 1;
12563
12564 - for (i = 0; i < nBlocksToScan; i++)
12565 - for (j = i + 1; j < nBlocksToScan; j++)
12566 - if (blockIndex[i].seq > blockIndex[j].seq) {
12567 - temp = blockIndex[j];
12568 - blockIndex[j] = blockIndex[i];
12569 - blockIndex[i] = temp;
12570 - }
12571 + if (immediateDeletion) {
12572 + retVal =
12573 + yaffs_ChangeObjectName(in, in->myDev->deletedDir,
12574 + _Y("deleted"), 0, 0);
12575 + T(YAFFS_TRACE_TRACING,
12576 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
12577 + in->objectId));
12578 + in->deleted = 1;
12579 + in->myDev->nDeletedFiles++;
12580 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12581 + yaffs_ResizeFile(in, 0);
12582 + yaffs_SoftDeleteFile(in);
12583 + } else {
12584 + retVal =
12585 + yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
12586 + _Y("unlinked"), 0, 0);
12587 }
12588 -#endif
12589
12590 - YYIELD();
12591
12592 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
12593 + return retVal;
12594 +}
12595 +
12596 +int yaffs_DeleteFile(yaffs_Object *in)
12597 +{
12598 + int retVal = YAFFS_OK;
12599 + int deleted; /* Need to cache value on stack if in is freed */
12600 + yaffs_Device *dev = in->myDev;
12601 +
12602 + if (dev->param.disableSoftDelete || dev->param.isYaffs2)
12603 + yaffs_ResizeFile(in, 0);
12604 +
12605 + if (in->nDataChunks > 0) {
12606 + /* Use soft deletion if there is data in the file.
12607 + * That won't be the case if it has been resized to zero.
12608 + */
12609 + if (!in->unlinked)
12610 + retVal = yaffs_UnlinkFileIfNeeded(in);
12611
12612 - /* Now scan the blocks looking at the data. */
12613 - startIterator = 0;
12614 - endIterator = nBlocksToScan - 1;
12615 - T(YAFFS_TRACE_SCAN_DEBUG,
12616 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
12617 + deleted = in->deleted;
12618
12619 - /* For each block.... backwards */
12620 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
12621 - blockIterator--) {
12622 - /* Cooperative multitasking! This loop can run for so
12623 - long that watchdog timers expire. */
12624 - YYIELD();
12625 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
12626 + in->deleted = 1;
12627 + deleted = 1;
12628 + in->myDev->nDeletedFiles++;
12629 + yaffs_SoftDeleteFile(in);
12630 + }
12631 + return deleted ? YAFFS_OK : YAFFS_FAIL;
12632 + } else {
12633 + /* The file has no data chunks so we toss it immediately */
12634 + yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
12635 + in->variant.fileVariant.top = NULL;
12636 + yaffs_DoGenericObjectDeletion(in);
12637
12638 - /* get the block to scan in the correct order */
12639 - blk = blockIndex[blockIterator].block;
12640 + return YAFFS_OK;
12641 + }
12642 +}
12643
12644 - bi = yaffs_GetBlockInfo(dev, blk);
12645 +static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
12646 +{
12647 + return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
12648 + !(ylist_empty(&obj->variant.directoryVariant.children));
12649 +}
12650
12651 +static int yaffs_DeleteDirectory(yaffs_Object *obj)
12652 +{
12653 + /* First check that the directory is empty. */
12654 + if (yaffs_IsNonEmptyDirectory(obj))
12655 + return YAFFS_FAIL;
12656
12657 - state = bi->blockState;
12658 + return yaffs_DoGenericObjectDeletion(obj);
12659 +}
12660
12661 - deleted = 0;
12662 +static int yaffs_DeleteSymLink(yaffs_Object *in)
12663 +{
12664 + if(in->variant.symLinkVariant.alias)
12665 + YFREE(in->variant.symLinkVariant.alias);
12666 + in->variant.symLinkVariant.alias=NULL;
12667
12668 - /* For each chunk in each block that needs scanning.... */
12669 - foundChunksInBlock = 0;
12670 - for (c = dev->nChunksPerBlock - 1;
12671 - !alloc_failed && c >= 0 &&
12672 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12673 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
12674 - /* Scan backwards...
12675 - * Read the tags and decide what to do
12676 - */
12677 + return yaffs_DoGenericObjectDeletion(in);
12678 +}
12679
12680 - chunk = blk * dev->nChunksPerBlock + c;
12681 +static int yaffs_DeleteHardLink(yaffs_Object *in)
12682 +{
12683 + /* remove this hardlink from the list assocaited with the equivalent
12684 + * object
12685 + */
12686 + ylist_del_init(&in->hardLinks);
12687 + return yaffs_DoGenericObjectDeletion(in);
12688 +}
12689
12690 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12691 - &tags);
12692 +int yaffs_DeleteObject(yaffs_Object *obj)
12693 +{
12694 +int retVal = -1;
12695 + switch (obj->variantType) {
12696 + case YAFFS_OBJECT_TYPE_FILE:
12697 + retVal = yaffs_DeleteFile(obj);
12698 + break;
12699 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12700 + if(!ylist_empty(&obj->variant.directoryVariant.dirty)){
12701 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->objectId));
12702 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12703 + }
12704 + return yaffs_DeleteDirectory(obj);
12705 + break;
12706 + case YAFFS_OBJECT_TYPE_SYMLINK:
12707 + retVal = yaffs_DeleteSymLink(obj);
12708 + break;
12709 + case YAFFS_OBJECT_TYPE_HARDLINK:
12710 + retVal = yaffs_DeleteHardLink(obj);
12711 + break;
12712 + case YAFFS_OBJECT_TYPE_SPECIAL:
12713 + retVal = yaffs_DoGenericObjectDeletion(obj);
12714 + break;
12715 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12716 + retVal = 0;
12717 + break; /* should not happen. */
12718 + }
12719
12720 - /* Let's have a good look at this chunk... */
12721 + return retVal;
12722 +}
12723
12724 - if (!tags.chunkUsed) {
12725 - /* An unassigned chunk in the block.
12726 - * If there are used chunks after this one, then
12727 - * it is a chunk that was skipped due to failing the erased
12728 - * check. Just skip it so that it can be deleted.
12729 - * But, more typically, We get here when this is an unallocated
12730 - * chunk and his means that either the block is empty or
12731 - * this is the one being allocated from
12732 - */
12733 +static int yaffs_UnlinkWorker(yaffs_Object *obj)
12734 +{
12735
12736 - if (foundChunksInBlock) {
12737 - /* This is a chunk that was skipped due to failing the erased check */
12738 - } else if (c == 0) {
12739 - /* We're looking at the first chunk in the block so the block is unused */
12740 - state = YAFFS_BLOCK_STATE_EMPTY;
12741 - dev->nErasedBlocks++;
12742 - } else {
12743 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
12744 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
12745 - if (dev->sequenceNumber == bi->sequenceNumber) {
12746 - /* this is the block being allocated from */
12747 -
12748 - T(YAFFS_TRACE_SCAN,
12749 - (TSTR
12750 - (" Allocating from %d %d"
12751 - TENDSTR), blk, c));
12752 -
12753 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12754 - dev->allocationBlock = blk;
12755 - dev->allocationPage = c;
12756 - dev->allocationBlockFinder = blk;
12757 - } else {
12758 - /* This is a partially written block that is not
12759 - * the current allocation block. This block must have
12760 - * had a write failure, so set up for retirement.
12761 - */
12762 -
12763 - /* bi->needsRetiring = 1; ??? TODO */
12764 - bi->gcPrioritise = 1;
12765 -
12766 - T(YAFFS_TRACE_ALWAYS,
12767 - (TSTR("Partially written block %d detected" TENDSTR),
12768 - blk));
12769 - }
12770 - }
12771 - }
12772 + int immediateDeletion = 0;
12773
12774 - dev->nFreeChunks++;
12775 + if (!obj->myInode)
12776 + immediateDeletion = 1;
12777
12778 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
12779 - T(YAFFS_TRACE_SCAN,
12780 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
12781 - blk, c));
12782 -
12783 - dev->nFreeChunks++;
12784 -
12785 - } else if (tags.chunkId > 0) {
12786 - /* chunkId > 0 so it is a data chunk... */
12787 - unsigned int endpos;
12788 - __u32 chunkBase =
12789 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
12790 -
12791 - foundChunksInBlock = 1;
12792 -
12793 -
12794 - yaffs_SetChunkBit(dev, blk, c);
12795 - bi->pagesInUse++;
12796 -
12797 - in = yaffs_FindOrCreateObjectByNumber(dev,
12798 - tags.
12799 - objectId,
12800 - YAFFS_OBJECT_TYPE_FILE);
12801 - if (!in) {
12802 - /* Out of memory */
12803 - alloc_failed = 1;
12804 - }
12805 + if(obj)
12806 + yaffs_UpdateParent(obj->parent);
12807
12808 - if (in &&
12809 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12810 - && chunkBase <
12811 - in->variant.fileVariant.shrinkSize) {
12812 - /* This has not been invalidated by a resize */
12813 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
12814 - chunk, -1)) {
12815 - alloc_failed = 1;
12816 - }
12817 + if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
12818 + return yaffs_DeleteHardLink(obj);
12819 + } else if (!ylist_empty(&obj->hardLinks)) {
12820 + /* Curve ball: We're unlinking an object that has a hardlink.
12821 + *
12822 + * This problem arises because we are not strictly following
12823 + * The Linux link/inode model.
12824 + *
12825 + * We can't really delete the object.
12826 + * Instead, we do the following:
12827 + * - Select a hardlink.
12828 + * - Unhook it from the hard links
12829 + * - Move it from its parent directory (so that the rename can work)
12830 + * - Rename the object to the hardlink's name.
12831 + * - Delete the hardlink
12832 + */
12833
12834 - /* File size is calculated by looking at the data chunks if we have not
12835 - * seen an object header yet. Stop this practice once we find an object header.
12836 - */
12837 - endpos =
12838 - (tags.chunkId -
12839 - 1) * dev->nDataBytesPerChunk +
12840 - tags.byteCount;
12841 -
12842 - if (!in->valid && /* have not got an object header yet */
12843 - in->variant.fileVariant.
12844 - scannedFileSize < endpos) {
12845 - in->variant.fileVariant.
12846 - scannedFileSize = endpos;
12847 - in->variant.fileVariant.
12848 - fileSize =
12849 - in->variant.fileVariant.
12850 - scannedFileSize;
12851 - }
12852 + yaffs_Object *hl;
12853 + yaffs_Object *parent;
12854 + int retVal;
12855 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
12856
12857 - } else if (in) {
12858 - /* This chunk has been invalidated by a resize, so delete */
12859 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
12860 + hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
12861
12862 - }
12863 - } else {
12864 - /* chunkId == 0, so it is an ObjectHeader.
12865 - * Thus, we read in the object header and make the object
12866 - */
12867 - foundChunksInBlock = 1;
12868 + yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
12869 + parent = hl->parent;
12870
12871 - yaffs_SetChunkBit(dev, blk, c);
12872 - bi->pagesInUse++;
12873 + ylist_del_init(&hl->hardLinks);
12874
12875 - oh = NULL;
12876 - in = NULL;
12877 + yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl);
12878
12879 - if (tags.extraHeaderInfoAvailable) {
12880 - in = yaffs_FindOrCreateObjectByNumber
12881 - (dev, tags.objectId,
12882 - tags.extraObjectType);
12883 - if (!in)
12884 - alloc_failed = 1;
12885 - }
12886 + retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0);
12887
12888 - if (!in ||
12889 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
12890 - !in->valid ||
12891 -#endif
12892 - tags.extraShadows ||
12893 - (!in->valid &&
12894 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12895 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
12896 -
12897 - /* If we don't have valid info then we need to read the chunk
12898 - * TODO In future we can probably defer reading the chunk and
12899 - * living with invalid data until needed.
12900 - */
12901 + if (retVal == YAFFS_OK)
12902 + retVal = yaffs_DoGenericObjectDeletion(hl);
12903
12904 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
12905 - chunk,
12906 - chunkData,
12907 - NULL);
12908 -
12909 - oh = (yaffs_ObjectHeader *) chunkData;
12910 -
12911 - if (dev->inbandTags) {
12912 - /* Fix up the header if they got corrupted by inband tags */
12913 - oh->shadowsObject = oh->inbandShadowsObject;
12914 - oh->isShrink = oh->inbandIsShrink;
12915 - }
12916 + return retVal;
12917
12918 - if (!in) {
12919 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
12920 - if (!in)
12921 - alloc_failed = 1;
12922 - }
12923 + } else if (immediateDeletion) {
12924 + switch (obj->variantType) {
12925 + case YAFFS_OBJECT_TYPE_FILE:
12926 + return yaffs_DeleteFile(obj);
12927 + break;
12928 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12929 + ylist_del_init(&obj->variant.directoryVariant.dirty);
12930 + return yaffs_DeleteDirectory(obj);
12931 + break;
12932 + case YAFFS_OBJECT_TYPE_SYMLINK:
12933 + return yaffs_DeleteSymLink(obj);
12934 + break;
12935 + case YAFFS_OBJECT_TYPE_SPECIAL:
12936 + return yaffs_DoGenericObjectDeletion(obj);
12937 + break;
12938 + case YAFFS_OBJECT_TYPE_HARDLINK:
12939 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12940 + default:
12941 + return YAFFS_FAIL;
12942 + }
12943 + } else if(yaffs_IsNonEmptyDirectory(obj))
12944 + return YAFFS_FAIL;
12945 + else
12946 + return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
12947 + _Y("unlinked"), 0, 0);
12948 +}
12949
12950 - }
12951
12952 - if (!in) {
12953 - /* TODO Hoosterman we have a problem! */
12954 - T(YAFFS_TRACE_ERROR,
12955 - (TSTR
12956 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
12957 - TENDSTR), tags.objectId, chunk));
12958 - continue;
12959 - }
12960 +static int yaffs_UnlinkObject(yaffs_Object *obj)
12961 +{
12962
12963 - if (in->valid) {
12964 - /* We have already filled this one.
12965 - * We have a duplicate that will be discarded, but
12966 - * we first have to suck out resize info if it is a file.
12967 - */
12968 + if (obj && obj->unlinkAllowed)
12969 + return yaffs_UnlinkWorker(obj);
12970
12971 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
12972 - ((oh &&
12973 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
12974 - (tags.extraHeaderInfoAvailable &&
12975 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
12976 - __u32 thisSize =
12977 - (oh) ? oh->fileSize : tags.
12978 - extraFileLength;
12979 - __u32 parentObjectId =
12980 - (oh) ? oh->
12981 - parentObjectId : tags.
12982 - extraParentObjectId;
12983 -
12984 -
12985 - isShrink =
12986 - (oh) ? oh->isShrink : tags.
12987 - extraIsShrinkHeader;
12988 + return YAFFS_FAIL;
12989
12990 - /* If it is deleted (unlinked at start also means deleted)
12991 - * we treat the file size as being zeroed at this point.
12992 - */
12993 - if (parentObjectId ==
12994 - YAFFS_OBJECTID_DELETED
12995 - || parentObjectId ==
12996 - YAFFS_OBJECTID_UNLINKED) {
12997 - thisSize = 0;
12998 - isShrink = 1;
12999 - }
13000 +}
13001 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
13002 +{
13003 + yaffs_Object *obj;
13004
13005 - if (isShrink &&
13006 - in->variant.fileVariant.
13007 - shrinkSize > thisSize) {
13008 - in->variant.fileVariant.
13009 - shrinkSize =
13010 - thisSize;
13011 - }
13012 + obj = yaffs_FindObjectByName(dir, name);
13013 + return yaffs_UnlinkObject(obj);
13014 +}
13015
13016 - if (isShrink)
13017 - bi->hasShrinkHeader = 1;
13018 +/*----------------------- Initialisation Scanning ---------------------- */
13019
13020 - }
13021 - /* Use existing - destroy this one. */
13022 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13023 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
13024 + int backwardScanning)
13025 +{
13026 + yaffs_Object *obj;
13027
13028 - }
13029 + if (!backwardScanning) {
13030 + /* Handle YAFFS1 forward scanning case
13031 + * For YAFFS1 we always do the deletion
13032 + */
13033
13034 - if (!in->valid && in->variantType !=
13035 - (oh ? oh->type : tags.extraObjectType))
13036 - T(YAFFS_TRACE_ERROR, (
13037 - TSTR("yaffs tragedy: Bad object type, "
13038 - TCONT("%d != %d, for object %d at chunk ")
13039 - TCONT("%d during scan")
13040 - TENDSTR), oh ?
13041 - oh->type : tags.extraObjectType,
13042 - in->variantType, tags.objectId,
13043 - chunk));
13044 -
13045 - if (!in->valid &&
13046 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13047 - tags.objectId ==
13048 - YAFFS_OBJECTID_LOSTNFOUND)) {
13049 - /* We only load some info, don't fiddle with directory structure */
13050 - in->valid = 1;
13051 + } else {
13052 + /* Handle YAFFS2 case (backward scanning)
13053 + * If the shadowed object exists then ignore.
13054 + */
13055 + obj = yaffs_FindObjectByNumber(dev, objId);
13056 + if(obj)
13057 + return;
13058 + }
13059
13060 - if (oh) {
13061 - in->variantType = oh->type;
13062 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13063 + * We put it in unlinked dir to be cleaned up after the scanning
13064 + */
13065 + obj =
13066 + yaffs_FindOrCreateObjectByNumber(dev, objId,
13067 + YAFFS_OBJECT_TYPE_FILE);
13068 + if (!obj)
13069 + return;
13070 + obj->isShadowed = 1;
13071 + yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
13072 + obj->variant.fileVariant.shrinkSize = 0;
13073 + obj->valid = 1; /* So that we don't read any other info for this file */
13074
13075 - in->yst_mode = oh->yst_mode;
13076 -#ifdef CONFIG_YAFFS_WINCE
13077 - in->win_atime[0] = oh->win_atime[0];
13078 - in->win_ctime[0] = oh->win_ctime[0];
13079 - in->win_mtime[0] = oh->win_mtime[0];
13080 - in->win_atime[1] = oh->win_atime[1];
13081 - in->win_ctime[1] = oh->win_ctime[1];
13082 - in->win_mtime[1] = oh->win_mtime[1];
13083 -#else
13084 - in->yst_uid = oh->yst_uid;
13085 - in->yst_gid = oh->yst_gid;
13086 - in->yst_atime = oh->yst_atime;
13087 - in->yst_mtime = oh->yst_mtime;
13088 - in->yst_ctime = oh->yst_ctime;
13089 - in->yst_rdev = oh->yst_rdev;
13090 +}
13091
13092 -#endif
13093 - } else {
13094 - in->variantType = tags.extraObjectType;
13095 - in->lazyLoaded = 1;
13096 - }
13097
13098 - in->hdrChunk = chunk;
13099 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
13100 +{
13101 + yaffs_Object *hl;
13102 + yaffs_Object *in;
13103
13104 - } else if (!in->valid) {
13105 - /* we need to load this info */
13106 + while (hardList) {
13107 + hl = hardList;
13108 + hardList = (yaffs_Object *) (hardList->hardLinks.next);
13109
13110 - in->valid = 1;
13111 - in->hdrChunk = chunk;
13112 + in = yaffs_FindObjectByNumber(dev,
13113 + hl->variant.hardLinkVariant.
13114 + equivalentObjectId);
13115
13116 - if (oh) {
13117 - in->variantType = oh->type;
13118 + if (in) {
13119 + /* Add the hardlink pointers */
13120 + hl->variant.hardLinkVariant.equivalentObject = in;
13121 + ylist_add(&hl->hardLinks, &in->hardLinks);
13122 + } else {
13123 + /* Todo Need to report/handle this better.
13124 + * Got a problem... hardlink to a non-existant object
13125 + */
13126 + hl->variant.hardLinkVariant.equivalentObject = NULL;
13127 + YINIT_LIST_HEAD(&hl->hardLinks);
13128
13129 - in->yst_mode = oh->yst_mode;
13130 -#ifdef CONFIG_YAFFS_WINCE
13131 - in->win_atime[0] = oh->win_atime[0];
13132 - in->win_ctime[0] = oh->win_ctime[0];
13133 - in->win_mtime[0] = oh->win_mtime[0];
13134 - in->win_atime[1] = oh->win_atime[1];
13135 - in->win_ctime[1] = oh->win_ctime[1];
13136 - in->win_mtime[1] = oh->win_mtime[1];
13137 -#else
13138 - in->yst_uid = oh->yst_uid;
13139 - in->yst_gid = oh->yst_gid;
13140 - in->yst_atime = oh->yst_atime;
13141 - in->yst_mtime = oh->yst_mtime;
13142 - in->yst_ctime = oh->yst_ctime;
13143 - in->yst_rdev = oh->yst_rdev;
13144 -#endif
13145 + }
13146 + }
13147 +}
13148
13149 - if (oh->shadowsObject > 0)
13150 - yaffs_HandleShadowedObject(dev,
13151 - oh->
13152 - shadowsObject,
13153 - 1);
13154 -
13155 -
13156 - yaffs_SetObjectName(in, oh->name);
13157 - parent =
13158 - yaffs_FindOrCreateObjectByNumber
13159 - (dev, oh->parentObjectId,
13160 - YAFFS_OBJECT_TYPE_DIRECTORY);
13161 -
13162 - fileSize = oh->fileSize;
13163 - isShrink = oh->isShrink;
13164 - equivalentObjectId = oh->equivalentObjectId;
13165
13166 - } else {
13167 - in->variantType = tags.extraObjectType;
13168 - parent =
13169 - yaffs_FindOrCreateObjectByNumber
13170 - (dev, tags.extraParentObjectId,
13171 - YAFFS_OBJECT_TYPE_DIRECTORY);
13172 - fileSize = tags.extraFileLength;
13173 - isShrink = tags.extraIsShrinkHeader;
13174 - equivalentObjectId = tags.extraEquivalentObjectId;
13175 - in->lazyLoaded = 1;
13176 +static void yaffs_StripDeletedObjects(yaffs_Device *dev)
13177 +{
13178 + /*
13179 + * Sort out state of unlinked and deleted objects after scanning.
13180 + */
13181 + struct ylist_head *i;
13182 + struct ylist_head *n;
13183 + yaffs_Object *l;
13184
13185 - }
13186 - in->dirty = 0;
13187 + if (dev->readOnly)
13188 + return;
13189
13190 - if (!parent)
13191 - alloc_failed = 1;
13192 + /* Soft delete all the unlinked files */
13193 + ylist_for_each_safe(i, n,
13194 + &dev->unlinkedDir->variant.directoryVariant.children) {
13195 + if (i) {
13196 + l = ylist_entry(i, yaffs_Object, siblings);
13197 + yaffs_DeleteObject(l);
13198 + }
13199 + }
13200
13201 - /* directory stuff...
13202 - * hook up to parent
13203 - */
13204 + ylist_for_each_safe(i, n,
13205 + &dev->deletedDir->variant.directoryVariant.children) {
13206 + if (i) {
13207 + l = ylist_entry(i, yaffs_Object, siblings);
13208 + yaffs_DeleteObject(l);
13209 + }
13210 + }
13211
13212 - if (parent && parent->variantType ==
13213 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13214 - /* Set up as a directory */
13215 - parent->variantType =
13216 - YAFFS_OBJECT_TYPE_DIRECTORY;
13217 - YINIT_LIST_HEAD(&parent->variant.
13218 - directoryVariant.
13219 - children);
13220 - } else if (!parent || parent->variantType !=
13221 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13222 - /* Hoosterman, another problem....
13223 - * We're trying to use a non-directory as a directory
13224 - */
13225 +}
13226
13227 - T(YAFFS_TRACE_ERROR,
13228 - (TSTR
13229 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13230 - TENDSTR)));
13231 - parent = dev->lostNFoundDir;
13232 - }
13233 +/*
13234 + * This code iterates through all the objects making sure that they are rooted.
13235 + * Any unrooted objects are re-rooted in lost+found.
13236 + * An object needs to be in one of:
13237 + * - Directly under deleted, unlinked
13238 + * - Directly or indirectly under root.
13239 + *
13240 + * Note:
13241 + * This code assumes that we don't ever change the current relationships between
13242 + * directories:
13243 + * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
13244 + * lostNfound->parent == rootDir
13245 + *
13246 + * This fixes the problem where directories might have inadvertently been deleted
13247 + * leaving the object "hanging" without being rooted in the directory tree.
13248 + */
13249 +
13250 +static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
13251 +{
13252 + return (obj == dev->deletedDir ||
13253 + obj == dev->unlinkedDir||
13254 + obj == dev->rootDir);
13255 +}
13256
13257 - yaffs_AddObjectToDirectory(parent, in);
13258 +static void yaffs_FixHangingObjects(yaffs_Device *dev)
13259 +{
13260 + yaffs_Object *obj;
13261 + yaffs_Object *parent;
13262 + int i;
13263 + struct ylist_head *lh;
13264 + struct ylist_head *n;
13265 + int depthLimit;
13266 + int hanging;
13267
13268 - itsUnlinked = (parent == dev->deletedDir) ||
13269 - (parent == dev->unlinkedDir);
13270 + if (dev->readOnly)
13271 + return;
13272
13273 - if (isShrink) {
13274 - /* Mark the block as having a shrinkHeader */
13275 - bi->hasShrinkHeader = 1;
13276 - }
13277 + /* Iterate through the objects in each hash entry,
13278 + * looking at each object.
13279 + * Make sure it is rooted.
13280 + */
13281
13282 - /* Note re hardlinks.
13283 - * Since we might scan a hardlink before its equivalent object is scanned
13284 - * we put them all in a list.
13285 - * After scanning is complete, we should have all the objects, so we run
13286 - * through this list and fix up all the chains.
13287 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13288 + ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
13289 + if (lh) {
13290 + obj = ylist_entry(lh, yaffs_Object, hashLink);
13291 + parent= obj->parent;
13292 +
13293 + if(yaffs_HasNULLParent(dev,obj)){
13294 + /* These directories are not hanging */
13295 + hanging = 0;
13296 + }
13297 + else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13298 + hanging = 1;
13299 + else if(yaffs_HasNULLParent(dev,parent))
13300 + hanging = 0;
13301 + else {
13302 + /*
13303 + * Need to follow the parent chain to see if it is hanging.
13304 */
13305 + hanging = 0;
13306 + depthLimit=100;
13307
13308 - switch (in->variantType) {
13309 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13310 - /* Todo got a problem */
13311 - break;
13312 - case YAFFS_OBJECT_TYPE_FILE:
13313 -
13314 - if (in->variant.fileVariant.
13315 - scannedFileSize < fileSize) {
13316 - /* This covers the case where the file size is greater
13317 - * than where the data is
13318 - * This will happen if the file is resized to be larger
13319 - * than its current data extents.
13320 - */
13321 - in->variant.fileVariant.fileSize = fileSize;
13322 - in->variant.fileVariant.scannedFileSize =
13323 - in->variant.fileVariant.fileSize;
13324 - }
13325 -
13326 - if (isShrink &&
13327 - in->variant.fileVariant.shrinkSize > fileSize) {
13328 - in->variant.fileVariant.shrinkSize = fileSize;
13329 - }
13330 -
13331 - break;
13332 - case YAFFS_OBJECT_TYPE_HARDLINK:
13333 - if (!itsUnlinked) {
13334 - in->variant.hardLinkVariant.equivalentObjectId =
13335 - equivalentObjectId;
13336 - in->hardLinks.next =
13337 - (struct ylist_head *) hardList;
13338 - hardList = in;
13339 - }
13340 - break;
13341 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13342 - /* Do nothing */
13343 - break;
13344 - case YAFFS_OBJECT_TYPE_SPECIAL:
13345 - /* Do nothing */
13346 - break;
13347 - case YAFFS_OBJECT_TYPE_SYMLINK:
13348 - if (oh) {
13349 - in->variant.symLinkVariant.alias =
13350 - yaffs_CloneString(oh->alias);
13351 - if (!in->variant.symLinkVariant.alias)
13352 - alloc_failed = 1;
13353 - }
13354 - break;
13355 + while(parent != dev->rootDir &&
13356 + parent->parent &&
13357 + parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
13358 + depthLimit > 0){
13359 + parent = parent->parent;
13360 + depthLimit--;
13361 }
13362 -
13363 + if(parent != dev->rootDir)
13364 + hanging = 1;
13365 + }
13366 + if(hanging){
13367 + T(YAFFS_TRACE_SCAN,
13368 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13369 + obj->objectId));
13370 + yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
13371 }
13372 -
13373 }
13374 + }
13375 + }
13376 +}
13377
13378 - } /* End of scanning for each chunk */
13379
13380 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13381 - /* If we got this far while scanning, then the block is fully allocated. */
13382 - state = YAFFS_BLOCK_STATE_FULL;
13383 - }
13384 +/*
13385 + * Delete directory contents for cleaning up lost and found.
13386 + */
13387 +static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
13388 +{
13389 + yaffs_Object *obj;
13390 + struct ylist_head *lh;
13391 + struct ylist_head *n;
13392
13393 - bi->blockState = state;
13394 + if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
13395 + YBUG();
13396 +
13397 + ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
13398 + if (lh) {
13399 + obj = ylist_entry(lh, yaffs_Object, siblings);
13400 + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
13401 + yaffs_DeleteDirectoryContents(obj);
13402 +
13403 + T(YAFFS_TRACE_SCAN,
13404 + (TSTR("Deleting lost_found object %d" TENDSTR),
13405 + obj->objectId));
13406
13407 - /* Now let's see if it was dirty */
13408 - if (bi->pagesInUse == 0 &&
13409 - !bi->hasShrinkHeader &&
13410 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13411 - yaffs_BlockBecameDirty(dev, blk);
13412 + /* Need to use UnlinkObject since Delete would not handle
13413 + * hardlinked objects correctly.
13414 + */
13415 + yaffs_UnlinkObject(obj);
13416 }
13417 -
13418 }
13419 +
13420 +}
13421
13422 - if (altBlockIndex)
13423 - YFREE_ALT(blockIndex);
13424 - else
13425 - YFREE(blockIndex);
13426 +static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
13427 +{
13428 + yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
13429 +}
13430
13431 - /* Ok, we've done all the scanning.
13432 - * Fix up the hard link chains.
13433 - * We should now have scanned all the objects, now it's time to add these
13434 - * hardlinks.
13435 - */
13436 - yaffs_HardlinkFixup(dev, hardList);
13437 +static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
13438 +{
13439 + __u8 *chunkData;
13440 + yaffs_ObjectHeader *oh;
13441 + yaffs_Device *dev;
13442 + yaffs_ExtendedTags tags;
13443 + int result;
13444 + int alloc_failed = 0;
13445
13446 + if (!in)
13447 + return;
13448
13449 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13450 + dev = in->myDev;
13451
13452 - if (alloc_failed)
13453 - return YAFFS_FAIL;
13454 +#if 0
13455 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
13456 + in->objectId,
13457 + in->lazyLoaded ? "not yet" : "already"));
13458 +#endif
13459
13460 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
13461 + if (in->lazyLoaded && in->hdrChunk > 0) {
13462 + in->lazyLoaded = 0;
13463 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13464
13465 - return YAFFS_OK;
13466 -}
13467 + result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
13468 + oh = (yaffs_ObjectHeader *) chunkData;
13469
13470 -/*------------------------------ Directory Functions ----------------------------- */
13471 + in->yst_mode = oh->yst_mode;
13472 +#ifdef CONFIG_YAFFS_WINCE
13473 + in->win_atime[0] = oh->win_atime[0];
13474 + in->win_ctime[0] = oh->win_ctime[0];
13475 + in->win_mtime[0] = oh->win_mtime[0];
13476 + in->win_atime[1] = oh->win_atime[1];
13477 + in->win_ctime[1] = oh->win_ctime[1];
13478 + in->win_mtime[1] = oh->win_mtime[1];
13479 +#else
13480 + in->yst_uid = oh->yst_uid;
13481 + in->yst_gid = oh->yst_gid;
13482 + in->yst_atime = oh->yst_atime;
13483 + in->yst_mtime = oh->yst_mtime;
13484 + in->yst_ctime = oh->yst_ctime;
13485 + in->yst_rdev = oh->yst_rdev;
13486
13487 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
13488 -{
13489 - struct ylist_head *lh;
13490 - yaffs_Object *listObj;
13491 +#endif
13492 + yaffs_SetObjectNameFromOH(in, oh);
13493
13494 - int count = 0;
13495 + if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
13496 + in->variant.symLinkVariant.alias =
13497 + yaffs_CloneString(oh->alias);
13498 + if (!in->variant.symLinkVariant.alias)
13499 + alloc_failed = 1; /* Not returned to caller */
13500 + }
13501
13502 - if (!obj) {
13503 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
13504 - YBUG();
13505 - return;
13506 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
13507 }
13508 +}
13509
13510 - if (yaffs_SkipVerification(obj->myDev))
13511 - return;
13512 +/*------------------------------ Directory Functions ----------------------------- */
13513
13514 - if (!obj->parent) {
13515 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
13516 - YBUG();
13517 +/*
13518 + *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
13519 + * link (ie. name) is created or deleted in the directory.
13520 + *
13521 + * ie.
13522 + * create dir/a : update dir's mtime/ctime
13523 + * rm dir/a: update dir's mtime/ctime
13524 + * modify dir/a: don't update dir's mtimme/ctime
13525 + *
13526 + * This can be handled immediately or defered. Defering helps reduce the number
13527 + * of updates when many files in a directory are changed within a brief period.
13528 + *
13529 + * If the directory updating is defered then yaffs_UpdateDirtyDirecories must be
13530 + * called periodically.
13531 + */
13532 +
13533 +static void yaffs_UpdateParent(yaffs_Object *obj)
13534 +{
13535 + yaffs_Device *dev;
13536 + if(!obj)
13537 return;
13538 - }
13539 -
13540 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13541 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
13542 - YBUG();
13543 - }
13544 -
13545 - /* Iterate through the objects in each hash entry */
13546 +#ifndef CONFIG_YAFFS_WINCE
13547
13548 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
13549 - if (lh) {
13550 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13551 - yaffs_VerifyObject(listObj);
13552 - if (obj == listObj)
13553 - count++;
13554 + dev = obj->myDev;
13555 + obj->dirty = 1;
13556 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
13557 + if(dev->param.deferDirectoryUpdate){
13558 + struct ylist_head *link = &obj->variant.directoryVariant.dirty;
13559 +
13560 + if(ylist_empty(link)){
13561 + ylist_add(link,&dev->dirtyDirectories);
13562 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->objectId));
13563 }
13564 - }
13565
13566 - if (count != 1) {
13567 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
13568 - YBUG();
13569 - }
13570 + } else
13571 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13572 +#endif
13573 }
13574
13575 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
13576 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
13577 {
13578 - struct ylist_head *lh;
13579 - yaffs_Object *listObj;
13580 -
13581 - if (!directory) {
13582 - YBUG();
13583 - return;
13584 - }
13585 + struct ylist_head *link;
13586 + yaffs_Object *obj;
13587 + yaffs_DirectoryStructure *dS;
13588 + yaffs_ObjectVariant *oV;
13589
13590 - if (yaffs_SkipFullVerification(directory->myDev))
13591 - return;
13592 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
13593
13594 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
13595 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
13596 - YBUG();
13597 - }
13598 + while(!ylist_empty(&dev->dirtyDirectories)){
13599 + link = dev->dirtyDirectories.next;
13600 + ylist_del_init(link);
13601 +
13602 + dS=ylist_entry(link,yaffs_DirectoryStructure,dirty);
13603 + oV = ylist_entry(dS,yaffs_ObjectVariant,directoryVariant);
13604 + obj = ylist_entry(oV,yaffs_Object,variant);
13605
13606 - /* Iterate through the objects in each hash entry */
13607 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId));
13608
13609 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
13610 - if (lh) {
13611 - listObj = ylist_entry(lh, yaffs_Object, siblings);
13612 - if (listObj->parent != directory) {
13613 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
13614 - YBUG();
13615 - }
13616 - yaffs_VerifyObjectInDirectory(listObj);
13617 - }
13618 + if(obj->dirty)
13619 + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
13620 }
13621 }
13622
13623 -
13624 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
13625 {
13626 yaffs_Device *dev = obj->myDev;
13627 @@ -6677,18 +4474,17 @@ static void yaffs_RemoveObjectFromDirect
13628
13629 yaffs_VerifyDirectory(parent);
13630
13631 - if (dev && dev->removeObjectCallback)
13632 - dev->removeObjectCallback(obj);
13633 + if (dev && dev->param.removeObjectCallback)
13634 + dev->param.removeObjectCallback(obj);
13635
13636
13637 ylist_del_init(&obj->siblings);
13638 obj->parent = NULL;
13639 -
13640 +
13641 yaffs_VerifyDirectory(parent);
13642 }
13643
13644 -
13645 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13646 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
13647 yaffs_Object *obj)
13648 {
13649 if (!directory) {
13650 @@ -6781,7 +4577,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
13651 * Do a real check
13652 */
13653 yaffs_GetObjectName(l, buffer,
13654 - YAFFS_MAX_NAME_LENGTH);
13655 + YAFFS_MAX_NAME_LENGTH + 1);
13656 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
13657 return l;
13658 }
13659 @@ -6842,36 +4638,124 @@ yaffs_Object *yaffs_GetEquivalentObject(
13660 return obj;
13661 }
13662
13663 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
13664 -{
13665 - memset(name, 0, buffSize * sizeof(YCHAR));
13666 -
13667 - yaffs_CheckObjectDetailsLoaded(obj);
13668 +/*
13669 + * A note or two on object names.
13670 + * * If the object name is missing, we then make one up in the form objnnn
13671 + *
13672 + * * ASCII names are stored in the object header's name field from byte zero
13673 + * * Unicode names are historically stored starting from byte zero.
13674 + *
13675 + * Then there are automatic Unicode names...
13676 + * The purpose of these is to save names in a way that can be read as
13677 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
13678 + * system to share files.
13679 + *
13680 + * These automatic unicode are stored slightly differently...
13681 + * - If the name can fit in the ASCII character space then they are saved as
13682 + * ascii names as per above.
13683 + * - If the name needs Unicode then the name is saved in Unicode
13684 + * starting at oh->name[1].
13685
13686 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13687 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13688 - } else if (obj->hdrChunk <= 0) {
13689 + */
13690 +static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize)
13691 +{
13692 + /* Create an object name if we could not find one. */
13693 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
13694 YCHAR locName[20];
13695 YCHAR numString[20];
13696 YCHAR *x = &numString[19];
13697 unsigned v = obj->objectId;
13698 numString[19] = 0;
13699 - while (v > 0) {
13700 + while(v>0){
13701 x--;
13702 *x = '0' + (v % 10);
13703 v /= 10;
13704 }
13705 /* make up a name */
13706 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
13707 - yaffs_strcat(locName, x);
13708 + yaffs_strcat(locName,x);
13709 yaffs_strncpy(name, locName, buffSize - 1);
13710 + }
13711 +}
13712 +
13713 +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
13714 +{
13715 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13716 + if(dev->param.autoUnicode){
13717 + if(*ohName){
13718 + /* It is an ASCII name, so do an ASCII to unicode conversion */
13719 + const char *asciiOhName = (const char *)ohName;
13720 + int n = bufferSize - 1;
13721 + while(n > 0 && *asciiOhName){
13722 + *name = *asciiOhName;
13723 + name++;
13724 + asciiOhName++;
13725 + n--;
13726 + }
13727 + } else
13728 + yaffs_strncpy(name,ohName+1, bufferSize -1);
13729 + } else
13730 +#endif
13731 + yaffs_strncpy(name, ohName, bufferSize - 1);
13732 +}
13733 +
13734 +
13735 +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name)
13736 +{
13737 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
13738 +
13739 + int isAscii;
13740 + YCHAR *w;
13741
13742 + if(dev->param.autoUnicode){
13743 +
13744 + isAscii = 1;
13745 + w = name;
13746 +
13747 + /* Figure out if the name will fit in ascii character set */
13748 + while(isAscii && *w){
13749 + if((*w) & 0xff00)
13750 + isAscii = 0;
13751 + w++;
13752 + }
13753 +
13754 + if(isAscii){
13755 + /* It is an ASCII name, so do a unicode to ascii conversion */
13756 + char *asciiOhName = (char *)ohName;
13757 + int n = YAFFS_MAX_NAME_LENGTH - 1;
13758 + while(n > 0 && *name){
13759 + *asciiOhName= *name;
13760 + name++;
13761 + asciiOhName++;
13762 + n--;
13763 + }
13764 + } else{
13765 + /* It is a unicode name, so save starting at the second YCHAR */
13766 + *ohName = 0;
13767 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
13768 + }
13769 }
13770 + else
13771 +#endif
13772 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
13773 +
13774 +}
13775 +
13776 +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
13777 +{
13778 + memset(name, 0, buffSize * sizeof(YCHAR));
13779 +
13780 + yaffs_CheckObjectDetailsLoaded(obj);
13781 +
13782 + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
13783 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
13784 + }
13785 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
13786 - else if (obj->shortName[0])
13787 + else if (obj->shortName[0]) {
13788 yaffs_strcpy(name, obj->shortName);
13789 + }
13790 #endif
13791 - else {
13792 + else if(obj->hdrChunk > 0) {
13793 int result;
13794 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
13795
13796 @@ -6884,14 +4768,17 @@ int yaffs_GetObjectName(yaffs_Object *ob
13797 obj->hdrChunk, buffer,
13798 NULL);
13799 }
13800 - yaffs_strncpy(name, oh->name, buffSize - 1);
13801 + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize);
13802
13803 yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
13804 }
13805
13806 - return yaffs_strlen(name);
13807 + yaffs_FixNullName(obj,name,buffSize);
13808 +
13809 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
13810 }
13811
13812 +
13813 int yaffs_GetObjectFileLength(yaffs_Object *obj)
13814 {
13815 /* Dereference any hard linking */
13816 @@ -6899,9 +4786,11 @@ int yaffs_GetObjectFileLength(yaffs_Obje
13817
13818 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
13819 return obj->variant.fileVariant.fileSize;
13820 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
13821 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
13822 - else {
13823 + if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
13824 + if(!obj->variant.symLinkVariant.alias)
13825 + return 0;
13826 + return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
13827 + } else {
13828 /* Only a directory should drop through to here */
13829 return obj->myDev->nDataBytesPerChunk;
13830 }
13831 @@ -6992,7 +4881,7 @@ int yaffs_SetAttributes(yaffs_Object *ob
13832 if (valid & ATTR_SIZE)
13833 yaffs_ResizeFile(obj, attr->ia_size);
13834
13835 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
13836 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
13837
13838 return YAFFS_OK;
13839
13840 @@ -7025,12 +4914,129 @@ int yaffs_GetAttributes(yaffs_Object *ob
13841
13842 #endif
13843
13844 +
13845 +static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags)
13846 +{
13847 + yaffs_XAttrMod xmod;
13848 +
13849 + int result;
13850 +
13851 + xmod.set = set;
13852 + xmod.name = name;
13853 + xmod.data = value;
13854 + xmod.size = size;
13855 + xmod.flags = flags;
13856 + xmod.result = -ENOSPC;
13857 +
13858 + result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod);
13859 +
13860 + if(result > 0)
13861 + return xmod.result;
13862 + else
13863 + return -ENOSPC;
13864 +}
13865 +
13866 +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod)
13867 +{
13868 + int retval = 0;
13869 + int x_offs = sizeof(yaffs_ObjectHeader);
13870 + yaffs_Device *dev = obj->myDev;
13871 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13872 +
13873 + char * x_buffer = buffer + x_offs;
13874 +
13875 + if(xmod->set)
13876 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
13877 + else
13878 + retval = nval_del(x_buffer, x_size, xmod->name);
13879 +
13880 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13881 + obj->xattrKnown = 1;
13882 +
13883 + xmod->result = retval;
13884 +
13885 + return retval;
13886 +}
13887 +
13888 +static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13889 +{
13890 + char *buffer = NULL;
13891 + int result;
13892 + yaffs_ExtendedTags tags;
13893 + yaffs_Device *dev = obj->myDev;
13894 + int x_offs = sizeof(yaffs_ObjectHeader);
13895 + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
13896 +
13897 + char * x_buffer;
13898 +
13899 + int retval = 0;
13900 +
13901 + if(obj->hdrChunk < 1)
13902 + return -ENODATA;
13903 +
13904 + /* If we know that the object has no xattribs then don't do all the
13905 + * reading and parsing.
13906 + */
13907 + if(obj->xattrKnown && !obj->hasXattr){
13908 + if(name)
13909 + return -ENODATA;
13910 + else
13911 + return 0;
13912 + }
13913 +
13914 + buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__);
13915 + if(!buffer)
13916 + return -ENOMEM;
13917 +
13918 + result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags);
13919 +
13920 + if(result != YAFFS_OK)
13921 + retval = -ENOENT;
13922 + else{
13923 + x_buffer = buffer + x_offs;
13924 +
13925 + if (!obj->xattrKnown){
13926 + obj->hasXattr = nval_hasvalues(x_buffer, x_size);
13927 + obj->xattrKnown = 1;
13928 + }
13929 +
13930 + if(name)
13931 + retval = nval_get(x_buffer, x_size, name, value, size);
13932 + else
13933 + retval = nval_list(x_buffer, x_size, value,size);
13934 + }
13935 + yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__);
13936 + return retval;
13937 +}
13938 +
13939 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags)
13940 +{
13941 + return yaffs_DoXMod(obj, 1, name, value, size, flags);
13942 +}
13943 +
13944 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name)
13945 +{
13946 + return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
13947 +}
13948 +
13949 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size)
13950 +{
13951 + return yaffs_DoXFetch(obj, name, value, size);
13952 +}
13953 +
13954 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size)
13955 +{
13956 + return yaffs_DoXFetch(obj, NULL, buffer,size);
13957 +}
13958 +
13959 +
13960 +
13961 #if 0
13962 int yaffs_DumpObject(yaffs_Object *obj)
13963 {
13964 YCHAR name[257];
13965
13966 - yaffs_GetObjectName(obj, name, 256);
13967 + yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
13968
13969 T(YAFFS_TRACE_ALWAYS,
13970 (TSTR
13971 @@ -7050,30 +5056,32 @@ static int yaffs_CheckDevFunctions(const
13972 {
13973
13974 /* Common functions, gotta have */
13975 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
13976 + if (!dev->param.eraseBlockInNAND || !dev->param.initialiseNAND)
13977 return 0;
13978
13979 #ifdef CONFIG_YAFFS_YAFFS2
13980
13981 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
13982 - if (dev->writeChunkWithTagsToNAND &&
13983 - dev->readChunkWithTagsFromNAND &&
13984 - !dev->writeChunkToNAND &&
13985 - !dev->readChunkFromNAND &&
13986 - dev->markNANDBlockBad && dev->queryNANDBlock)
13987 + if (dev->param.writeChunkWithTagsToNAND &&
13988 + dev->param.readChunkWithTagsFromNAND &&
13989 + !dev->param.writeChunkToNAND &&
13990 + !dev->param.readChunkFromNAND &&
13991 + dev->param.markNANDBlockBad &&
13992 + dev->param.queryNANDBlock)
13993 return 1;
13994 #endif
13995
13996 /* Can use the "spare" style interface for yaffs1 */
13997 - if (!dev->isYaffs2 &&
13998 - !dev->writeChunkWithTagsToNAND &&
13999 - !dev->readChunkWithTagsFromNAND &&
14000 - dev->writeChunkToNAND &&
14001 - dev->readChunkFromNAND &&
14002 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
14003 + if (!dev->param.isYaffs2 &&
14004 + !dev->param.writeChunkWithTagsToNAND &&
14005 + !dev->param.readChunkWithTagsFromNAND &&
14006 + dev->param.writeChunkToNAND &&
14007 + dev->param.readChunkFromNAND &&
14008 + !dev->param.markNANDBlockBad &&
14009 + !dev->param.queryNANDBlock)
14010 return 1;
14011
14012 - return 0; /* bad */
14013 + return 0; /* bad */
14014 }
14015
14016
14017 @@ -7120,35 +5128,35 @@ int yaffs_GutsInitialise(yaffs_Device *d
14018 return YAFFS_FAIL;
14019 }
14020
14021 - dev->internalStartBlock = dev->startBlock;
14022 - dev->internalEndBlock = dev->endBlock;
14023 + dev->internalStartBlock = dev->param.startBlock;
14024 + dev->internalEndBlock = dev->param.endBlock;
14025 dev->blockOffset = 0;
14026 dev->chunkOffset = 0;
14027 dev->nFreeChunks = 0;
14028
14029 - dev->gcBlock = -1;
14030 + dev->gcBlock = 0;
14031
14032 - if (dev->startBlock == 0) {
14033 - dev->internalStartBlock = dev->startBlock + 1;
14034 - dev->internalEndBlock = dev->endBlock + 1;
14035 + if (dev->param.startBlock == 0) {
14036 + dev->internalStartBlock = dev->param.startBlock + 1;
14037 + dev->internalEndBlock = dev->param.endBlock + 1;
14038 dev->blockOffset = 1;
14039 - dev->chunkOffset = dev->nChunksPerBlock;
14040 + dev->chunkOffset = dev->param.nChunksPerBlock;
14041 }
14042
14043 /* Check geometry parameters. */
14044
14045 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14046 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14047 - (dev->inbandTags && !dev->isYaffs2) ||
14048 - dev->nChunksPerBlock < 2 ||
14049 - dev->nReservedBlocks < 2 ||
14050 + if ((!dev->param.inbandTags && dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 1024) ||
14051 + (!dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 512) ||
14052 + (dev->param.inbandTags && !dev->param.isYaffs2) ||
14053 + dev->param.nChunksPerBlock < 2 ||
14054 + dev->param.nReservedBlocks < 2 ||
14055 dev->internalStartBlock <= 0 ||
14056 dev->internalEndBlock <= 0 ||
14057 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14058 + dev->internalEndBlock <= (dev->internalStartBlock + dev->param.nReservedBlocks + 2)) { /* otherwise it is too small */
14059 T(YAFFS_TRACE_ALWAYS,
14060 (TSTR
14061 ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14062 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14063 + TENDSTR), dev->param.totalBytesPerChunk, dev->param.isYaffs2 ? "2" : "", dev->param.inbandTags));
14064 return YAFFS_FAIL;
14065 }
14066
14067 @@ -7159,10 +5167,10 @@ int yaffs_GutsInitialise(yaffs_Device *d
14068 }
14069
14070 /* Sort out space for inband tags, if required */
14071 - if (dev->inbandTags)
14072 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14073 + if (dev->param.inbandTags)
14074 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14075 else
14076 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
14077 + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk;
14078
14079 /* Got the right mix of functions? */
14080 if (!yaffs_CheckDevFunctions(dev)) {
14081 @@ -7209,12 +5217,12 @@ int yaffs_GutsInitialise(yaffs_Device *d
14082 * We need to find the next power of 2 > than internalEndBlock
14083 */
14084
14085 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
14086 + x = dev->param.nChunksPerBlock * (dev->internalEndBlock + 1);
14087
14088 bits = ShiftsGE(x);
14089
14090 /* Set up tnode width if wide tnodes are enabled. */
14091 - if (!dev->wideTnodesDisabled) {
14092 + if (!dev->param.wideTnodesDisabled) {
14093 /* bits must be even so that we end up with 32-bit words */
14094 if (bits & 1)
14095 bits++;
14096 @@ -7238,10 +5246,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14097 else
14098 dev->chunkGroupBits = bits - dev->tnodeWidth;
14099
14100 + dev->tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
14101 + if(dev->tnodeSize < sizeof(yaffs_Tnode))
14102 + dev->tnodeSize = sizeof(yaffs_Tnode);
14103
14104 dev->chunkGroupSize = 1 << dev->chunkGroupBits;
14105
14106 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
14107 + if (dev->param.nChunksPerBlock < dev->chunkGroupSize) {
14108 /* We have a problem because the soft delete won't work if
14109 * the chunk group size > chunks per block.
14110 * This can be remedied by using larger "virtual blocks".
14111 @@ -7255,9 +5266,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14112 /* OK, we've finished verifying the device, lets continue with initialisation */
14113
14114 /* More device initialisation */
14115 - dev->garbageCollections = 0;
14116 - dev->passiveGarbageCollections = 0;
14117 - dev->currentDirtyChecker = 0;
14118 + dev->allGCs = 0;
14119 + dev->passiveGCs = 0;
14120 + dev->oldestDirtyGCs = 0;
14121 + dev->backgroundGCs = 0;
14122 + dev->gcBlockFinder = 0;
14123 dev->bufferedBlock = -1;
14124 dev->doingBufferedBlockRewrite = 0;
14125 dev->nDeletedFiles = 0;
14126 @@ -7269,8 +5282,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14127 dev->tagsEccUnfixed = 0;
14128 dev->nErasureFailures = 0;
14129 dev->nErasedBlocks = 0;
14130 - dev->isDoingGC = 0;
14131 + dev->gcDisable= 0;
14132 dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
14133 + YINIT_LIST_HEAD(&dev->dirtyDirectories);
14134 + dev->oldestDirtySequence = 0;
14135 + dev->oldestDirtyBlock = 0;
14136
14137 /* Initialise temporary buffers and caches. */
14138 if (!yaffs_InitialiseTempBuffers(dev))
14139 @@ -7281,13 +5297,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14140
14141
14142 if (!init_failed &&
14143 - dev->nShortOpCaches > 0) {
14144 + dev->param.nShortOpCaches > 0) {
14145 int i;
14146 void *buf;
14147 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
14148 + int srCacheBytes = dev->param.nShortOpCaches * sizeof(yaffs_ChunkCache);
14149
14150 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14151 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14152 + if (dev->param.nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
14153 + dev->param.nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
14154
14155 dev->srCache = YMALLOC(srCacheBytes);
14156
14157 @@ -7296,11 +5312,11 @@ int yaffs_GutsInitialise(yaffs_Device *d
14158 if (dev->srCache)
14159 memset(dev->srCache, 0, srCacheBytes);
14160
14161 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
14162 + for (i = 0; i < dev->param.nShortOpCaches && buf; i++) {
14163 dev->srCache[i].object = NULL;
14164 dev->srCache[i].lastUse = 0;
14165 dev->srCache[i].dirty = 0;
14166 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
14167 + dev->srCache[i].data = buf = YMALLOC_DMA(dev->param.totalBytesPerChunk);
14168 }
14169 if (!buf)
14170 init_failed = 1;
14171 @@ -7311,19 +5327,18 @@ int yaffs_GutsInitialise(yaffs_Device *d
14172 dev->cacheHits = 0;
14173
14174 if (!init_failed) {
14175 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
14176 + dev->gcCleanupList = YMALLOC(dev->param.nChunksPerBlock * sizeof(__u32));
14177 if (!dev->gcCleanupList)
14178 init_failed = 1;
14179 }
14180
14181 - if (dev->isYaffs2)
14182 - dev->useHeaderFileSize = 1;
14183 + if (dev->param.isYaffs2)
14184 + dev->param.useHeaderFileSize = 1;
14185
14186 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14187 init_failed = 1;
14188
14189 - yaffs_InitialiseTnodes(dev);
14190 - yaffs_InitialiseObjects(dev);
14191 + yaffs_InitialiseTnodesAndObjects(dev);
14192
14193 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14194 init_failed = 1;
14195 @@ -7331,8 +5346,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14196
14197 if (!init_failed) {
14198 /* Now scan the flash. */
14199 - if (dev->isYaffs2) {
14200 - if (yaffs_CheckpointRestore(dev)) {
14201 + if (dev->param.isYaffs2) {
14202 + if (yaffs2_CheckpointRestore(dev)) {
14203 yaffs_CheckObjectDetailsLoaded(dev->rootDir);
14204 T(YAFFS_TRACE_ALWAYS,
14205 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
14206 @@ -7342,9 +5357,8 @@ int yaffs_GutsInitialise(yaffs_Device *d
14207 * and scan backwards.
14208 */
14209 yaffs_DeinitialiseBlocks(dev);
14210 - yaffs_DeinitialiseTnodes(dev);
14211 - yaffs_DeinitialiseObjects(dev);
14212
14213 + yaffs_DeinitialiseTnodesAndObjects(dev);
14214
14215 dev->nErasedBlocks = 0;
14216 dev->nFreeChunks = 0;
14217 @@ -7353,24 +5367,25 @@ int yaffs_GutsInitialise(yaffs_Device *d
14218 dev->nDeletedFiles = 0;
14219 dev->nUnlinkedFiles = 0;
14220 dev->nBackgroundDeletions = 0;
14221 - dev->oldestDirtySequence = 0;
14222
14223 if (!init_failed && !yaffs_InitialiseBlocks(dev))
14224 init_failed = 1;
14225
14226 - yaffs_InitialiseTnodes(dev);
14227 - yaffs_InitialiseObjects(dev);
14228 + yaffs_InitialiseTnodesAndObjects(dev);
14229
14230 if (!init_failed && !yaffs_CreateInitialDirectories(dev))
14231 init_failed = 1;
14232
14233 - if (!init_failed && !yaffs_ScanBackwards(dev))
14234 + if (!init_failed && !yaffs2_ScanBackwards(dev))
14235 init_failed = 1;
14236 }
14237 - } else if (!yaffs_Scan(dev))
14238 + } else if (!yaffs1_Scan(dev))
14239 init_failed = 1;
14240
14241 yaffs_StripDeletedObjects(dev);
14242 + yaffs_FixHangingObjects(dev);
14243 + if(dev->param.emptyLostAndFound)
14244 + yaffs_EmptyLostAndFound(dev);
14245 }
14246
14247 if (init_failed) {
14248 @@ -7394,6 +5409,9 @@ int yaffs_GutsInitialise(yaffs_Device *d
14249 yaffs_VerifyFreeChunks(dev);
14250 yaffs_VerifyBlocks(dev);
14251
14252 + /* Clean up any aborted checkpoint data */
14253 + if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
14254 + yaffs2_InvalidateCheckpoint(dev);
14255
14256 T(YAFFS_TRACE_TRACING,
14257 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
14258 @@ -7407,12 +5425,11 @@ void yaffs_Deinitialise(yaffs_Device *de
14259 int i;
14260
14261 yaffs_DeinitialiseBlocks(dev);
14262 - yaffs_DeinitialiseTnodes(dev);
14263 - yaffs_DeinitialiseObjects(dev);
14264 - if (dev->nShortOpCaches > 0 &&
14265 + yaffs_DeinitialiseTnodesAndObjects(dev);
14266 + if (dev->param.nShortOpCaches > 0 &&
14267 dev->srCache) {
14268
14269 - for (i = 0; i < dev->nShortOpCaches; i++) {
14270 + for (i = 0; i < dev->param.nShortOpCaches; i++) {
14271 if (dev->srCache[i].data)
14272 YFREE(dev->srCache[i].data);
14273 dev->srCache[i].data = NULL;
14274 @@ -7429,34 +5446,33 @@ void yaffs_Deinitialise(yaffs_Device *de
14275
14276 dev->isMounted = 0;
14277
14278 - if (dev->deinitialiseNAND)
14279 - dev->deinitialiseNAND(dev);
14280 + if (dev->param.deinitialiseNAND)
14281 + dev->param.deinitialiseNAND(dev);
14282 }
14283 }
14284
14285 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
14286 +int yaffs_CountFreeChunks(yaffs_Device *dev)
14287 {
14288 - int nFree;
14289 + int nFree=0;
14290 int b;
14291
14292 yaffs_BlockInfo *blk;
14293
14294 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
14295 - b++) {
14296 - blk = yaffs_GetBlockInfo(dev, b);
14297 -
14298 + blk = dev->blockInfo;
14299 + for (b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) {
14300 switch (blk->blockState) {
14301 case YAFFS_BLOCK_STATE_EMPTY:
14302 case YAFFS_BLOCK_STATE_ALLOCATING:
14303 case YAFFS_BLOCK_STATE_COLLECTING:
14304 case YAFFS_BLOCK_STATE_FULL:
14305 nFree +=
14306 - (dev->nChunksPerBlock - blk->pagesInUse +
14307 + (dev->param.nChunksPerBlock - blk->pagesInUse +
14308 blk->softDeletions);
14309 break;
14310 default:
14311 break;
14312 }
14313 + blk++;
14314 }
14315
14316 return nFree;
14317 @@ -7481,21 +5497,19 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14318
14319 /* Now count the number of dirty chunks in the cache and subtract those */
14320
14321 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
14322 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.nShortOpCaches; i++) {
14323 if (dev->srCache[i].dirty)
14324 nDirtyCacheChunks++;
14325 }
14326
14327 nFree -= nDirtyCacheChunks;
14328
14329 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
14330 + nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock);
14331
14332 /* Now we figure out how much to reserve for the checkpoint and report that... */
14333 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
14334 - if (blocksForCheckpoint < 0)
14335 - blocksForCheckpoint = 0;
14336 + blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev);
14337
14338 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
14339 + nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock);
14340
14341 if (nFree < 0)
14342 nFree = 0;
14343 @@ -7504,27 +5518,6 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
14344
14345 }
14346
14347 -static int yaffs_freeVerificationFailures;
14348 -
14349 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
14350 -{
14351 - int counted;
14352 - int difference;
14353 -
14354 - if (yaffs_SkipVerification(dev))
14355 - return;
14356 -
14357 - counted = yaffs_CountFreeChunks(dev);
14358 -
14359 - difference = dev->nFreeChunks - counted;
14360 -
14361 - if (difference) {
14362 - T(YAFFS_TRACE_ALWAYS,
14363 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
14364 - dev->nFreeChunks, counted, difference));
14365 - yaffs_freeVerificationFailures++;
14366 - }
14367 -}
14368
14369 /*---------------------------------------- YAFFS test code ----------------------*/
14370
14371 @@ -7532,7 +5525,7 @@ static void yaffs_VerifyFreeChunks(yaffs
14372 do { \
14373 if (sizeof(structure) != syze) { \
14374 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
14375 - name, syze, sizeof(structure))); \
14376 + name, syze, (int) sizeof(structure))); \
14377 return YAFFS_FAIL; \
14378 } \
14379 } while (0)
14380 @@ -7542,9 +5535,8 @@ static int yaffs_CheckStructures(void)
14381 /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
14382 /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
14383 /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
14384 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
14385 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
14386 -#endif
14387 +/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
14388 +
14389 #ifndef CONFIG_YAFFS_WINCE
14390 yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
14391 #endif
14392 diff -Nrup a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
14393 --- a/fs/yaffs2/yaffs_guts.h 2010-10-03 17:48:22.718000363 +0300
14394 +++ b/fs/yaffs2/yaffs_guts.h 2010-10-03 18:03:47.542000362 +0300
14395 @@ -1,7 +1,7 @@
14396 /*
14397 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14398 *
14399 - * Copyright (C) 2002-2007 Aleph One Ltd.
14400 + * Copyright (C) 2002-2010 Aleph One Ltd.
14401 * for Toby Churchill Ltd and Brightstar Engineering
14402 *
14403 * Created by Charles Manning <charles@aleph1.co.uk>
14404 @@ -16,8 +16,9 @@
14405 #ifndef __YAFFS_GUTS_H__
14406 #define __YAFFS_GUTS_H__
14407
14408 -#include "devextras.h"
14409 #include "yportenv.h"
14410 +#include "devextras.h"
14411 +#include "yaffs_list.h"
14412
14413 #define YAFFS_OK 1
14414 #define YAFFS_FAIL 0
14415 @@ -52,7 +53,6 @@
14416
14417 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
14418
14419 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
14420
14421 #define YAFFS_ALLOCATION_NOBJECTS 100
14422 #define YAFFS_ALLOCATION_NTNODES 100
14423 @@ -62,8 +62,9 @@
14424
14425
14426 #define YAFFS_OBJECT_SPACE 0x40000
14427 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
14428
14429 -#define YAFFS_CHECKPOINT_VERSION 3
14430 +#define YAFFS_CHECKPOINT_VERSION 4
14431
14432 #ifdef CONFIG_YAFFS_UNICODE
14433 #define YAFFS_MAX_NAME_LENGTH 127
14434 @@ -81,12 +82,11 @@
14435 #define YAFFS_OBJECTID_UNLINKED 3
14436 #define YAFFS_OBJECTID_DELETED 4
14437
14438 -/* Sseudo object ids for checkpointing */
14439 +/* Pseudo object ids for checkpointing */
14440 #define YAFFS_OBJECTID_SB_HEADER 0x10
14441 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
14442 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
14443
14444 -/* */
14445
14446 #define YAFFS_MAX_SHORT_OP_CACHES 20
14447
14448 @@ -119,11 +119,7 @@ typedef struct {
14449 int dirty;
14450 int nBytes; /* Only valid if the cache is dirty */
14451 int locked; /* Can't push out or flush while locked. */
14452 -#ifdef CONFIG_YAFFS_YAFFS2
14453 __u8 *data;
14454 -#else
14455 - __u8 data[YAFFS_BYTES_PER_CHUNK];
14456 -#endif
14457 } yaffs_ChunkCache;
14458
14459
14460 @@ -234,6 +230,8 @@ typedef enum {
14461 YAFFS_BLOCK_STATE_UNKNOWN = 0,
14462
14463 YAFFS_BLOCK_STATE_SCANNING,
14464 + /* Being scanned */
14465 +
14466 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
14467 /* The block might have something on it (ie it is allocating or full, perhaps empty)
14468 * but it needs to be scanned to determine its true state.
14469 @@ -249,21 +247,23 @@ typedef enum {
14470 /* This block is partially allocated.
14471 * At least one page holds valid data.
14472 * This is the one currently being used for page
14473 - * allocation. Should never be more than one of these
14474 + * allocation. Should never be more than one of these.
14475 + * If a block is only partially allocated at mount it is treated as full.
14476 */
14477
14478 YAFFS_BLOCK_STATE_FULL,
14479 /* All the pages in this block have been allocated.
14480 + * If a block was only partially allocated when mounted we treat
14481 + * it as fully allocated.
14482 */
14483
14484 YAFFS_BLOCK_STATE_DIRTY,
14485 - /* All pages have been allocated and deleted.
14486 + /* The block was full and now all chunks have been deleted.
14487 * Erase me, reuse me.
14488 */
14489
14490 YAFFS_BLOCK_STATE_CHECKPOINT,
14491 - /* This block is assigned to holding checkpoint data.
14492 - */
14493 + /* This block is assigned to holding checkpoint data. */
14494
14495 YAFFS_BLOCK_STATE_COLLECTING,
14496 /* This block is being garbage collected */
14497 @@ -351,23 +351,12 @@ typedef struct {
14498 /*--------------------------- Tnode -------------------------- */
14499
14500 union yaffs_Tnode_union {
14501 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
14502 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
14503 -#else
14504 union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
14505 -#endif
14506 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
14507
14508 };
14509
14510 typedef union yaffs_Tnode_union yaffs_Tnode;
14511
14512 -struct yaffs_TnodeList_struct {
14513 - struct yaffs_TnodeList_struct *next;
14514 - yaffs_Tnode *tnodes;
14515 -};
14516 -
14517 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
14518
14519 /*------------------------ Object -----------------------------*/
14520 /* An object can be one of:
14521 @@ -387,6 +376,7 @@ typedef struct {
14522
14523 typedef struct {
14524 struct ylist_head children; /* list of child links */
14525 + struct ylist_head dirty; /* Entry for list of dirty directories */
14526 } yaffs_DirectoryStructure;
14527
14528 typedef struct {
14529 @@ -405,6 +395,8 @@ typedef union {
14530 yaffs_HardLinkStructure hardLinkVariant;
14531 } yaffs_ObjectVariant;
14532
14533 +
14534 +
14535 struct yaffs_ObjectStruct {
14536 __u8 deleted:1; /* This should only apply to unlinked files. */
14537 __u8 softDeleted:1; /* it has also been soft deleted */
14538 @@ -424,6 +416,10 @@ struct yaffs_ObjectStruct {
14539 * until the inode is released.
14540 */
14541 __u8 beingCreated:1; /* This object is still being created so skip some checks. */
14542 + __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */
14543 +
14544 + __u8 xattrKnown:1; /* We know if this has object has xattribs or not. */
14545 + __u8 hasXattr:1; /* This object has xattribs. Valid if xattrKnown. */
14546
14547 __u8 serial; /* serial number of chunk in NAND. Cached here */
14548 __u16 sum; /* sum of the name to speed searching */
14549 @@ -452,10 +448,6 @@ struct yaffs_ObjectStruct {
14550 YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
14551 #endif
14552
14553 -#ifndef __KERNEL__
14554 - __u32 inUse;
14555 -#endif
14556 -
14557 #ifdef CONFIG_YAFFS_WINCE
14558 __u32 win_ctime[2];
14559 __u32 win_mtime[2];
14560 @@ -470,10 +462,7 @@ struct yaffs_ObjectStruct {
14561
14562 __u32 yst_rdev;
14563
14564 -#ifdef __KERNEL__
14565 - struct inode *myInode;
14566 -
14567 -#endif
14568 + void *myInode;
14569
14570 yaffs_ObjectType variantType;
14571
14572 @@ -483,13 +472,6 @@ struct yaffs_ObjectStruct {
14573
14574 typedef struct yaffs_ObjectStruct yaffs_Object;
14575
14576 -struct yaffs_ObjectList_struct {
14577 - yaffs_Object *objects;
14578 - struct yaffs_ObjectList_struct *next;
14579 -};
14580 -
14581 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
14582 -
14583 typedef struct {
14584 struct ylist_head list;
14585 int count;
14586 @@ -531,12 +513,18 @@ typedef struct {
14587
14588 /*----------------- Device ---------------------------------*/
14589
14590 -struct yaffs_DeviceStruct {
14591 - struct ylist_head devList;
14592 - const char *name;
14593
14594 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
14595 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
14596 +struct yaffs_DeviceParamStruct {
14597 + const YCHAR *name;
14598 +
14599 + /*
14600 + * Entry parameters set up way early. Yaffs sets up the rest.
14601 + * The structure should be zeroed out before use so that unused
14602 + * and defualt values are zero.
14603 + */
14604 +
14605 + int inbandTags; /* Use unband tags */
14606 + __u32 totalBytesPerChunk; /* Should be >= 512, does not need to be a power of 2 */
14607 int nChunksPerBlock; /* does not need to be a power of 2 */
14608 int spareBytesPerChunk; /* spare area size */
14609 int startBlock; /* Start block we're allowed to use */
14610 @@ -545,24 +533,24 @@ struct yaffs_DeviceStruct {
14611 /* reserved blocks on NOR and RAM. */
14612
14613
14614 - /* Stuff used by the shared space checkpointing mechanism */
14615 - /* If this value is zero, then this mechanism is disabled */
14616 -
14617 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
14618 -
14619 -
14620 int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
14621 - * the number of short op caches (don't use too many)
14622 + * the number of short op caches (don't use too many).
14623 + * 10 to 20 is a good bet.
14624 */
14625 + int useNANDECC; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
14626 + int noTagsECC; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
14627
14628 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14629 + int isYaffs2; /* Use yaffs2 mode on this device */
14630
14631 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
14632 + int emptyLostAndFound; /* Auto-empty lost+found directory on mount */
14633
14634 - void *genericDevice; /* Pointer to device context
14635 - * On an mtd this holds the mtd pointer.
14636 - */
14637 - void *superBlock;
14638 + int refreshPeriod; /* How often we should check to do a block refresh */
14639 +
14640 + /* Checkpoint control. Can be set before or after initialisation */
14641 + __u8 skipCheckpointRead;
14642 + __u8 skipCheckpointWrite;
14643 +
14644 + int enableXattr; /* Enable xattribs */
14645
14646 /* NAND access functions (Must be set before calling YAFFS)*/
14647
14648 @@ -589,58 +577,68 @@ struct yaffs_DeviceStruct {
14649 yaffs_BlockState *state, __u32 *sequenceNumber);
14650 #endif
14651
14652 - int isYaffs2;
14653 -
14654 /* The removeObjectCallback function must be supplied by OS flavours that
14655 - * need it. The Linux kernel does not use this, but yaffs direct does use
14656 - * it to implement the faster readdir
14657 + * need it.
14658 + * yaffs direct uses it to implement the faster readdir.
14659 + * Linux uses it to protect the directory during unlocking.
14660 */
14661 void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
14662
14663 - /* Callback to mark the superblock dirsty */
14664 - void (*markSuperBlockDirty)(void *superblock);
14665 + /* Callback to mark the superblock dirty */
14666 + void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev);
14667 +
14668 + /* Callback to control garbage collection. */
14669 + unsigned (*gcControl)(struct yaffs_DeviceStruct *dev);
14670
14671 + /* Debug control flags. Don't use unless you know what you're doing */
14672 + int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
14673 + int disableLazyLoad; /* Disable lazy loading on this device */
14674 int wideTnodesDisabled; /* Set to disable wide tnodes */
14675 + int disableSoftDelete; /* yaffs 1 only: Set to disable the use of softdeletion. */
14676 +
14677 + int deferDirectoryUpdate; /* Set to defer directory updates */
14678 +
14679 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14680 + int autoUnicode;
14681 +#endif
14682 + int alwaysCheckErased; /* Force chunk erased check always on */
14683 +};
14684
14685 - YCHAR *pathDividers; /* String of legal path dividers */
14686 +typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam;
14687
14688 +struct yaffs_DeviceStruct {
14689 + struct yaffs_DeviceParamStruct param;
14690
14691 - /* End of stuff that must be set before initialisation. */
14692 + /* Context storage. Holds extra OS specific data for this device */
14693
14694 - /* Checkpoint control. Can be set before or after initialisation */
14695 - __u8 skipCheckpointRead;
14696 - __u8 skipCheckpointWrite;
14697 + void *osContext;
14698 + void *driverContext;
14699 +
14700 + struct ylist_head devList;
14701
14702 /* Runtime parameters. Set up by YAFFS. */
14703 + int nDataBytesPerChunk;
14704
14705 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
14706 + /* Non-wide tnode stuff */
14707 + __u16 chunkGroupBits; /* Number of bits that need to be resolved if
14708 + * the tnodes are not wide enough.
14709 + */
14710 __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
14711
14712 /* Stuff to support wide tnodes */
14713 __u32 tnodeWidth;
14714 __u32 tnodeMask;
14715 + __u32 tnodeSize;
14716
14717 /* Stuff for figuring out file offset to chunk conversions */
14718 __u32 chunkShift; /* Shift value */
14719 __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
14720 __u32 chunkMask; /* Mask to use for power-of-2 case */
14721
14722 - /* Stuff to handle inband tags */
14723 - int inbandTags;
14724 - __u32 totalBytesPerChunk;
14725 -
14726 -#ifdef __KERNEL__
14727 -
14728 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
14729 - struct semaphore grossLock; /* Gross locking semaphore */
14730 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
14731 - * at compile time so we have to allocate it.
14732 - */
14733 - void (*putSuperFunc) (struct super_block *sb);
14734 -#endif
14735
14736 - int isMounted;
14737
14738 + int isMounted;
14739 + int readOnly;
14740 int isCheckpointed;
14741
14742
14743 @@ -682,51 +680,31 @@ struct yaffs_DeviceStruct {
14744 __u32 allocationPage;
14745 int allocationBlockFinder; /* Used to search for next allocation block */
14746
14747 - /* Runtime state */
14748 - int nTnodesCreated;
14749 - yaffs_Tnode *freeTnodes;
14750 - int nFreeTnodes;
14751 - yaffs_TnodeList *allocatedTnodeList;
14752 -
14753 - int isDoingGC;
14754 - int gcBlock;
14755 - int gcChunk;
14756 -
14757 - int nObjectsCreated;
14758 - yaffs_Object *freeObjects;
14759 - int nFreeObjects;
14760 + /* Object and Tnode memory management */
14761 + void *allocator;
14762 + int nObjects;
14763 + int nTnodes;
14764
14765 int nHardLinks;
14766
14767 - yaffs_ObjectList *allocatedObjectList;
14768 -
14769 yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
14770 + __u32 bucketFinder;
14771
14772 int nFreeChunks;
14773
14774 - int currentDirtyChecker; /* Used to find current dirtiest block */
14775 -
14776 + /* Garbage collection control */
14777 __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
14778 - int nonAggressiveSkip; /* GC state/mode */
14779 + __u32 nCleanups;
14780
14781 - /* Statistcs */
14782 - int nPageWrites;
14783 - int nPageReads;
14784 - int nBlockErasures;
14785 - int nErasureFailures;
14786 - int nGCCopies;
14787 - int garbageCollections;
14788 - int passiveGarbageCollections;
14789 - int nRetriedWrites;
14790 - int nRetiredBlocks;
14791 - int eccFixed;
14792 - int eccUnfixed;
14793 - int tagsEccFixed;
14794 - int tagsEccUnfixed;
14795 - int nDeletions;
14796 - int nUnmarkedDeletions;
14797 -
14798 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14799 + unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
14800 + unsigned gcDisable;
14801 + unsigned gcBlockFinder;
14802 + unsigned gcDirtiest;
14803 + unsigned gcPagesInUse;
14804 + unsigned gcNotDone;
14805 + unsigned gcBlock;
14806 + unsigned gcChunk;
14807 + unsigned gcSkip;
14808
14809 /* Special directories */
14810 yaffs_Object *rootDir;
14811 @@ -743,8 +721,6 @@ struct yaffs_DeviceStruct {
14812 yaffs_ChunkCache *srCache;
14813 int srLastUse;
14814
14815 - int cacheHits;
14816 -
14817 /* Stuff for background deletion and unlinked files.*/
14818 yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
14819 yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
14820 @@ -753,7 +729,6 @@ struct yaffs_DeviceStruct {
14821 int nUnlinkedFiles; /* Count of unlinked files. */
14822 int nBackgroundDeletions; /* Count of background deletions. */
14823
14824 -
14825 /* Temporary buffer management */
14826 yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
14827 int maxTemp;
14828 @@ -764,6 +739,36 @@ struct yaffs_DeviceStruct {
14829 /* yaffs2 runtime stuff */
14830 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14831 unsigned oldestDirtySequence;
14832 + unsigned oldestDirtyBlock;
14833 +
14834 + /* Block refreshing */
14835 + int refreshSkip; /* A skip down counter. Refresh happens when this gets to zero. */
14836 +
14837 + /* Dirty directory handling */
14838 + struct ylist_head dirtyDirectories; /* List of dirty directories */
14839 +
14840 +
14841 + /* Statistcs */
14842 + __u32 nPageWrites;
14843 + __u32 nPageReads;
14844 + __u32 nBlockErasures;
14845 + __u32 nErasureFailures;
14846 + __u32 nGCCopies;
14847 + __u32 allGCs;
14848 + __u32 passiveGCs;
14849 + __u32 oldestDirtyGCs;
14850 + __u32 nGCBlocks;
14851 + __u32 backgroundGCs;
14852 + __u32 nRetriedWrites;
14853 + __u32 nRetiredBlocks;
14854 + __u32 eccFixed;
14855 + __u32 eccUnfixed;
14856 + __u32 tagsEccFixed;
14857 + __u32 tagsEccUnfixed;
14858 + __u32 nDeletions;
14859 + __u32 nUnmarkedDeletions;
14860 + __u32 refreshCount;
14861 + __u32 cacheHits;
14862
14863 };
14864
14865 @@ -796,7 +801,6 @@ typedef struct {
14866
14867 /* yaffs2 runtime stuff */
14868 unsigned sequenceNumber; /* Sequence number of currently allocating block */
14869 - unsigned oldestDirtySequence;
14870
14871 } yaffs_CheckpointDevice;
14872
14873 @@ -809,6 +813,23 @@ typedef struct {
14874 } yaffs_CheckpointValidity;
14875
14876
14877 +struct yaffs_ShadowFixerStruct {
14878 + int objectId;
14879 + int shadowedId;
14880 + struct yaffs_ShadowFixerStruct *next;
14881 +};
14882 +
14883 +/* Structure for doing xattr modifications */
14884 +typedef struct {
14885 + int set; /* If 0 then this is a deletion */
14886 + const YCHAR *name;
14887 + const void *data;
14888 + int size;
14889 + int flags;
14890 + int result;
14891 +}yaffs_XAttrMod;
14892 +
14893 +
14894 /*----------------------- YAFFS Functions -----------------------*/
14895
14896 int yaffs_GutsInitialise(yaffs_Device *dev);
14897 @@ -840,7 +861,8 @@ int yaffs_ResizeFile(yaffs_Object *obj,
14898
14899 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
14900 __u32 mode, __u32 uid, __u32 gid);
14901 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
14902 +
14903 +int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync);
14904
14905 /* Flushing and checkpointing */
14906 void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
14907 @@ -873,6 +895,12 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Objec
14908 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
14909 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
14910
14911 +
14912 +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags);
14913 +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size);
14914 +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size);
14915 +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name);
14916 +
14917 /* Special directories */
14918 yaffs_Object *yaffs_Root(yaffs_Device *dev);
14919 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
14920 @@ -882,18 +910,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Dev
14921 void yfsd_WinFileTimeNow(__u32 target[2]);
14922 #endif
14923
14924 -#ifdef __KERNEL__
14925 -
14926 void yaffs_HandleDeferedFree(yaffs_Object *obj);
14927 -#endif
14928 +
14929 +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev);
14930 +
14931 +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency);
14932
14933 /* Debug dump */
14934 int yaffs_DumpObject(yaffs_Object *obj);
14935
14936 void yaffs_GutsTest(yaffs_Device *dev);
14937
14938 -/* A few useful functions */
14939 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
14940 +/* A few useful functions to be used within the core files*/
14941 void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
14942 int yaffs_CheckFF(__u8 *buffer, int nBytes);
14943 void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
14944 @@ -901,4 +929,41 @@ void yaffs_HandleChunkError(yaffs_Device
14945 __u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
14946 void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
14947
14948 +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
14949 + int number,
14950 + yaffs_ObjectType type);
14951 +int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
14952 + int chunkInNAND, int inScan);
14953 +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name);
14954 +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh);
14955 +void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14956 + yaffs_Object *obj);
14957 +YCHAR *yaffs_CloneString(const YCHAR *str);
14958 +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
14959 +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo);
14960 +int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
14961 + int force, int isShrink, int shadows,
14962 + yaffs_XAttrMod *xop);
14963 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
14964 + int backwardScanning);
14965 +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks);
14966 +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev);
14967 +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
14968 + yaffs_FileStructure *fStruct,
14969 + __u32 chunkId,
14970 + yaffs_Tnode *passedTn);
14971 +
14972 +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
14973 + int nBytes, int writeThrough);
14974 +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize);
14975 +void yaffs_SkipRestOfBlock(yaffs_Device *dev);
14976 +
14977 +int yaffs_CountFreeChunks(yaffs_Device *dev);
14978 +
14979 +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
14980 + yaffs_FileStructure *fStruct,
14981 + __u32 chunkId);
14982 +
14983 +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
14984 +
14985 #endif
14986 diff -Nrup a/fs/yaffs2/yaffsinterface.h b/fs/yaffs2/yaffsinterface.h
14987 --- a/fs/yaffs2/yaffsinterface.h 2010-10-03 17:29:32.916000361 +0300
14988 +++ b/fs/yaffs2/yaffsinterface.h 2010-10-03 18:03:47.543000365 +0300
14989 @@ -1,7 +1,7 @@
14990 /*
14991 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14992 *
14993 - * Copyright (C) 2002-2007 Aleph One Ltd.
14994 + * Copyright (C) 2002-2010 Aleph One Ltd.
14995 * for Toby Churchill Ltd and Brightstar Engineering
14996 *
14997 * Created by Charles Manning <charles@aleph1.co.uk>
14998 diff -Nrup a/fs/yaffs2/yaffs_linux_allocator.c b/fs/yaffs2/yaffs_linux_allocator.c
14999 --- a/fs/yaffs2/yaffs_linux_allocator.c 1970-01-01 02:00:00.000000000 +0200
15000 +++ b/fs/yaffs2/yaffs_linux_allocator.c 2010-10-03 18:03:47.519000366 +0300
15001 @@ -0,0 +1,200 @@
15002 +/*
15003 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15004 + *
15005 + * Copyright (C) 2002-2010 Aleph One Ltd.
15006 + * for Toby Churchill Ltd and Brightstar Engineering
15007 + *
15008 + * Created by Charles Manning <charles@aleph1.co.uk>
15009 + *
15010 + * This program is free software; you can redistribute it and/or modify
15011 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15012 + * published by the Free Software Foundation.
15013 + *
15014 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15015 + *
15016 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
15017 + */
15018 +
15019 +
15020 +#include "yaffs_allocator.h"
15021 +#include "yaffs_guts.h"
15022 +#include "yaffs_trace.h"
15023 +#include "yportenv.h"
15024 +#include "yaffs_linux.h"
15025 +/*
15026 + * Start out with the same allocator as yaffs direct.
15027 + * Todo: Change to Linux slab allocator.
15028 + */
15029 +
15030 +
15031 +
15032 +#define NAMELEN 20
15033 +struct yaffs_AllocatorStruct {
15034 + char tnode_name[NAMELEN+1];
15035 + char object_name[NAMELEN+1];
15036 + struct kmem_cache *tnode_cache;
15037 + struct kmem_cache *object_cache;
15038 +};
15039 +
15040 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
15041 +
15042 +int mount_id;
15043 +
15044 +void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
15045 +{
15046 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
15047 +
15048 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
15049 +
15050 + if(allocator){
15051 + if(allocator->tnode_cache){
15052 + kmem_cache_destroy(allocator->tnode_cache);
15053 + allocator->tnode_cache = NULL;
15054 + } else {
15055 + T(YAFFS_TRACE_ALWAYS,
15056 + (TSTR("NULL tnode cache\n")));
15057 + YBUG();
15058 + }
15059 +
15060 + if(allocator->object_cache){
15061 + kmem_cache_destroy(allocator->object_cache);
15062 + allocator->object_cache = NULL;
15063 + } else {
15064 + T(YAFFS_TRACE_ALWAYS,
15065 + (TSTR("NULL object cache\n")));
15066 + YBUG();
15067 + }
15068 +
15069 + YFREE(allocator);
15070 +
15071 + } else {
15072 + T(YAFFS_TRACE_ALWAYS,
15073 + (TSTR("Deinitialising NULL allocator\n")));
15074 + YBUG();
15075 + }
15076 + dev->allocator = NULL;
15077 +}
15078 +
15079 +
15080 +static void fake_ctor0(void *data){data = data;}
15081 +static void fake_ctor1(void *data){data = data;}
15082 +static void fake_ctor2(void *data){data = data;}
15083 +static void fake_ctor3(void *data){data = data;}
15084 +static void fake_ctor4(void *data){data = data;}
15085 +static void fake_ctor5(void *data){data = data;}
15086 +static void fake_ctor6(void *data){data = data;}
15087 +static void fake_ctor7(void *data){data = data;}
15088 +static void fake_ctor8(void *data){data = data;}
15089 +static void fake_ctor9(void *data){data = data;}
15090 +
15091 +static void (*fake_ctor_list[10]) (void *) = {
15092 + fake_ctor0,
15093 + fake_ctor1,
15094 + fake_ctor2,
15095 + fake_ctor3,
15096 + fake_ctor4,
15097 + fake_ctor5,
15098 + fake_ctor6,
15099 + fake_ctor7,
15100 + fake_ctor8,
15101 + fake_ctor9,
15102 +};
15103 +
15104 +void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
15105 +{
15106 + yaffs_Allocator *allocator;
15107 + unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id;
15108 +
15109 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
15110 +
15111 + if(dev->allocator)
15112 + YBUG();
15113 + else if(mount_id >= 10){
15114 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
15115 + } else {
15116 + allocator = YMALLOC(sizeof(yaffs_Allocator));
15117 + memset(allocator,0,sizeof(yaffs_Allocator));
15118 + dev->allocator = allocator;
15119 +
15120 + if(!dev->allocator){
15121 + T(YAFFS_TRACE_ALWAYS,
15122 + (TSTR("yaffs allocator creation failed\n")));
15123 + YBUG();
15124 + return;
15125 +
15126 + }
15127 +
15128 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
15129 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
15130 +
15131 + allocator->tnode_cache =
15132 + kmem_cache_create(allocator->tnode_name,
15133 + dev->tnodeSize,
15134 + 0, 0,
15135 + fake_ctor_list[mount_id]);
15136 + if(allocator->tnode_cache)
15137 + T(YAFFS_TRACE_ALLOCATE,
15138 + (TSTR("tnode cache \"%s\" %p\n"),
15139 + allocator->tnode_name,allocator->tnode_cache));
15140 + else {
15141 + T(YAFFS_TRACE_ALWAYS,
15142 + (TSTR("yaffs cache creation failed\n")));
15143 + YBUG();
15144 + }
15145 +
15146 +
15147 + allocator->object_cache =
15148 + kmem_cache_create(allocator->object_name,
15149 + sizeof(yaffs_Object),
15150 + 0, 0,
15151 + fake_ctor_list[mount_id]);
15152 +
15153 + if(allocator->object_cache)
15154 + T(YAFFS_TRACE_ALLOCATE,
15155 + (TSTR("object cache \"%s\" %p\n"),
15156 + allocator->object_name,allocator->object_cache));
15157 +
15158 + else {
15159 + T(YAFFS_TRACE_ALWAYS,
15160 + (TSTR("yaffs cache creation failed\n")));
15161 + YBUG();
15162 + }
15163 + }
15164 +}
15165 +
15166 +
15167 +yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
15168 +{
15169 + yaffs_Allocator *allocator = dev->allocator;
15170 + if(!allocator || !allocator->tnode_cache){
15171 + YBUG();
15172 + return NULL;
15173 + }
15174 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
15175 +}
15176 +
15177 +void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
15178 +{
15179 + yaffs_Allocator *allocator = dev->allocator;
15180 + kmem_cache_free(allocator->tnode_cache,tn);
15181 +}
15182 +
15183 +yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
15184 +{
15185 + yaffs_Allocator *allocator = dev->allocator;
15186 + if(!allocator){
15187 + YBUG();
15188 + return NULL;
15189 + }
15190 + if(!allocator->object_cache){
15191 + YBUG();
15192 + return NULL;
15193 + }
15194 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
15195 +}
15196 +
15197 +void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
15198 +{
15199 + yaffs_Allocator *allocator = dev->allocator;
15200 + kmem_cache_free(allocator->object_cache,obj);
15201 +}
15202 diff -Nrup a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h
15203 --- a/fs/yaffs2/yaffs_linux.h 1970-01-01 02:00:00.000000000 +0200
15204 +++ b/fs/yaffs2/yaffs_linux.h 2010-10-03 18:03:47.544000367 +0300
15205 @@ -0,0 +1,43 @@
15206 +/*
15207 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15208 + *
15209 + * Copyright (C) 2002-2010 Aleph One Ltd.
15210 + * for Toby Churchill Ltd and Brightstar Engineering
15211 + *
15212 + * Created by Charles Manning <charles@aleph1.co.uk>
15213 + *
15214 + * This program is free software; you can redistribute it and/or modify
15215 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15216 + * published by the Free Software Foundation.
15217 + *
15218 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15219 + */
15220 +
15221 +#ifndef __YAFFS_LINUX_H__
15222 +#define __YAFFS_LINUX_H__
15223 +
15224 +#include "devextras.h"
15225 +#include "yportenv.h"
15226 +
15227 +struct yaffs_LinuxContext {
15228 + struct ylist_head contextList; /* List of these we have mounted */
15229 + struct yaffs_DeviceStruct *dev;
15230 + struct super_block * superBlock;
15231 + struct task_struct *bgThread; /* Background thread for this device */
15232 + int bgRunning;
15233 + struct semaphore grossLock; /* Gross locking semaphore */
15234 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
15235 + * at compile time so we have to allocate it.
15236 + */
15237 + struct ylist_head searchContexts;
15238 + void (*putSuperFunc)(struct super_block *sb);
15239 +
15240 + struct task_struct *readdirProcess;
15241 + unsigned mount_id;
15242 +};
15243 +
15244 +#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext))
15245 +#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext))
15246 +
15247 +#endif
15248 +
15249 diff -Nrup a/fs/yaffs2/yaffs_list.h b/fs/yaffs2/yaffs_list.h
15250 --- a/fs/yaffs2/yaffs_list.h 1970-01-01 02:00:00.000000000 +0200
15251 +++ b/fs/yaffs2/yaffs_list.h 2010-10-03 18:03:47.544000367 +0300
15252 @@ -0,0 +1,127 @@
15253 +/*
15254 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15255 + *
15256 + * Copyright (C) 2002-2010 Aleph One Ltd.
15257 + * for Toby Churchill Ltd and Brightstar Engineering
15258 + *
15259 + * Created by Charles Manning <charles@aleph1.co.uk>
15260 + *
15261 + * This program is free software; you can redistribute it and/or modify
15262 + * it under the terms of the GNU Lesser General Public License version 2.1 as
15263 + * published by the Free Software Foundation.
15264 + *
15265 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
15266 + */
15267 +
15268 +/*
15269 + * This file is just holds extra declarations of macros that would normally
15270 + * be providesd in the Linux kernel. These macros have been written from
15271 + * scratch but are functionally equivalent to the Linux ones.
15272 + *
15273 + */
15274 +
15275 +#ifndef __YAFFS_LIST_H__
15276 +#define __YAFFS_LIST_H__
15277 +
15278 +
15279 +#include "yportenv.h"
15280 +
15281 +/*
15282 + * This is a simple doubly linked list implementation that matches the
15283 + * way the Linux kernel doubly linked list implementation works.
15284 + */
15285 +
15286 +struct ylist_head {
15287 + struct ylist_head *next; /* next in chain */
15288 + struct ylist_head *prev; /* previous in chain */
15289 +};
15290 +
15291 +
15292 +/* Initialise a static list */
15293 +#define YLIST_HEAD(name) \
15294 +struct ylist_head name = { &(name), &(name)}
15295 +
15296 +
15297 +
15298 +/* Initialise a list head to an empty list */
15299 +#define YINIT_LIST_HEAD(p) \
15300 +do { \
15301 + (p)->next = (p);\
15302 + (p)->prev = (p); \
15303 +} while (0)
15304 +
15305 +
15306 +/* Add an element to a list */
15307 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
15308 + struct ylist_head *list)
15309 +{
15310 + struct ylist_head *listNext = list->next;
15311 +
15312 + list->next = newEntry;
15313 + newEntry->prev = list;
15314 + newEntry->next = listNext;
15315 + listNext->prev = newEntry;
15316 +
15317 +}
15318 +
15319 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
15320 + struct ylist_head *list)
15321 +{
15322 + struct ylist_head *listPrev = list->prev;
15323 +
15324 + list->prev = newEntry;
15325 + newEntry->next = list;
15326 + newEntry->prev = listPrev;
15327 + listPrev->next = newEntry;
15328 +
15329 +}
15330 +
15331 +
15332 +/* Take an element out of its current list, with or without
15333 + * reinitialising the links.of the entry*/
15334 +static Y_INLINE void ylist_del(struct ylist_head *entry)
15335 +{
15336 + struct ylist_head *listNext = entry->next;
15337 + struct ylist_head *listPrev = entry->prev;
15338 +
15339 + listNext->prev = listPrev;
15340 + listPrev->next = listNext;
15341 +
15342 +}
15343 +
15344 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
15345 +{
15346 + ylist_del(entry);
15347 + entry->next = entry->prev = entry;
15348 +}
15349 +
15350 +
15351 +/* Test if the list is empty */
15352 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
15353 +{
15354 + return (entry->next == entry);
15355 +}
15356 +
15357 +
15358 +/* ylist_entry takes a pointer to a list entry and offsets it to that
15359 + * we can find a pointer to the object it is embedded in.
15360 + */
15361 +
15362 +
15363 +#define ylist_entry(entry, type, member) \
15364 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
15365 +
15366 +
15367 +/* ylist_for_each and list_for_each_safe iterate over lists.
15368 + * ylist_for_each_safe uses temporary storage to make the list delete safe
15369 + */
15370 +
15371 +#define ylist_for_each(itervar, list) \
15372 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
15373 +
15374 +#define ylist_for_each_safe(itervar, saveVar, list) \
15375 + for (itervar = (list)->next, saveVar = (list)->next->next; \
15376 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
15377 +
15378 +
15379 +#endif
15380 diff -Nrup a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
15381 --- a/fs/yaffs2/yaffs_mtdif1.c 2010-10-03 17:48:22.719000363 +0300
15382 +++ b/fs/yaffs2/yaffs_mtdif1.c 2010-10-03 18:03:47.519000366 +0300
15383 @@ -2,7 +2,7 @@
15384 * YAFFS: Yet another FFS. A NAND-flash specific file system.
15385 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15386 *
15387 - * Copyright (C) 2002 Aleph One Ltd.
15388 + * Copyright (C) 2002-2010 Aleph One Ltd.
15389 * for Toby Churchill Ltd and Brightstar Engineering
15390 *
15391 * This program is free software; you can redistribute it and/or modify
15392 @@ -24,9 +24,11 @@
15393 */
15394
15395 #include "yportenv.h"
15396 +#include "yaffs_trace.h"
15397 #include "yaffs_guts.h"
15398 #include "yaffs_packedtags1.h"
15399 #include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
15400 +#include "yaffs_linux.h"
15401
15402 #include "linux/kernel.h"
15403 #include "linux/version.h"
15404 @@ -36,8 +38,6 @@
15405 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15406 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
15407
15408 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
15409 -
15410 #ifndef CONFIG_YAFFS_9BYTE_TAGS
15411 # define YTAG1_SIZE 8
15412 #else
15413 @@ -91,7 +91,7 @@ static struct nand_ecclayout nand_oob_16
15414 int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15415 int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
15416 {
15417 - struct mtd_info *mtd = dev->genericDevice;
15418 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15419 int chunkBytes = dev->nDataBytesPerChunk;
15420 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15421 struct mtd_oob_ops ops;
15422 @@ -102,8 +102,6 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15423 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15424 compile_time_assertion(sizeof(yaffs_Tags) == 8);
15425
15426 - dev->nPageWrites++;
15427 -
15428 yaffs_PackTags1(&pt1, etags);
15429 yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15430
15431 @@ -137,9 +135,9 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
15432
15433 retval = mtd->write_oob(mtd, addr, &ops);
15434 if (retval) {
15435 - yaffs_trace(YAFFS_TRACE_MTD,
15436 - "write_oob failed, chunk %d, mtd error %d\n",
15437 - chunkInNAND, retval);
15438 + T(YAFFS_TRACE_MTD,
15439 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
15440 + chunkInNAND, retval));
15441 }
15442 return retval ? YAFFS_FAIL : YAFFS_OK;
15443 }
15444 @@ -171,7 +169,7 @@ static int rettags(yaffs_ExtendedTags *e
15445 int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15446 int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
15447 {
15448 - struct mtd_info *mtd = dev->genericDevice;
15449 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15450 int chunkBytes = dev->nDataBytesPerChunk;
15451 loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15452 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15453 @@ -180,8 +178,6 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15454 int retval;
15455 int deleted;
15456
15457 - dev->nPageReads++;
15458 -
15459 memset(&ops, 0, sizeof(ops));
15460 ops.mode = MTD_OOB_AUTO;
15461 ops.len = (data) ? chunkBytes : 0;
15462 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15463 */
15464 retval = mtd->read_oob(mtd, addr, &ops);
15465 if (retval) {
15466 - yaffs_trace(YAFFS_TRACE_MTD,
15467 - "read_oob failed, chunk %d, mtd error %d\n",
15468 - chunkInNAND, retval);
15469 + T(YAFFS_TRACE_MTD,
15470 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
15471 + chunkInNAND, retval));
15472 }
15473
15474 switch (retval) {
15475 @@ -284,11 +280,11 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
15476 */
15477 int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15478 {
15479 - struct mtd_info *mtd = dev->genericDevice;
15480 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15481 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15482 + int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk;
15483 int retval;
15484
15485 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
15486 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), blockNo));
15487
15488 retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15489 return (retval) ? YAFFS_FAIL : YAFFS_OK;
15490 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
15491 int oobavail = mtd->ecclayout->oobavail;
15492
15493 if (oobavail < YTAG1_SIZE) {
15494 - yaffs_trace(YAFFS_TRACE_ERROR,
15495 - "mtd device has only %d bytes for tags, need %d\n",
15496 - oobavail, YTAG1_SIZE);
15497 + T(YAFFS_TRACE_ERROR,
15498 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
15499 + oobavail, YTAG1_SIZE));
15500 return YAFFS_FAIL;
15501 }
15502 return YAFFS_OK;
15503 @@ -325,8 +321,8 @@ static int nandmtd1_TestPrerequists(stru
15504 int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15505 yaffs_BlockState *pState, __u32 *pSequenceNumber)
15506 {
15507 - struct mtd_info *mtd = dev->genericDevice;
15508 - int chunkNo = blockNo * dev->nChunksPerBlock;
15509 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
15510 + int chunkNo = blockNo * dev->param.nChunksPerBlock;
15511 loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
15512 yaffs_ExtendedTags etags;
15513 int state = YAFFS_BLOCK_STATE_DEAD;
15514 @@ -342,8 +338,8 @@ int nandmtd1_QueryNANDBlock(struct yaffs
15515 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15516 etags.blockBad = (mtd->block_isbad)(mtd, addr);
15517 if (etags.blockBad) {
15518 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15519 - "block %d is marked bad\n", blockNo);
15520 + T(YAFFS_TRACE_BAD_BLOCKS,
15521 + (TSTR("block %d is marked bad"TENDSTR), blockNo));
15522 state = YAFFS_BLOCK_STATE_DEAD;
15523 } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
15524 /* bad tags, need to look more closely */
15525 diff -Nrup a/fs/yaffs2/yaffs_mtdif1-compat.c b/fs/yaffs2/yaffs_mtdif1-compat.c
15526 --- a/fs/yaffs2/yaffs_mtdif1-compat.c 2010-10-03 17:29:32.916000361 +0300
15527 +++ b/fs/yaffs2/yaffs_mtdif1-compat.c 1970-01-01 02:00:00.000000000 +0200
15528 @@ -1,434 +0,0 @@
15529 -From ian@brightstareng.com Fri May 18 15:06:49 2007
15530 -From ian@brightstareng.com Fri May 18 15:08:21 2007
15531 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
15532 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
15533 - (envelope-from <ian@brightstareng.com>)
15534 - id 1Hp380-00011e-T6
15535 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
15536 -Received: from localhost (localhost.localdomain [127.0.0.1])
15537 - by zebra.brightstareng.com (Postfix) with ESMTP
15538 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
15539 -Received: from zebra.brightstareng.com ([127.0.0.1])
15540 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
15541 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
15542 -Received: from pippin (unknown [192.168.1.25])
15543 - by zebra.brightstareng.com (Postfix) with ESMTP
15544 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
15545 -From: Ian McDonnell <ian@brightstareng.com>
15546 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
15547 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
15548 -Date: Fri, 18 May 2007 10:06:49 -0400
15549 -User-Agent: KMail/1.9.1
15550 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
15551 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
15552 -Cc: Andrea Conti <alyf@alyf.net>,
15553 - Charles Manning <manningc2@actrix.gen.nz>
15554 -MIME-Version: 1.0
15555 -Content-Type: Multipart/Mixed;
15556 - boundary="Boundary-00=_5LbTGmt62YoutxM"
15557 -Message-Id: <200705181006.49860.ian@brightstareng.com>
15558 -X-Virus-Scanned: by amavisd-new at brightstareng.com
15559 -Status: R
15560 -X-Status: NT
15561 -X-KMail-EncryptionState:
15562 -X-KMail-SignatureState:
15563 -X-KMail-MDN-Sent:
15564 -
15565 ---Boundary-00=_5LbTGmt62YoutxM
15566 -Content-Type: text/plain;
15567 - charset="iso-8859-15"
15568 -Content-Transfer-Encoding: 7bit
15569 -Content-Disposition: inline
15570 -
15571 -David, Andrea,
15572 -
15573 -On Friday 18 May 2007 08:34, you wrote:
15574 -> Yea team. With this fix in place (I put it in the wrong place
15575 -> at first) I can now mount and ls the Yaffs partition without
15576 -> an error messages!
15577 -
15578 -Good news!
15579 -
15580 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
15581 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
15582 -See the LINUX_VERSION_CODE conditional in
15583 -nandmtd1_ReadChunkWithTagsFromNAND.
15584 -
15585 --imcd
15586 -
15587 ---Boundary-00=_5LbTGmt62YoutxM
15588 -Content-Type: text/x-csrc;
15589 - charset="iso-8859-15";
15590 - name="yaffs_mtdif1.c"
15591 -Content-Transfer-Encoding: 7bit
15592 -Content-Disposition: attachment;
15593 - filename="yaffs_mtdif1.c"
15594 -
15595 -/*
15596 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
15597 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
15598 - *
15599 - * Copyright (C) 2002 Aleph One Ltd.
15600 - * for Toby Churchill Ltd and Brightstar Engineering
15601 - *
15602 - * This program is free software; you can redistribute it and/or modify
15603 - * it under the terms of the GNU General Public License version 2 as
15604 - * published by the Free Software Foundation.
15605 - */
15606 -
15607 -/*
15608 - * This module provides the interface between yaffs_nand.c and the
15609 - * MTD API. This version is used when the MTD interface supports the
15610 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
15611 - * and we have small-page NAND device.
15612 - *
15613 - * These functions are invoked via function pointers in yaffs_nand.c.
15614 - * This replaces functionality provided by functions in yaffs_mtdif.c
15615 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
15616 - * called in yaffs_mtdif.c when the function pointers are NULL.
15617 - * We assume the MTD layer is performing ECC (useNANDECC is true).
15618 - */
15619 -
15620 -#include "yportenv.h"
15621 -#include "yaffs_guts.h"
15622 -#include "yaffs_packedtags1.h"
15623 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
15624 -
15625 -#include "linux/kernel.h"
15626 -#include "linux/version.h"
15627 -#include "linux/types.h"
15628 -#include "linux/mtd/mtd.h"
15629 -
15630 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
15631 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
15632 -
15633 -const char *yaffs_mtdif1_c_version = "$Id$";
15634 -
15635 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15636 -# define YTAG1_SIZE 8
15637 -#else
15638 -# define YTAG1_SIZE 9
15639 -#endif
15640 -
15641 -#if 0
15642 -/* Use the following nand_ecclayout with MTD when using
15643 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
15644 - * If you have existing Yaffs images and the byte order differs from this,
15645 - * adjust 'oobfree' to match your existing Yaffs data.
15646 - *
15647 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
15648 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
15649 - * the 9th byte.
15650 - *
15651 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
15652 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
15653 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
15654 - * byte and B is the small-page bad-block indicator byte.
15655 - */
15656 -static struct nand_ecclayout nand_oob_16 = {
15657 - .eccbytes = 6,
15658 - .eccpos = { 8, 9, 10, 13, 14, 15 },
15659 - .oobavail = 9,
15660 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
15661 -};
15662 -#endif
15663 -
15664 -/* Write a chunk (page) of data to NAND.
15665 - *
15666 - * Caller always provides ExtendedTags data which are converted to a more
15667 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
15668 - * contents of the tags meta-data; used to valid the tags when read.
15669 - *
15670 - * - Pack ExtendedTags to PackedTags1 form
15671 - * - Compute mini-ECC for PackedTags1
15672 - * - Write data and packed tags to NAND.
15673 - *
15674 - * Note: Due to the use of the PackedTags1 meta-data which does not include
15675 - * a full sequence number (as found in the larger PackedTags2 form) it is
15676 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
15677 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
15678 - * to be written just once. When Yaffs performs this operation, this
15679 - * function is called with a NULL data pointer -- calling MTD write_oob
15680 - * without data is valid usage (2.6.17).
15681 - *
15682 - * Any underlying MTD error results in YAFFS_FAIL.
15683 - * Returns YAFFS_OK or YAFFS_FAIL.
15684 - */
15685 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
15686 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
15687 -{
15688 - struct mtd_info * mtd = dev->genericDevice;
15689 - int chunkBytes = dev->nDataBytesPerChunk;
15690 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15691 - struct mtd_oob_ops ops;
15692 - yaffs_PackedTags1 pt1;
15693 - int retval;
15694 -
15695 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
15696 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
15697 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
15698 -
15699 - yaffs_PackTags1(&pt1, etags);
15700 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
15701 -
15702 - /* When deleting a chunk, the upper layer provides only skeletal
15703 - * etags, one with chunkDeleted set. However, we need to update the
15704 - * tags, not erase them completely. So we use the NAND write property
15705 - * that only zeroed-bits stick and set tag bytes to all-ones and
15706 - * zero just the (not) deleted bit.
15707 - */
15708 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15709 - if (etags->chunkDeleted) {
15710 - memset(&pt1, 0xff, 8);
15711 - /* clear delete status bit to indicate deleted */
15712 - pt1.deleted = 0;
15713 - }
15714 -#else
15715 - ((__u8 *)&pt1)[8] = 0xff;
15716 - if (etags->chunkDeleted) {
15717 - memset(&pt1, 0xff, 8);
15718 - /* zero pageStatus byte to indicate deleted */
15719 - ((__u8 *)&pt1)[8] = 0;
15720 - }
15721 -#endif
15722 -
15723 - memset(&ops, 0, sizeof(ops));
15724 - ops.mode = MTD_OOB_AUTO;
15725 - ops.len = (data) ? chunkBytes : 0;
15726 - ops.ooblen = YTAG1_SIZE;
15727 - ops.datbuf = (__u8 *)data;
15728 - ops.oobbuf = (__u8 *)&pt1;
15729 -
15730 - retval = mtd->write_oob(mtd, addr, &ops);
15731 - if (retval) {
15732 - yaffs_trace(YAFFS_TRACE_MTD,
15733 - "write_oob failed, chunk %d, mtd error %d\n",
15734 - chunkInNAND, retval);
15735 - }
15736 - return retval ? YAFFS_FAIL : YAFFS_OK;
15737 -}
15738 -
15739 -/* Return with empty ExtendedTags but add eccResult.
15740 - */
15741 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
15742 -{
15743 - if (etags) {
15744 - memset(etags, 0, sizeof(*etags));
15745 - etags->eccResult = eccResult;
15746 - }
15747 - return retval;
15748 -}
15749 -
15750 -/* Read a chunk (page) from NAND.
15751 - *
15752 - * Caller expects ExtendedTags data to be usable even on error; that is,
15753 - * all members except eccResult and blockBad are zeroed.
15754 - *
15755 - * - Check ECC results for data (if applicable)
15756 - * - Check for blank/erased block (return empty ExtendedTags if blank)
15757 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
15758 - * - Convert PackedTags1 to ExtendedTags
15759 - * - Update eccResult and blockBad members to refect state.
15760 - *
15761 - * Returns YAFFS_OK or YAFFS_FAIL.
15762 - */
15763 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
15764 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
15765 -{
15766 - struct mtd_info * mtd = dev->genericDevice;
15767 - int chunkBytes = dev->nDataBytesPerChunk;
15768 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
15769 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
15770 - struct mtd_oob_ops ops;
15771 - yaffs_PackedTags1 pt1;
15772 - int retval;
15773 - int deleted;
15774 -
15775 - memset(&ops, 0, sizeof(ops));
15776 - ops.mode = MTD_OOB_AUTO;
15777 - ops.len = (data) ? chunkBytes : 0;
15778 - ops.ooblen = YTAG1_SIZE;
15779 - ops.datbuf = data;
15780 - ops.oobbuf = (__u8 *)&pt1;
15781 -
15782 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
15783 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
15784 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
15785 - */
15786 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
15787 -#endif
15788 - /* Read page and oob using MTD.
15789 - * Check status and determine ECC result.
15790 - */
15791 - retval = mtd->read_oob(mtd, addr, &ops);
15792 - if (retval) {
15793 - yaffs_trace(YAFFS_TRACE_MTD,
15794 - "read_oob failed, chunk %d, mtd error %d\n",
15795 - chunkInNAND, retval);
15796 - }
15797 -
15798 - switch (retval) {
15799 - case 0:
15800 - /* no error */
15801 - break;
15802 -
15803 - case -EUCLEAN:
15804 - /* MTD's ECC fixed the data */
15805 - eccres = YAFFS_ECC_RESULT_FIXED;
15806 - dev->eccFixed++;
15807 - break;
15808 -
15809 - case -EBADMSG:
15810 - /* MTD's ECC could not fix the data */
15811 - dev->eccUnfixed++;
15812 - /* fall into... */
15813 - default:
15814 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
15815 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
15816 - return YAFFS_FAIL;
15817 - }
15818 -
15819 - /* Check for a blank/erased chunk.
15820 - */
15821 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
15822 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
15823 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
15824 - }
15825 -
15826 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15827 - /* Read deleted status (bit) then return it to it's non-deleted
15828 - * state before performing tags mini-ECC check. pt1.deleted is
15829 - * inverted.
15830 - */
15831 - deleted = !pt1.deleted;
15832 - pt1.deleted = 1;
15833 -#else
15834 - (void) deleted; /* not used */
15835 -#endif
15836 -
15837 - /* Check the packed tags mini-ECC and correct if necessary/possible.
15838 - */
15839 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
15840 - switch (retval) {
15841 - case 0:
15842 - /* no tags error, use MTD result */
15843 - break;
15844 - case 1:
15845 - /* recovered tags-ECC error */
15846 - dev->tagsEccFixed++;
15847 - eccres = YAFFS_ECC_RESULT_FIXED;
15848 - break;
15849 - default:
15850 - /* unrecovered tags-ECC error */
15851 - dev->tagsEccUnfixed++;
15852 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
15853 - }
15854 -
15855 - /* Unpack the tags to extended form and set ECC result.
15856 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
15857 - */
15858 - pt1.shouldBeFF = 0xFFFFFFFF;
15859 - yaffs_UnpackTags1(etags, &pt1);
15860 - etags->eccResult = eccres;
15861 -
15862 - /* Set deleted state.
15863 - */
15864 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
15865 - etags->chunkDeleted = deleted;
15866 -#else
15867 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
15868 -#endif
15869 - return YAFFS_OK;
15870 -}
15871 -
15872 -/* Mark a block bad.
15873 - *
15874 - * This is a persistant state.
15875 - * Use of this function should be rare.
15876 - *
15877 - * Returns YAFFS_OK or YAFFS_FAIL.
15878 - */
15879 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
15880 -{
15881 - struct mtd_info * mtd = dev->genericDevice;
15882 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
15883 - int retval;
15884 -
15885 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
15886 -
15887 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
15888 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
15889 -}
15890 -
15891 -/* Check any MTD prerequists.
15892 - *
15893 - * Returns YAFFS_OK or YAFFS_FAIL.
15894 - */
15895 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
15896 -{
15897 - /* 2.6.18 has mtd->ecclayout->oobavail */
15898 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
15899 - int oobavail = mtd->ecclayout->oobavail;
15900 -
15901 - if (oobavail < YTAG1_SIZE) {
15902 - yaffs_trace(YAFFS_TRACE_ERROR,
15903 - "mtd device has only %d bytes for tags, need %d",
15904 - oobavail, YTAG1_SIZE);
15905 - return YAFFS_FAIL;
15906 - }
15907 - return YAFFS_OK;
15908 -}
15909 -
15910 -/* Query for the current state of a specific block.
15911 - *
15912 - * Examine the tags of the first chunk of the block and return the state:
15913 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
15914 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
15915 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
15916 - *
15917 - * Always returns YAFFS_OK.
15918 - */
15919 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
15920 - yaffs_BlockState * pState, int *pSequenceNumber)
15921 -{
15922 - struct mtd_info * mtd = dev->genericDevice;
15923 - int chunkNo = blockNo * dev->nChunksPerBlock;
15924 - yaffs_ExtendedTags etags;
15925 - int state = YAFFS_BLOCK_STATE_DEAD;
15926 - int seqnum = 0;
15927 - int retval;
15928 -
15929 - /* We don't yet have a good place to test for MTD config prerequists.
15930 - * Do it here as we are called during the initial scan.
15931 - */
15932 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
15933 - return YAFFS_FAIL;
15934 - }
15935 -
15936 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
15937 - if (etags.blockBad) {
15938 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
15939 - "block %d is marked bad", blockNo);
15940 - state = YAFFS_BLOCK_STATE_DEAD;
15941 - }
15942 - else if (etags.chunkUsed) {
15943 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
15944 - seqnum = etags.sequenceNumber;
15945 - }
15946 - else {
15947 - state = YAFFS_BLOCK_STATE_EMPTY;
15948 - }
15949 -
15950 - *pState = state;
15951 - *pSequenceNumber = seqnum;
15952 -
15953 - /* query always succeeds */
15954 - return YAFFS_OK;
15955 -}
15956 -
15957 -#endif /*KERNEL_VERSION*/
15958 -
15959 ---Boundary-00=_5LbTGmt62YoutxM--
15960 -
15961 -
15962 -
15963 diff -Nrup a/fs/yaffs2/yaffs_mtdif1.h b/fs/yaffs2/yaffs_mtdif1.h
15964 --- a/fs/yaffs2/yaffs_mtdif1.h 2010-10-03 17:48:22.719000363 +0300
15965 +++ b/fs/yaffs2/yaffs_mtdif1.h 2010-10-03 18:03:47.545000367 +0300
15966 @@ -1,7 +1,7 @@
15967 /*
15968 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
15969 *
15970 - * Copyright (C) 2002-2007 Aleph One Ltd.
15971 + * Copyright (C) 2002-2010 Aleph One Ltd.
15972 * for Toby Churchill Ltd and Brightstar Engineering
15973 *
15974 * This program is free software; you can redistribute it and/or modify
15975 diff -Nrup a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
15976 --- a/fs/yaffs2/yaffs_mtdif2.c 2010-10-03 17:48:22.720000363 +0300
15977 +++ b/fs/yaffs2/yaffs_mtdif2.c 2010-10-03 18:03:47.520000367 +0300
15978 @@ -1,7 +1,7 @@
15979 /*
15980 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
15981 *
15982 - * Copyright (C) 2002-2007 Aleph One Ltd.
15983 + * Copyright (C) 2002-2010 Aleph One Ltd.
15984 * for Toby Churchill Ltd and Brightstar Engineering
15985 *
15986 * Created by Charles Manning <charles@aleph1.co.uk>
15987 @@ -13,11 +13,8 @@
15988
15989 /* mtd interface for YAFFS2 */
15990
15991 -const char *yaffs_mtdif2_c_version =
15992 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
15993 -
15994 #include "yportenv.h"
15995 -
15996 +#include "yaffs_trace.h"
15997
15998 #include "yaffs_mtdif2.h"
15999
16000 @@ -27,6 +24,8 @@ const char *yaffs_mtdif2_c_version =
16001
16002 #include "yaffs_packedtags2.h"
16003
16004 +#include "yaffs_linux.h"
16005 +
16006 /* NB For use with inband tags....
16007 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
16008 * use it to load the tags.
16009 @@ -35,7 +34,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16010 const __u8 *data,
16011 const yaffs_ExtendedTags *tags)
16012 {
16013 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16014 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16015 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16016 struct mtd_oob_ops ops;
16017 #else
16018 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16019
16020 yaffs_PackedTags2 pt;
16021
16022 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
16023 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt;
16024 +
16025 T(YAFFS_TRACE_MTD,
16026 (TSTR
16027 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
16028 TENDSTR), chunkInNAND, data, tags));
16029
16030
16031 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16032 + addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16033
16034 /* For yaffs2 writing there must be both data and tags.
16035 * If we're using inband tags, then the tags are stuffed into
16036 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16037 */
16038 if (!data || !tags)
16039 BUG();
16040 - else if (dev->inbandTags) {
16041 + else if (dev->param.inbandTags) {
16042 yaffs_PackedTags2TagsPart *pt2tp;
16043 pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
16044 yaffs_PackTags2TagsPart(pt2tp, tags);
16045 } else
16046 - yaffs_PackTags2(&pt, tags);
16047 + yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC);
16048
16049 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16050 ops.mode = MTD_OOB_AUTO;
16051 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
16052 - ops.len = dev->totalBytesPerChunk;
16053 + ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size;
16054 + ops.len = dev->param.totalBytesPerChunk;
16055 ops.ooboffs = 0;
16056 ops.datbuf = (__u8 *)data;
16057 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
16058 + ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr;
16059 retval = mtd->write_oob(mtd, addr, &ops);
16060
16061 #else
16062 - if (!dev->inbandTags) {
16063 + if (!dev->param.inbandTags) {
16064 retval =
16065 mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16066 - &dummy, data, (__u8 *) &pt, NULL);
16067 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
16068 } else {
16069 retval =
16070 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
16071 + mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy,
16072 data);
16073 }
16074 #endif
16075 @@ -98,7 +100,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
16076 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
16077 __u8 *data, yaffs_ExtendedTags *tags)
16078 {
16079 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16080 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16081 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16082 struct mtd_oob_ops ops;
16083 #endif
16084 @@ -106,16 +108,19 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16085 int retval = 0;
16086 int localData = 0;
16087
16088 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
16089 + loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
16090
16091 yaffs_PackedTags2 pt;
16092
16093 + int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
16094 + void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt;
16095 +
16096 T(YAFFS_TRACE_MTD,
16097 (TSTR
16098 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
16099 TENDSTR), chunkInNAND, data, tags));
16100
16101 - if (dev->inbandTags) {
16102 + if (dev->param.inbandTags) {
16103
16104 if (!data) {
16105 localData = 1;
16106 @@ -127,20 +132,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16107
16108
16109 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
16110 - if (dev->inbandTags || (data && !tags))
16111 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
16112 + if (dev->param.inbandTags || (data && !tags))
16113 + retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk,
16114 &dummy, data);
16115 else if (tags) {
16116 ops.mode = MTD_OOB_AUTO;
16117 - ops.ooblen = sizeof(pt);
16118 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
16119 + ops.ooblen = packed_tags_size;
16120 + ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size;
16121 ops.ooboffs = 0;
16122 ops.datbuf = data;
16123 - ops.oobbuf = dev->spareBuffer;
16124 + ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer;
16125 retval = mtd->read_oob(mtd, addr, &ops);
16126 }
16127 #else
16128 - if (!dev->inbandTags && data && tags) {
16129 + if (!dev->param.inbandTags && data && tags) {
16130
16131 retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16132 &dummy, data, dev->spareBuffer,
16133 @@ -150,7 +155,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16134 retval =
16135 mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16136 data);
16137 - if (!dev->inbandTags && tags)
16138 + if (!dev->param.inbandTags && tags)
16139 retval =
16140 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
16141 dev->spareBuffer);
16142 @@ -158,7 +163,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16143 #endif
16144
16145
16146 - if (dev->inbandTags) {
16147 + if (dev->param.inbandTags) {
16148 if (tags) {
16149 yaffs_PackedTags2TagsPart *pt2tp;
16150 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
16151 @@ -166,16 +171,22 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16152 }
16153 } else {
16154 if (tags) {
16155 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
16156 - yaffs_UnpackTags2(tags, &pt);
16157 + memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size);
16158 + yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC);
16159 }
16160 }
16161
16162 if (localData)
16163 yaffs_ReleaseTempBuffer(dev, data, __LINE__);
16164
16165 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
16166 + if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16167 tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
16168 + dev->eccUnfixed++;
16169 + }
16170 + if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
16171 + tags->eccResult = YAFFS_ECC_RESULT_FIXED;
16172 + dev->eccFixed++;
16173 + }
16174 if (retval == 0)
16175 return YAFFS_OK;
16176 else
16177 @@ -184,15 +195,15 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
16178
16179 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
16180 {
16181 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16182 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16183 int retval;
16184 T(YAFFS_TRACE_MTD,
16185 (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
16186
16187 retval =
16188 mtd->block_markbad(mtd,
16189 - blockNo * dev->nChunksPerBlock *
16190 - dev->totalBytesPerChunk);
16191 + blockNo * dev->param.nChunksPerBlock *
16192 + dev->param.totalBytesPerChunk);
16193
16194 if (retval == 0)
16195 return YAFFS_OK;
16196 @@ -204,15 +215,15 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
16197 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
16198 yaffs_BlockState *state, __u32 *sequenceNumber)
16199 {
16200 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16201 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16202 int retval;
16203
16204 T(YAFFS_TRACE_MTD,
16205 (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
16206 retval =
16207 mtd->block_isbad(mtd,
16208 - blockNo * dev->nChunksPerBlock *
16209 - dev->totalBytesPerChunk);
16210 + blockNo * dev->param.nChunksPerBlock *
16211 + dev->param.totalBytesPerChunk);
16212
16213 if (retval) {
16214 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
16215 @@ -223,7 +234,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs
16216 yaffs_ExtendedTags t;
16217 nandmtd2_ReadChunkWithTagsFromNAND(dev,
16218 blockNo *
16219 - dev->nChunksPerBlock, NULL,
16220 + dev->param.nChunksPerBlock, NULL,
16221 &t);
16222
16223 if (t.chunkUsed) {
16224 diff -Nrup a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h
16225 --- a/fs/yaffs2/yaffs_mtdif2.h 2010-10-03 17:48:22.720000363 +0300
16226 +++ b/fs/yaffs2/yaffs_mtdif2.h 2010-10-03 18:03:47.545000367 +0300
16227 @@ -1,7 +1,7 @@
16228 /*
16229 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16230 *
16231 - * Copyright (C) 2002-2007 Aleph One Ltd.
16232 + * Copyright (C) 2002-2010 Aleph One Ltd.
16233 * for Toby Churchill Ltd and Brightstar Engineering
16234 *
16235 * Created by Charles Manning <charles@aleph1.co.uk>
16236 diff -Nrup a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c
16237 --- a/fs/yaffs2/yaffs_mtdif.c 2010-10-03 17:48:22.720000363 +0300
16238 +++ b/fs/yaffs2/yaffs_mtdif.c 2010-10-03 18:03:47.521000367 +0300
16239 @@ -1,7 +1,7 @@
16240 /*
16241 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16242 *
16243 - * Copyright (C) 2002-2007 Aleph One Ltd.
16244 + * Copyright (C) 2002-2010 Aleph One Ltd.
16245 * for Toby Churchill Ltd and Brightstar Engineering
16246 *
16247 * Created by Charles Manning <charles@aleph1.co.uk>
16248 @@ -11,9 +11,6 @@
16249 * published by the Free Software Foundation.
16250 */
16251
16252 -const char *yaffs_mtdif_c_version =
16253 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
16254 -
16255 #include "yportenv.h"
16256
16257
16258 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
16259 #include "linux/time.h"
16260 #include "linux/mtd/nand.h"
16261
16262 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
16263 -static struct nand_oobinfo yaffs_oobinfo = {
16264 - .useecc = 1,
16265 - .eccbytes = 6,
16266 - .eccpos = {8, 9, 10, 13, 14, 15}
16267 -};
16268 -
16269 -static struct nand_oobinfo yaffs_noeccinfo = {
16270 - .useecc = 0,
16271 -};
16272 -#endif
16273 -
16274 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16275 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
16276 -{
16277 - oob[0] = spare->tagByte0;
16278 - oob[1] = spare->tagByte1;
16279 - oob[2] = spare->tagByte2;
16280 - oob[3] = spare->tagByte3;
16281 - oob[4] = spare->tagByte4;
16282 - oob[5] = spare->tagByte5 & 0x3f;
16283 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
16284 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
16285 - oob[6] = spare->tagByte6;
16286 - oob[7] = spare->tagByte7;
16287 -}
16288 -
16289 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
16290 -{
16291 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
16292 - spare->tagByte0 = oob[0];
16293 - spare->tagByte1 = oob[1];
16294 - spare->tagByte2 = oob[2];
16295 - spare->tagByte3 = oob[3];
16296 - spare->tagByte4 = oob[4];
16297 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
16298 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
16299 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
16300 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
16301 - spare->tagByte6 = oob[6];
16302 - spare->tagByte7 = oob[7];
16303 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
16304 -
16305 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
16306 -}
16307 -#endif
16308 -
16309 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16310 - const __u8 *data, const yaffs_Spare *spare)
16311 -{
16312 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16313 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16314 - struct mtd_oob_ops ops;
16315 -#endif
16316 - size_t dummy;
16317 - int retval = 0;
16318 -
16319 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16320 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16321 - __u8 spareAsBytes[8]; /* OOB */
16322 -
16323 - if (data && !spare)
16324 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
16325 - &dummy, data);
16326 - else if (spare) {
16327 - if (dev->useNANDECC) {
16328 - translate_spare2oob(spare, spareAsBytes);
16329 - ops.mode = MTD_OOB_AUTO;
16330 - ops.ooblen = 8; /* temp hack */
16331 - } else {
16332 - ops.mode = MTD_OOB_RAW;
16333 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16334 - }
16335 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16336 - ops.datbuf = (u8 *)data;
16337 - ops.ooboffs = 0;
16338 - ops.oobbuf = spareAsBytes;
16339 - retval = mtd->write_oob(mtd, addr, &ops);
16340 - }
16341 -#else
16342 - __u8 *spareAsBytes = (__u8 *) spare;
16343 -
16344 - if (data && spare) {
16345 - if (dev->useNANDECC)
16346 - retval =
16347 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16348 - &dummy, data, spareAsBytes,
16349 - &yaffs_oobinfo);
16350 - else
16351 - retval =
16352 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
16353 - &dummy, data, spareAsBytes,
16354 - &yaffs_noeccinfo);
16355 - } else {
16356 - if (data)
16357 - retval =
16358 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16359 - data);
16360 - if (spare)
16361 - retval =
16362 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16363 - &dummy, spareAsBytes);
16364 - }
16365 -#endif
16366 -
16367 - if (retval == 0)
16368 - return YAFFS_OK;
16369 - else
16370 - return YAFFS_FAIL;
16371 -}
16372 -
16373 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16374 - yaffs_Spare *spare)
16375 -{
16376 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16377 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16378 - struct mtd_oob_ops ops;
16379 -#endif
16380 - size_t dummy;
16381 - int retval = 0;
16382 -
16383 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
16384 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
16385 - __u8 spareAsBytes[8]; /* OOB */
16386 -
16387 - if (data && !spare)
16388 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
16389 - &dummy, data);
16390 - else if (spare) {
16391 - if (dev->useNANDECC) {
16392 - ops.mode = MTD_OOB_AUTO;
16393 - ops.ooblen = 8; /* temp hack */
16394 - } else {
16395 - ops.mode = MTD_OOB_RAW;
16396 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
16397 - }
16398 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
16399 - ops.datbuf = data;
16400 - ops.ooboffs = 0;
16401 - ops.oobbuf = spareAsBytes;
16402 - retval = mtd->read_oob(mtd, addr, &ops);
16403 - if (dev->useNANDECC)
16404 - translate_oob2spare(spare, spareAsBytes);
16405 - }
16406 -#else
16407 - __u8 *spareAsBytes = (__u8 *) spare;
16408 -
16409 - if (data && spare) {
16410 - if (dev->useNANDECC) {
16411 - /* Careful, this call adds 2 ints */
16412 - /* to the end of the spare data. Calling function */
16413 - /* should allocate enough memory for spare, */
16414 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
16415 - retval =
16416 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16417 - &dummy, data, spareAsBytes,
16418 - &yaffs_oobinfo);
16419 - } else {
16420 - retval =
16421 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
16422 - &dummy, data, spareAsBytes,
16423 - &yaffs_noeccinfo);
16424 - }
16425 - } else {
16426 - if (data)
16427 - retval =
16428 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
16429 - data);
16430 - if (spare)
16431 - retval =
16432 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
16433 - &dummy, spareAsBytes);
16434 - }
16435 -#endif
16436 -
16437 - if (retval == 0)
16438 - return YAFFS_OK;
16439 - else
16440 - return YAFFS_FAIL;
16441 -}
16442 +#include "yaffs_linux.h"
16443
16444 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
16445 {
16446 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
16447 + struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
16448 __u32 addr =
16449 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
16450 - * dev->nChunksPerBlock;
16451 + ((loff_t) blockNumber) * dev->param.totalBytesPerChunk
16452 + * dev->param.nChunksPerBlock;
16453 struct erase_info ei;
16454 +
16455 int retval = 0;
16456
16457 ei.mtd = mtd;
16458 ei.addr = addr;
16459 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
16460 + ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock;
16461 ei.time = 1000;
16462 ei.retries = 2;
16463 ei.callback = NULL;
16464 ei.priv = (u_long) dev;
16465
16466 - /* Todo finish off the ei if required */
16467 -
16468 - sema_init(&dev->sem, 0);
16469 -
16470 retval = mtd->erase(mtd, &ei);
16471
16472 if (retval == 0)
16473 diff -Nrup a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h
16474 --- a/fs/yaffs2/yaffs_mtdif.h 2010-10-03 17:48:22.721000363 +0300
16475 +++ b/fs/yaffs2/yaffs_mtdif.h 2010-10-03 18:03:47.546000366 +0300
16476 @@ -1,7 +1,7 @@
16477 /*
16478 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16479 *
16480 - * Copyright (C) 2002-2007 Aleph One Ltd.
16481 + * Copyright (C) 2002-2010 Aleph One Ltd.
16482 * for Toby Churchill Ltd and Brightstar Engineering
16483 *
16484 * Created by Charles Manning <charles@aleph1.co.uk>
16485 @@ -22,11 +22,6 @@
16486 extern struct nand_oobinfo yaffs_oobinfo;
16487 extern struct nand_oobinfo yaffs_noeccinfo;
16488 #endif
16489 -
16490 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
16491 - const __u8 *data, const yaffs_Spare *spare);
16492 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
16493 - yaffs_Spare *spare);
16494 int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
16495 int nandmtd_InitialiseNAND(yaffs_Device *dev);
16496 #endif
16497 diff -Nrup a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c
16498 --- a/fs/yaffs2/yaffs_nameval.c 1970-01-01 02:00:00.000000000 +0200
16499 +++ b/fs/yaffs2/yaffs_nameval.c 2010-10-03 18:03:47.523000363 +0300
16500 @@ -0,0 +1,197 @@
16501 +/*
16502 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16503 + *
16504 + * Copyright (C) 2002-2010 Aleph One Ltd.
16505 + * for Toby Churchill Ltd and Brightstar Engineering
16506 + *
16507 + * Created by Charles Manning <charles@aleph1.co.uk>
16508 + *
16509 + * This program is free software; you can redistribute it and/or modify
16510 + * it under the terms of the GNU General Public License version 2 as
16511 + * published by the Free Software Foundation.
16512 + */
16513 +
16514 +/*
16515 + * This simple implementation of a name-value store assumes a small number of values and fits
16516 + * into a small finite buffer.
16517 + *
16518 + * Each attribute is stored as a record:
16519 + * sizeof(int) bytes record size.
16520 + * strnlen+1 bytes name null terminated.
16521 + * nbytes value.
16522 + * ----------
16523 + * total size stored in record size
16524 + *
16525 + * This code has not been tested with unicode yet.
16526 + */
16527 +
16528 +
16529 +#include "yaffs_nameval.h"
16530 +
16531 +#include "yportenv.h"
16532 +
16533 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
16534 + int *exist_size)
16535 +{
16536 + int pos=0;
16537 + int size;
16538 +
16539 + memcpy(&size,xb,sizeof(int));
16540 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16541 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
16542 + if(exist_size)
16543 + *exist_size = size;
16544 + return pos;
16545 + }
16546 + pos += size;
16547 + if(pos < xb_size -sizeof(int))
16548 + memcpy(&size,xb + pos,sizeof(int));
16549 + else
16550 + size = 0;
16551 + }
16552 + if(exist_size)
16553 + *exist_size = 0;
16554 + return -1;
16555 +}
16556 +
16557 +static int nval_used(const char *xb, int xb_size)
16558 +{
16559 + int pos=0;
16560 + int size;
16561 +
16562 + memcpy(&size,xb + pos,sizeof(int));
16563 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
16564 + pos += size;
16565 + if(pos < xb_size -sizeof(int))
16566 + memcpy(&size,xb + pos,sizeof(int));
16567 + else
16568 + size = 0;
16569 + }
16570 + return pos;
16571 +}
16572 +
16573 +int nval_del(char *xb, int xb_size, const YCHAR *name)
16574 +{
16575 + int pos = nval_find(xb, xb_size, name, NULL);
16576 + int size;
16577 +
16578 + if(pos >= 0 && pos < xb_size){
16579 + /* Find size, shift rest over this record, then zero out the rest of buffer */
16580 + memcpy(&size,xb+pos,sizeof(int));
16581 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
16582 + memset(xb + (xb_size - size),0,size);
16583 + return 0;
16584 + } else
16585 + return -ENODATA;
16586 +}
16587 +
16588 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
16589 +{
16590 + int pos;
16591 + int namelen = yaffs_strnlen(name,xb_size);
16592 + int reclen;
16593 + int size_exist = 0;
16594 + int space;
16595 + int start;
16596 +
16597 + pos = nval_find(xb,xb_size,name, &size_exist);
16598 +
16599 + if(flags & XATTR_CREATE && pos >= 0)
16600 + return -EEXIST;
16601 + if(flags & XATTR_REPLACE && pos < 0)
16602 + return -ENODATA;
16603 +
16604 + start = nval_used(xb,xb_size);
16605 + space = xb_size - start + size_exist;
16606 +
16607 + reclen = (sizeof(int) + namelen + 1 + bsize);
16608 +
16609 + if(reclen > space)
16610 + return -ENOSPC;
16611 +
16612 + if(pos >= 0){
16613 + nval_del(xb,xb_size,name);
16614 + start = nval_used(xb, xb_size);
16615 + }
16616 +
16617 + pos = start;
16618 +
16619 + memcpy(xb + pos,&reclen,sizeof(int));
16620 + pos +=sizeof(int);
16621 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
16622 + pos+= (namelen+1);
16623 + memcpy(xb + pos,buf,bsize);
16624 + return 0;
16625 +}
16626 +
16627 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
16628 +{
16629 + int pos = nval_find(xb,xb_size,name,NULL);
16630 + int size;
16631 +
16632 + if(pos >= 0 && pos< xb_size){
16633 +
16634 + memcpy(&size,xb +pos,sizeof(int));
16635 + pos+=sizeof(int); /* advance past record length */
16636 + size -= sizeof(int);
16637 +
16638 + /* Advance over name string */
16639 + while(xb[pos] && size > 0 && pos < xb_size){
16640 + pos++;
16641 + size--;
16642 + }
16643 + /*Advance over NUL */
16644 + pos++;
16645 + size--;
16646 +
16647 + if(size <= bsize){
16648 + memcpy(buf,xb + pos,size);
16649 + return size;
16650 + }
16651 +
16652 + }
16653 + if(pos >= 0)
16654 + return -ERANGE;
16655 + else
16656 + return -ENODATA;
16657 +}
16658 +
16659 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
16660 +{
16661 + int pos = 0;
16662 + int size;
16663 + int name_len;
16664 + int ncopied = 0;
16665 + int filled = 0;
16666 +
16667 + memcpy(&size,xb + pos,sizeof(int));
16668 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
16669 + pos+= sizeof(int);
16670 + size-=sizeof(int);
16671 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
16672 + if(ncopied + name_len + 1 < bsize){
16673 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
16674 + buf+= name_len;
16675 + *buf = '\0';
16676 + buf++;
16677 + if(sizeof(YCHAR) > 1){
16678 + *buf = '\0';
16679 + buf++;
16680 + }
16681 + ncopied += (name_len+1);
16682 + } else
16683 + filled = 1;
16684 + pos+=size;
16685 + if(pos < xb_size -sizeof(int))
16686 + memcpy(&size,xb + pos,sizeof(int));
16687 + else
16688 + size = 0;
16689 + }
16690 + return ncopied;
16691 +}
16692 +
16693 +
16694 +int nval_hasvalues(const char *xb, int xb_size)
16695 +{
16696 + return nval_used(xb, xb_size) > 0;
16697 +}
16698 diff -Nrup a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h
16699 --- a/fs/yaffs2/yaffs_nameval.h 1970-01-01 02:00:00.000000000 +0200
16700 +++ b/fs/yaffs2/yaffs_nameval.h 2010-10-03 18:03:47.546000366 +0300
16701 @@ -0,0 +1,25 @@
16702 +/*
16703 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16704 + *
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 + *
16710 + * This program is free software; you can redistribute it and/or modify
16711 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16712 + * published by the Free Software Foundation.
16713 + *
16714 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16715 + */
16716 +#ifndef __NAMEVAL_H__
16717 +#define __NAMEVAL_H__
16718 +
16719 +#include "yportenv.h"
16720 +
16721 +int nval_del(char *xb, int xb_size, const YCHAR *name);
16722 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
16723 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
16724 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
16725 +int nval_hasvalues(const char *xb, int xb_size);
16726 +#endif
16727 diff -Nrup a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
16728 --- a/fs/yaffs2/yaffs_nand.c 2010-10-03 17:48:22.721000363 +0300
16729 +++ b/fs/yaffs2/yaffs_nand.c 2010-10-03 18:03:47.524000359 +0300
16730 @@ -1,7 +1,7 @@
16731 /*
16732 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16733 *
16734 - * Copyright (C) 2002-2007 Aleph One Ltd.
16735 + * Copyright (C) 2002-2010 Aleph One Ltd.
16736 * for Toby Churchill Ltd and Brightstar Engineering
16737 *
16738 * Created by Charles Manning <charles@aleph1.co.uk>
16739 @@ -11,9 +11,6 @@
16740 * published by the Free Software Foundation.
16741 */
16742
16743 -const char *yaffs_nand_c_version =
16744 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
16745 -
16746 #include "yaffs_nand.h"
16747 #include "yaffs_tagscompat.h"
16748 #include "yaffs_tagsvalidity.h"
16749 @@ -29,12 +26,14 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16750
16751 int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
16752
16753 + dev->nPageReads++;
16754 +
16755 /* If there are no tags provided, use local tags to get prioritised gc working */
16756 if (!tags)
16757 tags = &localTags;
16758
16759 - if (dev->readChunkWithTagsFromNAND)
16760 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16761 + if (dev->param.readChunkWithTagsFromNAND)
16762 + result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
16763 tags);
16764 else
16765 result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
16766 @@ -44,7 +43,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaff
16767 if (tags &&
16768 tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
16769
16770 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
16771 + yaffs_BlockInfo *bi;
16772 + bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock);
16773 yaffs_HandleChunkError(dev, bi);
16774 }
16775
16776 @@ -56,6 +56,9 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16777 const __u8 *buffer,
16778 yaffs_ExtendedTags *tags)
16779 {
16780 +
16781 + dev->nPageWrites++;
16782 +
16783 chunkInNAND -= dev->chunkOffset;
16784
16785
16786 @@ -75,8 +78,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs
16787 YBUG();
16788 }
16789
16790 - if (dev->writeChunkWithTagsToNAND)
16791 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16792 + if (dev->param.writeChunkWithTagsToNAND)
16793 + return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
16794 tags);
16795 else
16796 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
16797 @@ -89,9 +92,9 @@ int yaffs_MarkBlockBad(yaffs_Device *dev
16798 {
16799 blockNo -= dev->blockOffset;
16800
16801 -;
16802 - if (dev->markNANDBlockBad)
16803 - return dev->markNANDBlockBad(dev, blockNo);
16804 +
16805 + if (dev->param.markNANDBlockBad)
16806 + return dev->param.markNANDBlockBad(dev, blockNo);
16807 else
16808 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
16809 }
16810 @@ -103,8 +106,8 @@ int yaffs_QueryInitialBlockState(yaffs_D
16811 {
16812 blockNo -= dev->blockOffset;
16813
16814 - if (dev->queryNANDBlock)
16815 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
16816 + if (dev->param.queryNANDBlock)
16817 + return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber);
16818 else
16819 return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
16820 state,
16821 @@ -119,16 +122,18 @@ int yaffs_EraseBlockInNAND(struct yaffs_
16822
16823 blockInNAND -= dev->blockOffset;
16824
16825 -
16826 dev->nBlockErasures++;
16827 - result = dev->eraseBlockInNAND(dev, blockInNAND);
16828 +
16829 + result = dev->param.eraseBlockInNAND(dev, blockInNAND);
16830
16831 return result;
16832 }
16833
16834 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
16835 {
16836 - return dev->initialiseNAND(dev);
16837 + if(dev->param.initialiseNAND)
16838 + return dev->param.initialiseNAND(dev);
16839 + return YAFFS_OK;
16840 }
16841
16842
16843 diff -Nrup a/fs/yaffs2/yaffs_nandemul2k.h b/fs/yaffs2/yaffs_nandemul2k.h
16844 --- a/fs/yaffs2/yaffs_nandemul2k.h 2010-10-03 17:48:22.721000364 +0300
16845 +++ b/fs/yaffs2/yaffs_nandemul2k.h 2010-10-03 18:03:47.546000366 +0300
16846 @@ -1,7 +1,7 @@
16847 /*
16848 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16849 *
16850 - * Copyright (C) 2002-2007 Aleph One Ltd.
16851 + * Copyright (C) 2002-2010 Aleph One Ltd.
16852 * for Toby Churchill Ltd and Brightstar Engineering
16853 *
16854 * Created by Charles Manning <charles@aleph1.co.uk>
16855 diff -Nrup a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
16856 --- a/fs/yaffs2/yaffs_nand.h 2010-10-03 17:48:22.721000364 +0300
16857 +++ b/fs/yaffs2/yaffs_nand.h 2010-10-03 18:03:47.547000363 +0300
16858 @@ -1,7 +1,7 @@
16859 /*
16860 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16861 *
16862 - * Copyright (C) 2002-2007 Aleph One Ltd.
16863 + * Copyright (C) 2002-2010 Aleph One Ltd.
16864 * for Toby Churchill Ltd and Brightstar Engineering
16865 *
16866 * Created by Charles Manning <charles@aleph1.co.uk>
16867 diff -Nrup a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c
16868 --- a/fs/yaffs2/yaffs_packedtags1.c 2010-10-03 17:48:22.721000364 +0300
16869 +++ b/fs/yaffs2/yaffs_packedtags1.c 2010-10-03 18:03:47.524000359 +0300
16870 @@ -1,7 +1,7 @@
16871 /*
16872 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16873 *
16874 - * Copyright (C) 2002-2007 Aleph One Ltd.
16875 + * Copyright (C) 2002-2010 Aleph One Ltd.
16876 * for Toby Churchill Ltd and Brightstar Engineering
16877 *
16878 * Created by Charles Manning <charles@aleph1.co.uk>
16879 diff -Nrup a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h
16880 --- a/fs/yaffs2/yaffs_packedtags1.h 2010-10-03 17:48:22.721000364 +0300
16881 +++ b/fs/yaffs2/yaffs_packedtags1.h 2010-10-03 18:03:47.547000363 +0300
16882 @@ -1,7 +1,7 @@
16883 /*
16884 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16885 *
16886 - * Copyright (C) 2002-2007 Aleph One Ltd.
16887 + * Copyright (C) 2002-2010 Aleph One Ltd.
16888 * for Toby Churchill Ltd and Brightstar Engineering
16889 *
16890 * Created by Charles Manning <charles@aleph1.co.uk>
16891 diff -Nrup a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
16892 --- a/fs/yaffs2/yaffs_packedtags2.c 2010-10-03 17:48:22.722000365 +0300
16893 +++ b/fs/yaffs2/yaffs_packedtags2.c 2010-10-03 18:03:47.524000359 +0300
16894 @@ -1,7 +1,7 @@
16895 /*
16896 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
16897 *
16898 - * Copyright (C) 2002-2007 Aleph One Ltd.
16899 + * Copyright (C) 2002-2010 Aleph One Ltd.
16900 * for Toby Churchill Ltd and Brightstar Engineering
16901 *
16902 * Created by Charles Manning <charles@aleph1.co.uk>
16903 @@ -13,6 +13,7 @@
16904
16905 #include "yaffs_packedtags2.h"
16906 #include "yportenv.h"
16907 +#include "yaffs_trace.h"
16908 #include "yaffs_tagsvalidity.h"
16909
16910 /* This code packs a set of extended tags into a binary structure for
16911 @@ -96,17 +97,14 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
16912 }
16913
16914
16915 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
16916 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC)
16917 {
16918 yaffs_PackTags2TagsPart(&pt->t, t);
16919
16920 -#ifndef YAFFS_IGNORE_TAGS_ECC
16921 - {
16922 + if(tagsECC)
16923 yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16924 sizeof(yaffs_PackedTags2TagsPart),
16925 &pt->ecc);
16926 - }
16927 -#endif
16928 }
16929
16930
16931 @@ -158,27 +156,24 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
16932 }
16933
16934
16935 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
16936 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC)
16937 {
16938
16939 yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16940
16941 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
16942 - /* Page is in use */
16943 -#ifndef YAFFS_IGNORE_TAGS_ECC
16944 - {
16945 - yaffs_ECCOther ecc;
16946 - int result;
16947 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16948 - sizeof
16949 - (yaffs_PackedTags2TagsPart),
16950 - &ecc);
16951 - result =
16952 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16953 - sizeof
16954 - (yaffs_PackedTags2TagsPart),
16955 - &pt->ecc, &ecc);
16956 - switch (result) {
16957 + if (pt->t.sequenceNumber != 0xFFFFFFFF &&
16958 + tagsECC){
16959 + /* Chunk is in use and we need to do ECC */
16960 +
16961 + yaffs_ECCOther ecc;
16962 + int result;
16963 + yaffs_ECCCalculateOther((unsigned char *)&pt->t,
16964 + sizeof(yaffs_PackedTags2TagsPart),
16965 + &ecc);
16966 + result = yaffs_ECCCorrectOther((unsigned char *)&pt->t,
16967 + sizeof(yaffs_PackedTags2TagsPart),
16968 + &pt->ecc, &ecc);
16969 + switch (result) {
16970 case 0:
16971 eccResult = YAFFS_ECC_RESULT_NO_ERROR;
16972 break;
16973 @@ -190,9 +185,7 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16974 break;
16975 default:
16976 eccResult = YAFFS_ECC_RESULT_UNKNOWN;
16977 - }
16978 }
16979 -#endif
16980 }
16981
16982 yaffs_UnpackTags2TagsPart(t, &pt->t);
16983 @@ -201,6 +194,5 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
16984
16985 yaffs_DumpPackedTags2(pt);
16986 yaffs_DumpTags2(t);
16987 -
16988 }
16989
16990 diff -Nrup a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h
16991 --- a/fs/yaffs2/yaffs_packedtags2.h 2010-10-03 17:48:22.722000365 +0300
16992 +++ b/fs/yaffs2/yaffs_packedtags2.h 2010-10-03 18:03:47.547000363 +0300
16993 @@ -1,7 +1,7 @@
16994 /*
16995 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16996 *
16997 - * Copyright (C) 2002-2007 Aleph One Ltd.
16998 + * Copyright (C) 2002-2010 Aleph One Ltd.
16999 * for Toby Churchill Ltd and Brightstar Engineering
17000 *
17001 * Created by Charles Manning <charles@aleph1.co.uk>
17002 @@ -34,8 +34,8 @@ typedef struct {
17003 } yaffs_PackedTags2;
17004
17005 /* Full packed tags with ECC, used for oob tags */
17006 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
17007 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
17008 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC);
17009 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC);
17010
17011 /* Only the tags part (no ECC for use with inband tags */
17012 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
17013 diff -Nrup a/fs/yaffs2/yaffs_qsort.h b/fs/yaffs2/yaffs_qsort.h
17014 --- a/fs/yaffs2/yaffs_qsort.h 2010-10-03 17:48:22.724000363 +0300
17015 +++ b/fs/yaffs2/yaffs_qsort.h 2010-10-03 18:03:47.548000359 +0300
17016 @@ -1,7 +1,7 @@
17017 /*
17018 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17019 *
17020 - * Copyright (C) 2002-2007 Aleph One Ltd.
17021 + * Copyright (C) 2002-2010 Aleph One Ltd.
17022 * for Toby Churchill Ltd and Brightstar Engineering
17023 *
17024 * Created by Charles Manning <charles@aleph1.co.uk>
17025 @@ -17,7 +17,18 @@
17026 #ifndef __YAFFS_QSORT_H__
17027 #define __YAFFS_QSORT_H__
17028
17029 +#ifdef __KERNEL__
17030 +#include <linux/sort.h>
17031 +
17032 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
17033 + int (*cmp)(const void *, const void *)){
17034 + sort(base, total_elems, size, cmp, NULL);
17035 +}
17036 +
17037 +#else
17038 +
17039 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
17040 int (*cmp)(const void *, const void *));
17041
17042 #endif
17043 +#endif
17044 diff -Nrup a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
17045 --- a/fs/yaffs2/yaffs_tagscompat.c 2010-10-03 17:48:22.724000363 +0300
17046 +++ b/fs/yaffs2/yaffs_tagscompat.c 2010-10-03 18:03:47.525000359 +0300
17047 @@ -1,7 +1,7 @@
17048 /*
17049 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17050 *
17051 - * Copyright (C) 2002-2007 Aleph One Ltd.
17052 + * Copyright (C) 2002-2010 Aleph One Ltd.
17053 * for Toby Churchill Ltd and Brightstar Engineering
17054 *
17055 * Created by Charles Manning <charles@aleph1.co.uk>
17056 @@ -15,6 +15,7 @@
17057 #include "yaffs_tagscompat.h"
17058 #include "yaffs_ecc.h"
17059 #include "yaffs_getblockinfo.h"
17060 +#include "yaffs_trace.h"
17061
17062 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
17063 #ifdef NOTYET
17064 @@ -163,15 +164,14 @@ static int yaffs_WriteChunkToNAND(struct
17065 int chunkInNAND, const __u8 *data,
17066 yaffs_Spare *spare)
17067 {
17068 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
17069 + if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) {
17070 T(YAFFS_TRACE_ERROR,
17071 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
17072 chunkInNAND));
17073 return YAFFS_FAIL;
17074 }
17075
17076 - dev->nPageWrites++;
17077 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
17078 + return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare);
17079 }
17080
17081 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
17082 @@ -184,16 +184,14 @@ static int yaffs_ReadChunkFromNAND(struc
17083 int retVal;
17084 yaffs_Spare localSpare;
17085
17086 - dev->nPageReads++;
17087 -
17088 if (!spare && data) {
17089 /* If we don't have a real spare, then we use a local one. */
17090 /* Need this for the calculation of the ecc */
17091 spare = &localSpare;
17092 }
17093
17094 - if (!dev->useNANDECC) {
17095 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
17096 + if (!dev->param.useNANDECC) {
17097 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare);
17098 if (data && doErrorCorrection) {
17099 /* Do ECC correction */
17100 /* Todo handle any errors */
17101 @@ -254,7 +252,7 @@ static int yaffs_ReadChunkFromNAND(struc
17102
17103 memset(&nspare, 0, sizeof(nspare));
17104
17105 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
17106 + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data,
17107 (yaffs_Spare *) &nspare);
17108 memcpy(spare, &nspare, sizeof(yaffs_Spare));
17109 if (data && doErrorCorrection) {
17110 @@ -307,10 +305,10 @@ static int yaffs_CheckChunkErased(struct
17111 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
17112 static __u8 data[YAFFS_BYTES_PER_CHUNK];
17113 /* Might as well always allocate the larger size for */
17114 - /* dev->useNANDECC == true; */
17115 + /* dev->param.useNANDECC == true; */
17116 static __u8 spare[sizeof(struct yaffs_NANDSpare)];
17117
17118 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17119 + dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
17120
17121 if (!init) {
17122 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
17123 @@ -333,7 +331,7 @@ static int yaffs_CheckChunkErased(struct
17124
17125 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
17126 {
17127 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17128 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17129
17130 /* Mark the block for retirement */
17131 yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
17132 @@ -365,7 +363,7 @@ static void yaffs_HandleUpdateChunk(yaff
17133
17134 static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
17135 {
17136 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
17137 + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
17138
17139 /* Mark the block for retirement */
17140 yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
17141 @@ -424,7 +422,7 @@ int yaffs_TagsCompatabilityWriteChunkWit
17142
17143 tags.serialNumber = eTags->serialNumber;
17144
17145 - if (!dev->useNANDECC && data)
17146 + if (!dev->param.useNANDECC && data)
17147 yaffs_CalcECC(data, &spare);
17148
17149 yaffs_LoadTagsIntoSpare(&spare, &tags);
17150 @@ -498,9 +496,9 @@ int yaffs_TagsCompatabilityMarkNANDBlock
17151
17152 spare.blockStatus = 'Y';
17153
17154 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
17155 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL,
17156 &spare);
17157 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
17158 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1,
17159 NULL, &spare);
17160
17161 return YAFFS_OK;
17162 @@ -525,9 +523,9 @@ int yaffs_TagsCompatabilityQueryNANDBloc
17163
17164 *sequenceNumber = 0;
17165
17166 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
17167 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL,
17168 &spare0, &dummy, 1);
17169 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
17170 + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL,
17171 &spare1, &dummy, 1);
17172
17173 if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
17174 diff -Nrup a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h
17175 --- a/fs/yaffs2/yaffs_tagscompat.h 2010-10-03 17:48:22.724000363 +0300
17176 +++ b/fs/yaffs2/yaffs_tagscompat.h 2010-10-03 18:03:47.548000359 +0300
17177 @@ -1,7 +1,7 @@
17178 /*
17179 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17180 *
17181 - * Copyright (C) 2002-2007 Aleph One Ltd.
17182 + * Copyright (C) 2002-2010 Aleph One Ltd.
17183 * for Toby Churchill Ltd and Brightstar Engineering
17184 *
17185 * Created by Charles Manning <charles@aleph1.co.uk>
17186 diff -Nrup a/fs/yaffs2/yaffs_tagsvalidity.c b/fs/yaffs2/yaffs_tagsvalidity.c
17187 --- a/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-03 17:48:22.725000363 +0300
17188 +++ b/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-03 18:03:47.526000362 +0300
17189 @@ -1,7 +1,7 @@
17190 /*
17191 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17192 *
17193 - * Copyright (C) 2002-2007 Aleph One Ltd.
17194 + * Copyright (C) 2002-2010 Aleph One Ltd.
17195 * for Toby Churchill Ltd and Brightstar Engineering
17196 *
17197 * Created by Charles Manning <charles@aleph1.co.uk>
17198 diff -Nrup a/fs/yaffs2/yaffs_tagsvalidity.h b/fs/yaffs2/yaffs_tagsvalidity.h
17199 --- a/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-03 17:48:22.725000363 +0300
17200 +++ b/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-03 18:03:47.549000359 +0300
17201 @@ -1,7 +1,7 @@
17202 /*
17203 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17204 *
17205 - * Copyright (C) 2002-2007 Aleph One Ltd.
17206 + * Copyright (C) 2002-2010 Aleph One Ltd.
17207 * for Toby Churchill Ltd and Brightstar Engineering
17208 *
17209 * Created by Charles Manning <charles@aleph1.co.uk>
17210 diff -Nrup a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h
17211 --- a/fs/yaffs2/yaffs_trace.h 1970-01-01 02:00:00.000000000 +0200
17212 +++ b/fs/yaffs2/yaffs_trace.h 2010-10-03 18:03:47.550000362 +0300
17213 @@ -0,0 +1,60 @@
17214 +/*
17215 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17216 + *
17217 + * Copyright (C) 2002-2010 Aleph One Ltd.
17218 + * for Toby Churchill Ltd and Brightstar Engineering
17219 + *
17220 + * Created by Charles Manning <charles@aleph1.co.uk>
17221 + *
17222 + * This program is free software; you can redistribute it and/or modify
17223 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17224 + * published by the Free Software Foundation.
17225 + *
17226 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17227 + */
17228 +
17229 +
17230 +#ifndef __YTRACE_H__
17231 +#define __YTRACE_H__
17232 +
17233 +extern unsigned int yaffs_traceMask;
17234 +extern unsigned int yaffs_wr_attempts;
17235 +
17236 +/*
17237 + * Tracing flags.
17238 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
17239 + */
17240 +
17241 +#define YAFFS_TRACE_OS 0x00000002
17242 +#define YAFFS_TRACE_ALLOCATE 0x00000004
17243 +#define YAFFS_TRACE_SCAN 0x00000008
17244 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
17245 +#define YAFFS_TRACE_ERASE 0x00000020
17246 +#define YAFFS_TRACE_GC 0x00000040
17247 +#define YAFFS_TRACE_WRITE 0x00000080
17248 +#define YAFFS_TRACE_TRACING 0x00000100
17249 +#define YAFFS_TRACE_DELETION 0x00000200
17250 +#define YAFFS_TRACE_BUFFERS 0x00000400
17251 +#define YAFFS_TRACE_NANDACCESS 0x00000800
17252 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
17253 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
17254 +#define YAFFS_TRACE_MTD 0x00004000
17255 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
17256 +
17257 +#define YAFFS_TRACE_VERIFY 0x00010000
17258 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
17259 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
17260 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
17261 +
17262 +#define YAFFS_TRACE_SYNC 0x00100000
17263 +#define YAFFS_TRACE_BACKGROUND 0x00200000
17264 +#define YAFFS_TRACE_LOCK 0x00400000
17265 +
17266 +#define YAFFS_TRACE_ERROR 0x40000000
17267 +#define YAFFS_TRACE_BUG 0x80000000
17268 +#define YAFFS_TRACE_ALWAYS 0xF0000000
17269 +
17270 +
17271 +#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
17272 +
17273 +#endif
17274 diff -Nrup a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c
17275 --- a/fs/yaffs2/yaffs_verify.c 1970-01-01 02:00:00.000000000 +0200
17276 +++ b/fs/yaffs2/yaffs_verify.c 2010-10-03 18:03:47.527000365 +0300
17277 @@ -0,0 +1,626 @@
17278 +/*
17279 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17280 + *
17281 + * Copyright (C) 2002-2010 Aleph One Ltd.
17282 + * for Toby Churchill Ltd and Brightstar Engineering
17283 + *
17284 + * Created by Charles Manning <charles@aleph1.co.uk>
17285 + *
17286 + * This program is free software; you can redistribute it and/or modify
17287 + * it under the terms of the GNU General Public License version 2 as
17288 + * published by the Free Software Foundation.
17289 + */
17290 +
17291 +
17292 +#include "yaffs_verify.h"
17293 +#include "yaffs_trace.h"
17294 +#include "yaffs_bitmap.h"
17295 +#include "yaffs_getblockinfo.h"
17296 +#include "yaffs_nand.h"
17297 +
17298 +int yaffs_SkipVerification(yaffs_Device *dev)
17299 +{
17300 + dev=dev;
17301 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
17302 +}
17303 +
17304 +static int yaffs_SkipFullVerification(yaffs_Device *dev)
17305 +{
17306 + dev=dev;
17307 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
17308 +}
17309 +
17310 +static int yaffs_SkipNANDVerification(yaffs_Device *dev)
17311 +{
17312 + dev=dev;
17313 + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
17314 +}
17315 +
17316 +
17317 +static const char *blockStateName[] = {
17318 +"Unknown",
17319 +"Needs scanning",
17320 +"Scanning",
17321 +"Empty",
17322 +"Allocating",
17323 +"Full",
17324 +"Dirty",
17325 +"Checkpoint",
17326 +"Collecting",
17327 +"Dead"
17328 +};
17329 +
17330 +
17331 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17332 +{
17333 + int actuallyUsed;
17334 + int inUse;
17335 +
17336 + if (yaffs_SkipVerification(dev))
17337 + return;
17338 +
17339 + /* Report illegal runtime states */
17340 + if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
17341 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
17342 +
17343 + switch (bi->blockState) {
17344 + case YAFFS_BLOCK_STATE_UNKNOWN:
17345 + case YAFFS_BLOCK_STATE_SCANNING:
17346 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
17347 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
17348 + n, blockStateName[bi->blockState]));
17349 + }
17350 +
17351 + /* Check pages in use and soft deletions are legal */
17352 +
17353 + actuallyUsed = bi->pagesInUse - bi->softDeletions;
17354 +
17355 + if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
17356 + bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
17357 + actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
17358 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
17359 + n, bi->pagesInUse, bi->softDeletions));
17360 +
17361 +
17362 + /* Check chunk bitmap legal */
17363 + inUse = yaffs_CountChunkBits(dev, n);
17364 + if (inUse != bi->pagesInUse)
17365 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
17366 + n, bi->pagesInUse, inUse));
17367 +
17368 +}
17369 +
17370 +
17371 +
17372 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
17373 +{
17374 + yaffs_VerifyBlock(dev, bi, n);
17375 +
17376 + /* After collection the block should be in the erased state */
17377 +
17378 + if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
17379 + bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
17380 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
17381 + n, bi->blockState));
17382 + }
17383 +}
17384 +
17385 +void yaffs_VerifyBlocks(yaffs_Device *dev)
17386 +{
17387 + int i;
17388 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
17389 + int nIllegalBlockStates = 0;
17390 +
17391 + if (yaffs_SkipVerification(dev))
17392 + return;
17393 +
17394 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
17395 +
17396 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
17397 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
17398 + yaffs_VerifyBlock(dev, bi, i);
17399 +
17400 + if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
17401 + nBlocksPerState[bi->blockState]++;
17402 + else
17403 + nIllegalBlockStates++;
17404 + }
17405 +
17406 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17407 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
17408 +
17409 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
17410 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
17411 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
17412 +
17413 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
17414 + T(YAFFS_TRACE_VERIFY,
17415 + (TSTR("%s %d blocks"TENDSTR),
17416 + blockStateName[i], nBlocksPerState[i]));
17417 +
17418 + if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
17419 + T(YAFFS_TRACE_VERIFY,
17420 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
17421 + dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
17422 +
17423 + if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
17424 + T(YAFFS_TRACE_VERIFY,
17425 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
17426 + dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
17427 +
17428 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
17429 + T(YAFFS_TRACE_VERIFY,
17430 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
17431 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
17432 +
17433 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
17434 +
17435 +}
17436 +
17437 +/*
17438 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
17439 + * case those tests will not be performed.
17440 + */
17441 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
17442 +{
17443 + if (obj && yaffs_SkipVerification(obj->myDev))
17444 + return;
17445 +
17446 + if (!(tags && obj && oh)) {
17447 + T(YAFFS_TRACE_VERIFY,
17448 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
17449 + tags, obj, oh));
17450 + return;
17451 + }
17452 +
17453 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
17454 + oh->type > YAFFS_OBJECT_TYPE_MAX)
17455 + T(YAFFS_TRACE_VERIFY,
17456 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
17457 + tags->objectId, oh->type));
17458 +
17459 + if (tags->objectId != obj->objectId)
17460 + T(YAFFS_TRACE_VERIFY,
17461 + (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
17462 + tags->objectId, obj->objectId));
17463 +
17464 +
17465 + /*
17466 + * Check that the object's parent ids match if parentCheck requested.
17467 + *
17468 + * Tests do not apply to the root object.
17469 + */
17470 +
17471 + if (parentCheck && tags->objectId > 1 && !obj->parent)
17472 + T(YAFFS_TRACE_VERIFY,
17473 + (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
17474 + tags->objectId, oh->parentObjectId));
17475 +
17476 + if (parentCheck && obj->parent &&
17477 + oh->parentObjectId != obj->parent->objectId &&
17478 + (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
17479 + obj->parent->objectId != YAFFS_OBJECTID_DELETED))
17480 + T(YAFFS_TRACE_VERIFY,
17481 + (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
17482 + tags->objectId, oh->parentObjectId, obj->parent->objectId));
17483 +
17484 + if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
17485 + T(YAFFS_TRACE_VERIFY,
17486 + (TSTR("Obj %d header name is NULL"TENDSTR),
17487 + obj->objectId));
17488 +
17489 + if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
17490 + T(YAFFS_TRACE_VERIFY,
17491 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
17492 + obj->objectId));
17493 +}
17494 +
17495 +
17496 +#if 0
17497 +/* Not being used, but don't want to throw away yet */
17498 +int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
17499 + __u32 level, int chunkOffset)
17500 +{
17501 + int i;
17502 + yaffs_Device *dev = obj->myDev;
17503 + int ok = 1;
17504 +
17505 + if (tn) {
17506 + if (level > 0) {
17507 +
17508 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
17509 + if (tn->internal[i]) {
17510 + ok = yaffs_VerifyTnodeWorker(obj,
17511 + tn->internal[i],
17512 + level - 1,
17513 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
17514 + }
17515 + }
17516 + } else if (level == 0) {
17517 + yaffs_ExtendedTags tags;
17518 + __u32 objectId = obj->objectId;
17519 +
17520 + chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
17521 +
17522 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
17523 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17524 +
17525 + if (theChunk > 0) {
17526 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
17527 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17528 + if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
17529 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17530 + objectId, chunkOffset, theChunk,
17531 + tags.objectId, tags.chunkId));
17532 + }
17533 + }
17534 + chunkOffset++;
17535 + }
17536 + }
17537 + }
17538 +
17539 + return ok;
17540 +
17541 +}
17542 +
17543 +#endif
17544 +
17545 +void yaffs_VerifyFile(yaffs_Object *obj)
17546 +{
17547 + int requiredTallness;
17548 + int actualTallness;
17549 + __u32 lastChunk;
17550 + __u32 x;
17551 + __u32 i;
17552 + yaffs_Device *dev;
17553 + yaffs_ExtendedTags tags;
17554 + yaffs_Tnode *tn;
17555 + __u32 objectId;
17556 +
17557 + if (!obj)
17558 + return;
17559 +
17560 + if (yaffs_SkipVerification(obj->myDev))
17561 + return;
17562 +
17563 + dev = obj->myDev;
17564 + objectId = obj->objectId;
17565 +
17566 + /* Check file size is consistent with tnode depth */
17567 + lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
17568 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
17569 + requiredTallness = 0;
17570 + while (x > 0) {
17571 + x >>= YAFFS_TNODES_INTERNAL_BITS;
17572 + requiredTallness++;
17573 + }
17574 +
17575 + actualTallness = obj->variant.fileVariant.topLevel;
17576 +
17577 + /* Check that the chunks in the tnode tree are all correct.
17578 + * We do this by scanning through the tnode tree and
17579 + * checking the tags for every chunk match.
17580 + */
17581 +
17582 + if (yaffs_SkipNANDVerification(dev))
17583 + return;
17584 +
17585 + for (i = 1; i <= lastChunk; i++) {
17586 + tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
17587 +
17588 + if (tn) {
17589 + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
17590 + if (theChunk > 0) {
17591 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
17592 + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
17593 + if (tags.objectId != objectId || tags.chunkId != i) {
17594 + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
17595 + objectId, i, theChunk,
17596 + tags.objectId, tags.chunkId));
17597 + }
17598 + }
17599 + }
17600 + }
17601 +}
17602 +
17603 +
17604 +void yaffs_VerifyHardLink(yaffs_Object *obj)
17605 +{
17606 + if (obj && yaffs_SkipVerification(obj->myDev))
17607 + return;
17608 +
17609 + /* Verify sane equivalent object */
17610 +}
17611 +
17612 +void yaffs_VerifySymlink(yaffs_Object *obj)
17613 +{
17614 + if (obj && yaffs_SkipVerification(obj->myDev))
17615 + return;
17616 +
17617 + /* Verify symlink string */
17618 +}
17619 +
17620 +void yaffs_VerifySpecial(yaffs_Object *obj)
17621 +{
17622 + if (obj && yaffs_SkipVerification(obj->myDev))
17623 + return;
17624 +}
17625 +
17626 +void yaffs_VerifyObject(yaffs_Object *obj)
17627 +{
17628 + yaffs_Device *dev;
17629 +
17630 + __u32 chunkMin;
17631 + __u32 chunkMax;
17632 +
17633 + __u32 chunkIdOk;
17634 + __u32 chunkInRange;
17635 + __u32 chunkShouldNotBeDeleted;
17636 + __u32 chunkValid;
17637 +
17638 + if (!obj)
17639 + return;
17640 +
17641 + if (obj->beingCreated)
17642 + return;
17643 +
17644 + dev = obj->myDev;
17645 +
17646 + if (yaffs_SkipVerification(dev))
17647 + return;
17648 +
17649 + /* Check sane object header chunk */
17650 +
17651 + chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
17652 + chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
17653 +
17654 + chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
17655 + chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
17656 + chunkValid = chunkInRange &&
17657 + yaffs_CheckChunkBit(dev,
17658 + obj->hdrChunk / dev->param.nChunksPerBlock,
17659 + obj->hdrChunk % dev->param.nChunksPerBlock);
17660 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
17661 +
17662 + if (!obj->fake &&
17663 + (!chunkIdOk || chunkShouldNotBeDeleted)) {
17664 + T(YAFFS_TRACE_VERIFY,
17665 + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
17666 + obj->objectId, obj->hdrChunk,
17667 + chunkIdOk ? "" : ",out of range",
17668 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
17669 + }
17670 +
17671 + if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
17672 + yaffs_ExtendedTags tags;
17673 + yaffs_ObjectHeader *oh;
17674 + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
17675 +
17676 + oh = (yaffs_ObjectHeader *)buffer;
17677 +
17678 + yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
17679 + &tags);
17680 +
17681 + yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
17682 +
17683 + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
17684 + }
17685 +
17686 + /* Verify it has a parent */
17687 + if (obj && !obj->fake &&
17688 + (!obj->parent || obj->parent->myDev != dev)) {
17689 + T(YAFFS_TRACE_VERIFY,
17690 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
17691 + obj->objectId, obj->parent));
17692 + }
17693 +
17694 + /* Verify parent is a directory */
17695 + if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17696 + T(YAFFS_TRACE_VERIFY,
17697 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
17698 + obj->objectId, obj->parent->variantType));
17699 + }
17700 +
17701 + switch (obj->variantType) {
17702 + case YAFFS_OBJECT_TYPE_FILE:
17703 + yaffs_VerifyFile(obj);
17704 + break;
17705 + case YAFFS_OBJECT_TYPE_SYMLINK:
17706 + yaffs_VerifySymlink(obj);
17707 + break;
17708 + case YAFFS_OBJECT_TYPE_DIRECTORY:
17709 + yaffs_VerifyDirectory(obj);
17710 + break;
17711 + case YAFFS_OBJECT_TYPE_HARDLINK:
17712 + yaffs_VerifyHardLink(obj);
17713 + break;
17714 + case YAFFS_OBJECT_TYPE_SPECIAL:
17715 + yaffs_VerifySpecial(obj);
17716 + break;
17717 + case YAFFS_OBJECT_TYPE_UNKNOWN:
17718 + default:
17719 + T(YAFFS_TRACE_VERIFY,
17720 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
17721 + obj->objectId, obj->variantType));
17722 + break;
17723 + }
17724 +}
17725 +
17726 +void yaffs_VerifyObjects(yaffs_Device *dev)
17727 +{
17728 + yaffs_Object *obj;
17729 + int i;
17730 + struct ylist_head *lh;
17731 +
17732 + if (yaffs_SkipVerification(dev))
17733 + return;
17734 +
17735 + /* Iterate through the objects in each hash entry */
17736 +
17737 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
17738 + ylist_for_each(lh, &dev->objectBucket[i].list) {
17739 + if (lh) {
17740 + obj = ylist_entry(lh, yaffs_Object, hashLink);
17741 + yaffs_VerifyObject(obj);
17742 + }
17743 + }
17744 + }
17745 +}
17746 +
17747 +
17748 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
17749 +{
17750 + struct ylist_head *lh;
17751 + yaffs_Object *listObj;
17752 +
17753 + int count = 0;
17754 +
17755 + if (!obj) {
17756 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
17757 + YBUG();
17758 + return;
17759 + }
17760 +
17761 + if (yaffs_SkipVerification(obj->myDev))
17762 + return;
17763 +
17764 + if (!obj->parent) {
17765 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
17766 + YBUG();
17767 + return;
17768 + }
17769 +
17770 + if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17771 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
17772 + YBUG();
17773 + }
17774 +
17775 + /* Iterate through the objects in each hash entry */
17776 +
17777 + ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
17778 + if (lh) {
17779 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17780 + yaffs_VerifyObject(listObj);
17781 + if (obj == listObj)
17782 + count++;
17783 + }
17784 + }
17785 +
17786 + if (count != 1) {
17787 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
17788 + YBUG();
17789 + }
17790 +}
17791 +
17792 +void yaffs_VerifyDirectory(yaffs_Object *directory)
17793 +{
17794 + struct ylist_head *lh;
17795 + yaffs_Object *listObj;
17796 +
17797 + if (!directory) {
17798 + YBUG();
17799 + return;
17800 + }
17801 +
17802 + if (yaffs_SkipFullVerification(directory->myDev))
17803 + return;
17804 +
17805 + if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
17806 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
17807 + YBUG();
17808 + }
17809 +
17810 + /* Iterate through the objects in each hash entry */
17811 +
17812 + ylist_for_each(lh, &directory->variant.directoryVariant.children) {
17813 + if (lh) {
17814 + listObj = ylist_entry(lh, yaffs_Object, siblings);
17815 + if (listObj->parent != directory) {
17816 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
17817 + YBUG();
17818 + }
17819 + yaffs_VerifyObjectInDirectory(listObj);
17820 + }
17821 + }
17822 +}
17823 +
17824 +static int yaffs_freeVerificationFailures;
17825 +
17826 +void yaffs_VerifyFreeChunks(yaffs_Device *dev)
17827 +{
17828 + int counted;
17829 + int difference;
17830 +
17831 + if (yaffs_SkipVerification(dev))
17832 + return;
17833 +
17834 + counted = yaffs_CountFreeChunks(dev);
17835 +
17836 + difference = dev->nFreeChunks - counted;
17837 +
17838 + if (difference) {
17839 + T(YAFFS_TRACE_ALWAYS,
17840 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
17841 + dev->nFreeChunks, counted, difference));
17842 + yaffs_freeVerificationFailures++;
17843 + }
17844 +}
17845 +
17846 +int yaffs_VerifyFileSanity(yaffs_Object *in)
17847 +{
17848 +#if 0
17849 + int chunk;
17850 + int nChunks;
17851 + int fSize;
17852 + int failed = 0;
17853 + int objId;
17854 + yaffs_Tnode *tn;
17855 + yaffs_Tags localTags;
17856 + yaffs_Tags *tags = &localTags;
17857 + int theChunk;
17858 + int chunkDeleted;
17859 +
17860 + if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
17861 + return YAFFS_FAIL;
17862 +
17863 + objId = in->objectId;
17864 + fSize = in->variant.fileVariant.fileSize;
17865 + nChunks =
17866 + (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
17867 +
17868 + for (chunk = 1; chunk <= nChunks; chunk++) {
17869 + tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
17870 + chunk);
17871 +
17872 + if (tn) {
17873 +
17874 + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
17875 +
17876 + if (yaffs_CheckChunkBits
17877 + (dev, theChunk / dev->param.nChunksPerBlock,
17878 + theChunk % dev->param.nChunksPerBlock)) {
17879 +
17880 + yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
17881 + tags,
17882 + &chunkDeleted);
17883 + if (yaffs_TagsMatch
17884 + (tags, in->objectId, chunk, chunkDeleted)) {
17885 + /* found it; */
17886 +
17887 + }
17888 + } else {
17889 +
17890 + failed = 1;
17891 + }
17892 +
17893 + } else {
17894 + /* T(("No level 0 found for %d\n", chunk)); */
17895 + }
17896 + }
17897 +
17898 + return failed ? YAFFS_FAIL : YAFFS_OK;
17899 +#else
17900 + in=in;
17901 + return YAFFS_OK;
17902 +#endif
17903 +}
17904 diff -Nrup a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h
17905 --- a/fs/yaffs2/yaffs_verify.h 1970-01-01 02:00:00.000000000 +0200
17906 +++ b/fs/yaffs2/yaffs_verify.h 2010-10-03 18:03:47.551000365 +0300
17907 @@ -0,0 +1,39 @@
17908 +/*
17909 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17910 + *
17911 + * Copyright (C) 2002-2010 Aleph One Ltd.
17912 + * for Toby Churchill Ltd and Brightstar Engineering
17913 + *
17914 + * Created by Charles Manning <charles@aleph1.co.uk>
17915 + *
17916 + * This program is free software; you can redistribute it and/or modify
17917 + * it under the terms of the GNU General Public License version 2 as
17918 + * published by the Free Software Foundation.
17919 + */
17920 +
17921 +#ifndef __YAFFS_VERIFY_H__
17922 +#define __YAFFS_VERIFY_H__
17923 +
17924 +#include "yaffs_guts.h"
17925 +
17926 +void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17927 +void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
17928 +void yaffs_VerifyBlocks(yaffs_Device *dev);
17929 +
17930 +void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck);
17931 +void yaffs_VerifyFile(yaffs_Object *obj);
17932 +void yaffs_VerifyHardLink(yaffs_Object *obj);
17933 +void yaffs_VerifySymlink(yaffs_Object *obj);
17934 +void yaffs_VerifySpecial(yaffs_Object *obj);
17935 +void yaffs_VerifyObject(yaffs_Object *obj);
17936 +void yaffs_VerifyObjects(yaffs_Device *dev);
17937 +void yaffs_VerifyObjectInDirectory(yaffs_Object *obj);
17938 +void yaffs_VerifyDirectory(yaffs_Object *directory);
17939 +void yaffs_VerifyFreeChunks(yaffs_Device *dev);
17940 +
17941 +int yaffs_VerifyFileSanity(yaffs_Object *obj);
17942 +
17943 +int yaffs_SkipVerification(yaffs_Device *dev);
17944 +
17945 +#endif
17946 +
17947 diff -Nrup a/fs/yaffs2/yaffs_vfs_glue.c b/fs/yaffs2/yaffs_vfs_glue.c
17948 --- a/fs/yaffs2/yaffs_vfs_glue.c 1970-01-01 02:00:00.000000000 +0200
17949 +++ b/fs/yaffs2/yaffs_vfs_glue.c 2010-10-03 18:03:47.557000359 +0300
17950 @@ -0,0 +1,3577 @@
17951 +/*
17952 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
17953 + *
17954 + * Copyright (C) 2002-2010 Aleph One Ltd.
17955 + * for Toby Churchill Ltd and Brightstar Engineering
17956 + *
17957 + * Created by Charles Manning <charles@aleph1.co.uk>
17958 + * Acknowledgements:
17959 + * Luc van OostenRyck for numerous patches.
17960 + * Nick Bane for numerous patches.
17961 + * Nick Bane for 2.5/2.6 integration.
17962 + * Andras Toth for mknod rdev issue.
17963 + * Michael Fischer for finding the problem with inode inconsistency.
17964 + * Some code bodily lifted from JFFS
17965 + *
17966 + * This program is free software; you can redistribute it and/or modify
17967 + * it under the terms of the GNU General Public License version 2 as
17968 + * published by the Free Software Foundation.
17969 + */
17970 +
17971 +/*
17972 + *
17973 + * This is the file system front-end to YAFFS that hooks it up to
17974 + * the VFS.
17975 + *
17976 + * Special notes:
17977 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
17978 + * this superblock
17979 + * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
17980 + * superblock
17981 + * >> inode->u.generic_ip points to the associated yaffs_Object.
17982 + */
17983 +
17984 +/*
17985 + * There are two variants of the VFS glue code. This variant should compile
17986 + * for any version of Linux.
17987 + */
17988 +#include <linux/version.h>
17989 +
17990 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
17991 +#define YAFFS_COMPILE_BACKGROUND
17992 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
17993 +#define YAFFS_COMPILE_FREEZER
17994 +#endif
17995 +#endif
17996 +
17997 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
17998 +#define YAFFS_COMPILE_EXPORTFS
17999 +#endif
18000 +
18001 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
18002 +#define YAFFS_USE_SETATTR_COPY
18003 +#define YAFFS_USE_TRUNCATE_SETSIZE
18004 +#endif
18005 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
18006 +#define YAFFS_HAS_EVICT_INODE
18007 +#endif
18008 +
18009 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
18010 +#define YAFFS_NEW_FOLLOW_LINK 1
18011 +#else
18012 +#define YAFFS_NEW_FOLLOW_LINK 0
18013 +#endif
18014 +
18015 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
18016 +#include <linux/config.h>
18017 +#endif
18018 +
18019 +#include <linux/kernel.h>
18020 +#include <linux/module.h>
18021 +#include <linux/slab.h>
18022 +#include <linux/init.h>
18023 +#include <linux/fs.h>
18024 +#include <linux/proc_fs.h>
18025 +#include <linux/smp_lock.h>
18026 +#include <linux/pagemap.h>
18027 +#include <linux/mtd/mtd.h>
18028 +#include <linux/interrupt.h>
18029 +#include <linux/string.h>
18030 +#include <linux/ctype.h>
18031 +
18032 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18033 +#include <linux/namei.h>
18034 +#endif
18035 +
18036 +#ifdef YAFFS_COMPILE_EXPORTFS
18037 +#include <linux/exportfs.h>
18038 +#endif
18039 +
18040 +#ifdef YAFFS_COMPILE_BACKGROUND
18041 +#include <linux/kthread.h>
18042 +#include <linux/delay.h>
18043 +#endif
18044 +#ifdef YAFFS_COMPILE_FREEZER
18045 +#include <linux/freezer.h>
18046 +#endif
18047 +
18048 +#include <asm/div64.h>
18049 +
18050 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18051 +
18052 +#include <linux/statfs.h>
18053 +
18054 +#define UnlockPage(p) unlock_page(p)
18055 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
18056 +
18057 +/* FIXME: use sb->s_id instead ? */
18058 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
18059 +
18060 +#else
18061 +
18062 +#include <linux/locks.h>
18063 +#define BDEVNAME_SIZE 0
18064 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
18065 +
18066 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
18067 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
18068 +#define __user
18069 +#endif
18070 +
18071 +#endif
18072 +
18073 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
18074 +#define YPROC_ROOT (&proc_root)
18075 +#else
18076 +#define YPROC_ROOT NULL
18077 +#endif
18078 +
18079 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
18080 +#define Y_INIT_TIMER(a) init_timer(a)
18081 +#else
18082 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
18083 +#endif
18084 +
18085 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18086 +#define WRITE_SIZE_STR "writesize"
18087 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
18088 +#else
18089 +#define WRITE_SIZE_STR "oobblock"
18090 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
18091 +#endif
18092 +
18093 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
18094 +#define YAFFS_USE_WRITE_BEGIN_END 1
18095 +#else
18096 +#define YAFFS_USE_WRITE_BEGIN_END 0
18097 +#endif
18098 +
18099 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
18100 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
18101 +{
18102 + uint64_t result = partition_size;
18103 + do_div(result, block_size);
18104 + return (uint32_t)result;
18105 +}
18106 +#else
18107 +#define YCALCBLOCKS(s, b) ((s)/(b))
18108 +#endif
18109 +
18110 +#include <linux/uaccess.h>
18111 +#include <linux/mtd/mtd.h>
18112 +
18113 +#include "yportenv.h"
18114 +#include "yaffs_trace.h"
18115 +#include "yaffs_guts.h"
18116 +
18117 +#include "yaffs_linux.h"
18118 +
18119 +#include "yaffs_mtdif.h"
18120 +#include "yaffs_mtdif1.h"
18121 +#include "yaffs_mtdif2.h"
18122 +
18123 +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
18124 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
18125 +unsigned int yaffs_auto_checkpoint = 1;
18126 +unsigned int yaffs_gc_control = 1;
18127 +unsigned int yaffs_bg_enable = 1;
18128 +
18129 +/* Module Parameters */
18130 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18131 +module_param(yaffs_traceMask, uint, 0644);
18132 +module_param(yaffs_wr_attempts, uint, 0644);
18133 +module_param(yaffs_auto_checkpoint, uint, 0644);
18134 +module_param(yaffs_gc_control, uint, 0644);
18135 +module_param(yaffs_bg_enable, uint, 0644);
18136 +#else
18137 +MODULE_PARM(yaffs_traceMask, "i");
18138 +MODULE_PARM(yaffs_wr_attempts, "i");
18139 +MODULE_PARM(yaffs_auto_checkpoint, "i");
18140 +MODULE_PARM(yaffs_gc_control, "i");
18141 +#endif
18142 +
18143 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
18144 +/* use iget and read_inode */
18145 +#define Y_IGET(sb, inum) iget((sb), (inum))
18146 +static void yaffs_read_inode(struct inode *inode);
18147 +
18148 +#else
18149 +/* Call local equivalent */
18150 +#define YAFFS_USE_OWN_IGET
18151 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
18152 +
18153 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
18154 +#endif
18155 +
18156 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18157 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
18158 +#else
18159 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
18160 +#endif
18161 +
18162 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
18163 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
18164 +
18165 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18166 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
18167 +#else
18168 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
18169 +#endif
18170 +
18171 +
18172 +#define update_dir_time(dir) do {\
18173 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
18174 + } while(0)
18175 +
18176 +static void yaffs_put_super(struct super_block *sb);
18177 +
18178 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
18179 + loff_t *pos);
18180 +static ssize_t yaffs_hold_space(struct file *f);
18181 +static void yaffs_release_space(struct file *f);
18182 +
18183 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18184 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
18185 +#else
18186 +static int yaffs_file_flush(struct file *file);
18187 +#endif
18188 +
18189 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
18190 +static int yaffs_sync_object(struct file *file, int datasync);
18191 +#else
18192 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
18193 + int datasync);
18194 +#endif
18195 +
18196 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
18197 +
18198 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18199 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
18200 + struct nameidata *n);
18201 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18202 + struct nameidata *n);
18203 +#else
18204 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
18205 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
18206 +#endif
18207 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
18208 + struct dentry *dentry);
18209 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
18210 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
18211 + const char *symname);
18212 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
18213 +
18214 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18215 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18216 + dev_t dev);
18217 +#else
18218 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
18219 + int dev);
18220 +#endif
18221 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
18222 + struct inode *new_dir, struct dentry *new_dentry);
18223 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
18224 +
18225 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18226 +static int yaffs_sync_fs(struct super_block *sb, int wait);
18227 +static void yaffs_write_super(struct super_block *sb);
18228 +#else
18229 +static int yaffs_sync_fs(struct super_block *sb);
18230 +static int yaffs_write_super(struct super_block *sb);
18231 +#endif
18232 +
18233 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18234 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
18235 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18236 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
18237 +#else
18238 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
18239 +#endif
18240 +
18241 +#ifdef YAFFS_HAS_PUT_INODE
18242 +static void yaffs_put_inode(struct inode *inode);
18243 +#endif
18244 +
18245 +#ifdef YAFFS_HAS_EVICT_INODE
18246 +static void yaffs_evict_inode(struct inode *);
18247 +#else
18248 +static void yaffs_delete_inode(struct inode *);
18249 +static void yaffs_clear_inode(struct inode *);
18250 +#endif
18251 +
18252 +static int yaffs_readpage(struct file *file, struct page *page);
18253 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18254 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
18255 +#else
18256 +static int yaffs_writepage(struct page *page);
18257 +#endif
18258 +
18259 +#ifdef CONFIG_YAFFS_XATTR
18260 +int yaffs_setxattr(struct dentry *dentry, const char *name,
18261 + const void *value, size_t size, int flags);
18262 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
18263 + size_t size);
18264 +int yaffs_removexattr(struct dentry *dentry, const char *name);
18265 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
18266 +#endif
18267 +
18268 +
18269 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
18270 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
18271 + loff_t pos, unsigned len, unsigned flags,
18272 + struct page **pagep, void **fsdata);
18273 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
18274 + loff_t pos, unsigned len, unsigned copied,
18275 + struct page *pg, void *fsdadata);
18276 +#else
18277 +static int yaffs_prepare_write(struct file *f, struct page *pg,
18278 + unsigned offset, unsigned to);
18279 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
18280 + unsigned to);
18281 +
18282 +#endif
18283 +
18284 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18285 + int buflen);
18286 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18287 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
18288 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18289 +#else
18290 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
18291 +#endif
18292 +
18293 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
18294 +
18295 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
18296 +
18297 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
18298 +
18299 +
18300 +static struct address_space_operations yaffs_file_address_operations = {
18301 + .readpage = yaffs_readpage,
18302 + .writepage = yaffs_writepage,
18303 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
18304 + .write_begin = yaffs_write_begin,
18305 + .write_end = yaffs_write_end,
18306 +#else
18307 + .prepare_write = yaffs_prepare_write,
18308 + .commit_write = yaffs_commit_write,
18309 +#endif
18310 +};
18311 +
18312 +
18313 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
18314 +static const struct file_operations yaffs_file_operations = {
18315 + .read = do_sync_read,
18316 + .write = do_sync_write,
18317 + .aio_read = generic_file_aio_read,
18318 + .aio_write = generic_file_aio_write,
18319 + .mmap = generic_file_mmap,
18320 + .flush = yaffs_file_flush,
18321 + .fsync = yaffs_sync_object,
18322 + .splice_read = generic_file_splice_read,
18323 + .splice_write = generic_file_splice_write,
18324 + .llseek = generic_file_llseek,
18325 +};
18326 +
18327 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
18328 +
18329 +static const struct file_operations yaffs_file_operations = {
18330 + .read = do_sync_read,
18331 + .write = do_sync_write,
18332 + .aio_read = generic_file_aio_read,
18333 + .aio_write = generic_file_aio_write,
18334 + .mmap = generic_file_mmap,
18335 + .flush = yaffs_file_flush,
18336 + .fsync = yaffs_sync_object,
18337 + .sendfile = generic_file_sendfile,
18338 +};
18339 +
18340 +#else
18341 +
18342 +static const struct file_operations yaffs_file_operations = {
18343 + .read = generic_file_read,
18344 + .write = generic_file_write,
18345 + .mmap = generic_file_mmap,
18346 + .flush = yaffs_file_flush,
18347 + .fsync = yaffs_sync_object,
18348 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18349 + .sendfile = generic_file_sendfile,
18350 +#endif
18351 +};
18352 +#endif
18353 +
18354 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
18355 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
18356 +{
18357 + void * kaddr = kmap_atomic(page, KM_USER0);
18358 + memset(kaddr + start, 0, end - start);
18359 + kunmap_atomic(kaddr, KM_USER0);
18360 + flush_dcache_page(page);
18361 +}
18362 +#endif
18363 +
18364 +
18365 +static const struct inode_operations yaffs_file_inode_operations = {
18366 + .setattr = yaffs_setattr,
18367 +#ifdef CONFIG_YAFFS_XATTR
18368 + .setxattr = yaffs_setxattr,
18369 + .getxattr = yaffs_getxattr,
18370 + .listxattr = yaffs_listxattr,
18371 + .removexattr = yaffs_removexattr,
18372 +#endif
18373 +};
18374 +
18375 +static const struct inode_operations yaffs_symlink_inode_operations = {
18376 + .readlink = yaffs_readlink,
18377 + .follow_link = yaffs_follow_link,
18378 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18379 + .put_link = yaffs_put_link,
18380 +#endif
18381 + .setattr = yaffs_setattr,
18382 +#ifdef CONFIG_YAFFS_XATTR
18383 + .setxattr = yaffs_setxattr,
18384 + .getxattr = yaffs_getxattr,
18385 + .listxattr = yaffs_listxattr,
18386 + .removexattr = yaffs_removexattr,
18387 +#endif
18388 +};
18389 +
18390 +static const struct inode_operations yaffs_dir_inode_operations = {
18391 + .create = yaffs_create,
18392 + .lookup = yaffs_lookup,
18393 + .link = yaffs_link,
18394 + .unlink = yaffs_unlink,
18395 + .symlink = yaffs_symlink,
18396 + .mkdir = yaffs_mkdir,
18397 + .rmdir = yaffs_unlink,
18398 + .mknod = yaffs_mknod,
18399 + .rename = yaffs_rename,
18400 + .setattr = yaffs_setattr,
18401 +#ifdef CONFIG_YAFFS_XATTR
18402 + .setxattr = yaffs_setxattr,
18403 + .getxattr = yaffs_getxattr,
18404 + .listxattr = yaffs_listxattr,
18405 + .removexattr = yaffs_removexattr,
18406 +#endif
18407 +};
18408 +
18409 +static const struct file_operations yaffs_dir_operations = {
18410 + .read = generic_read_dir,
18411 + .readdir = yaffs_readdir,
18412 + .fsync = yaffs_sync_object,
18413 + .llseek = yaffs_dir_llseek,
18414 +};
18415 +
18416 +static const struct super_operations yaffs_super_ops = {
18417 + .statfs = yaffs_statfs,
18418 +
18419 +#ifndef YAFFS_USE_OWN_IGET
18420 + .read_inode = yaffs_read_inode,
18421 +#endif
18422 +#ifdef YAFFS_HAS_PUT_INODE
18423 + .put_inode = yaffs_put_inode,
18424 +#endif
18425 + .put_super = yaffs_put_super,
18426 +#ifdef YAFFS_HAS_EVICT_INODE
18427 + .evict_inode = yaffs_evict_inode,
18428 +#else
18429 + .delete_inode = yaffs_delete_inode,
18430 + .clear_inode = yaffs_clear_inode,
18431 +#endif
18432 + .sync_fs = yaffs_sync_fs,
18433 + .write_super = yaffs_write_super,
18434 +};
18435 +
18436 +
18437 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
18438 +{
18439 +#ifdef YAFFS_USE_SETATTR_COPY
18440 + setattr_copy(inode,attr);
18441 + return 0;
18442 +#else
18443 + return inode_setattr(inode, attr);
18444 +#endif
18445 +
18446 +}
18447 +
18448 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
18449 +{
18450 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
18451 + truncate_setsize(inode,newsize);
18452 + return 0;
18453 +#else
18454 + truncate_inode_pages(&inode->i_data,newsize);
18455 + return 0;
18456 +#endif
18457 +
18458 +}
18459 +
18460 +static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
18461 +{
18462 + return yaffs_gc_control;
18463 +}
18464 +
18465 +static void yaffs_GrossLock(yaffs_Device *dev)
18466 +{
18467 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
18468 + down(&(yaffs_DeviceToLC(dev)->grossLock));
18469 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
18470 +}
18471 +
18472 +static void yaffs_GrossUnlock(yaffs_Device *dev)
18473 +{
18474 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
18475 + up(&(yaffs_DeviceToLC(dev)->grossLock));
18476 +}
18477 +
18478 +#ifdef YAFFS_COMPILE_EXPORTFS
18479 +
18480 +static struct inode *
18481 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
18482 +{
18483 + return Y_IGET(sb, ino);
18484 +}
18485 +
18486 +static struct dentry *
18487 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18488 +{
18489 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
18490 +}
18491 +
18492 +static struct dentry *
18493 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
18494 +{
18495 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
18496 +}
18497 +
18498 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
18499 +{
18500 +
18501 + struct super_block *sb = dentry->d_inode->i_sb;
18502 + struct dentry *parent = ERR_PTR(-ENOENT);
18503 + struct inode *inode;
18504 + unsigned long parent_ino;
18505 + yaffs_Object *d_obj;
18506 + yaffs_Object *parent_obj;
18507 +
18508 + d_obj = yaffs_InodeToObject(dentry->d_inode);
18509 +
18510 + if (d_obj) {
18511 + parent_obj = d_obj->parent;
18512 + if (parent_obj) {
18513 + parent_ino = yaffs_GetObjectInode(parent_obj);
18514 + inode = Y_IGET(sb, parent_ino);
18515 +
18516 + if (IS_ERR(inode)) {
18517 + parent = ERR_CAST(inode);
18518 + } else {
18519 + parent = d_obtain_alias(inode);
18520 + if (!IS_ERR(parent)) {
18521 + parent = ERR_PTR(-ENOMEM);
18522 + iput(inode);
18523 + }
18524 + }
18525 + }
18526 + }
18527 +
18528 + return parent;
18529 +}
18530 +
18531 +/* Just declare a zero structure as a NULL value implies
18532 + * using the default functions of exportfs.
18533 + */
18534 +
18535 +static struct export_operations yaffs_export_ops =
18536 +{
18537 + .fh_to_dentry = yaffs2_fh_to_dentry,
18538 + .fh_to_parent = yaffs2_fh_to_parent,
18539 + .get_parent = yaffs2_get_parent,
18540 +} ;
18541 +
18542 +#endif
18543 +
18544 +/*-----------------------------------------------------------------*/
18545 +/* Directory search context allows us to unlock access to yaffs during
18546 + * filldir without causing problems with the directory being modified.
18547 + * This is similar to the tried and tested mechanism used in yaffs direct.
18548 + *
18549 + * A search context iterates along a doubly linked list of siblings in the
18550 + * directory. If the iterating object is deleted then this would corrupt
18551 + * the list iteration, likely causing a crash. The search context avoids
18552 + * this by using the removeObjectCallback to move the search context to the
18553 + * next object before the object is deleted.
18554 + *
18555 + * Many readdirs (and thus seach conexts) may be alive simulateously so
18556 + * each yaffs_Device has a list of these.
18557 + *
18558 + * A seach context lives for the duration of a readdir.
18559 + *
18560 + * All these functions must be called while yaffs is locked.
18561 + */
18562 +
18563 +struct yaffs_SearchContext {
18564 + yaffs_Device *dev;
18565 + yaffs_Object *dirObj;
18566 + yaffs_Object *nextReturn;
18567 + struct ylist_head others;
18568 +};
18569 +
18570 +/*
18571 + * yaffs_NewSearch() creates a new search context, initialises it and
18572 + * adds it to the device's search context list.
18573 + *
18574 + * Called at start of readdir.
18575 + */
18576 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
18577 +{
18578 + yaffs_Device *dev = dir->myDev;
18579 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
18580 + if(sc){
18581 + sc->dirObj = dir;
18582 + sc->dev = dev;
18583 + if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18584 + sc->nextReturn = NULL;
18585 + else
18586 + sc->nextReturn = ylist_entry(
18587 + dir->variant.directoryVariant.children.next,
18588 + yaffs_Object,siblings);
18589 + YINIT_LIST_HEAD(&sc->others);
18590 + ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
18591 + }
18592 + return sc;
18593 +}
18594 +
18595 +/*
18596 + * yaffs_EndSearch() disposes of a search context and cleans up.
18597 + */
18598 +static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
18599 +{
18600 + if(sc){
18601 + ylist_del(&sc->others);
18602 + YFREE(sc);
18603 + }
18604 +}
18605 +
18606 +/*
18607 + * yaffs_SearchAdvance() moves a search context to the next object.
18608 + * Called when the search iterates or when an object removal causes
18609 + * the search context to be moved to the next object.
18610 + */
18611 +static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
18612 +{
18613 + if(!sc)
18614 + return;
18615 +
18616 + if( sc->nextReturn == NULL ||
18617 + ylist_empty(&sc->dirObj->variant.directoryVariant.children))
18618 + sc->nextReturn = NULL;
18619 + else {
18620 + struct ylist_head *next = sc->nextReturn->siblings.next;
18621 +
18622 + if( next == &sc->dirObj->variant.directoryVariant.children)
18623 + sc->nextReturn = NULL; /* end of list */
18624 + else
18625 + sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
18626 + }
18627 +}
18628 +
18629 +/*
18630 + * yaffs_RemoveObjectCallback() is called when an object is unlinked.
18631 + * We check open search contexts and advance any which are currently
18632 + * on the object being iterated.
18633 + */
18634 +static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
18635 +{
18636 +
18637 + struct ylist_head *i;
18638 + struct yaffs_SearchContext *sc;
18639 + struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
18640 +
18641 +
18642 + /* Iterate through the directory search contexts.
18643 + * If any are currently on the object being removed, then advance
18644 + * the search context to the next object to prevent a hanging pointer.
18645 + */
18646 + ylist_for_each(i, search_contexts) {
18647 + if (i) {
18648 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
18649 + if(sc->nextReturn == obj)
18650 + yaffs_SearchAdvance(sc);
18651 + }
18652 + }
18653 +
18654 +}
18655 +
18656 +
18657 +/*-----------------------------------------------------------------*/
18658 +
18659 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
18660 + int buflen)
18661 +{
18662 + unsigned char *alias;
18663 + int ret;
18664 +
18665 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18666 +
18667 + yaffs_GrossLock(dev);
18668 +
18669 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18670 +
18671 + yaffs_GrossUnlock(dev);
18672 +
18673 + if (!alias)
18674 + return -ENOMEM;
18675 +
18676 + ret = vfs_readlink(dentry, buffer, buflen, alias);
18677 + kfree(alias);
18678 + return ret;
18679 +}
18680 +
18681 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18682 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18683 +#else
18684 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
18685 +#endif
18686 +{
18687 + unsigned char *alias;
18688 + int ret;
18689 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
18690 +
18691 + yaffs_GrossLock(dev);
18692 +
18693 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
18694 + yaffs_GrossUnlock(dev);
18695 +
18696 + if (!alias) {
18697 + ret = -ENOMEM;
18698 + goto out;
18699 + }
18700 +
18701 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18702 + nd_set_link(nd, alias);
18703 + ret = (int)alias;
18704 +out:
18705 + return ERR_PTR(ret);
18706 +#else
18707 + ret = vfs_follow_link(nd, alias);
18708 + kfree(alias);
18709 +out:
18710 + return ret;
18711 +#endif
18712 +}
18713 +
18714 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
18715 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
18716 + kfree(alias);
18717 +}
18718 +#endif
18719 +
18720 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
18721 + yaffs_Object *obj);
18722 +
18723 +/*
18724 + * Lookup is used to find objects in the fs
18725 + */
18726 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18727 +
18728 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
18729 + struct nameidata *n)
18730 +#else
18731 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
18732 +#endif
18733 +{
18734 + yaffs_Object *obj;
18735 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
18736 +
18737 + yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
18738 +
18739 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18740 + yaffs_GrossLock(dev);
18741 +
18742 + T(YAFFS_TRACE_OS,
18743 + (TSTR("yaffs_lookup for %d:%s\n"),
18744 + yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
18745 +
18746 + obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
18747 + dentry->d_name.name);
18748 +
18749 + obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
18750 +
18751 + /* Can't hold gross lock when calling yaffs_get_inode() */
18752 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
18753 + yaffs_GrossUnlock(dev);
18754 +
18755 + if (obj) {
18756 + T(YAFFS_TRACE_OS,
18757 + (TSTR("yaffs_lookup found %d\n"), obj->objectId));
18758 +
18759 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
18760 +
18761 + if (inode) {
18762 + T(YAFFS_TRACE_OS,
18763 + (TSTR("yaffs_loookup dentry \n")));
18764 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
18765 + * d_add even if NULL inode */
18766 +#if 0
18767 + /*dget(dentry); // try to solve directory bug */
18768 + d_add(dentry, inode);
18769 +
18770 + /* return dentry; */
18771 + return NULL;
18772 +#endif
18773 + }
18774 +
18775 + } else {
18776 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
18777 +
18778 + }
18779 +
18780 +/* added NCB for 2.5/6 compatability - forces add even if inode is
18781 + * NULL which creates dentry hash */
18782 + d_add(dentry, inode);
18783 +
18784 + return NULL;
18785 +}
18786 +
18787 +
18788 +#ifdef YAFFS_HAS_PUT_INODE
18789 +
18790 +/* For now put inode is just for debugging
18791 + * Put inode is called when the inode **structure** is put.
18792 + */
18793 +static void yaffs_put_inode(struct inode *inode)
18794 +{
18795 + T(YAFFS_TRACE_OS,
18796 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
18797 + atomic_read(&inode->i_count)));
18798 +
18799 +}
18800 +#endif
18801 +
18802 +
18803 +static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj)
18804 +{
18805 + /* Clear the association between the inode and
18806 + * the yaffs_Object.
18807 + */
18808 + obj->myInode = NULL;
18809 + yaffs_InodeToObjectLV(inode) = NULL;
18810 +
18811 + /* If the object freeing was deferred, then the real
18812 + * free happens now.
18813 + * This should fix the inode inconsistency problem.
18814 + */
18815 + yaffs_HandleDeferedFree(obj);
18816 +}
18817 +
18818 +#ifdef YAFFS_HAS_EVICT_INODE
18819 +/* yaffs_evict_inode combines into one operation what was previously done in
18820 + * yaffs_clear_inode() and yaffs_delete_inode()
18821 + *
18822 + */
18823 +static void yaffs_evict_inode( struct inode *inode)
18824 +{
18825 + yaffs_Object *obj;
18826 + yaffs_Device *dev;
18827 + int deleteme = 0;
18828 +
18829 + obj = yaffs_InodeToObject(inode);
18830 +
18831 + T(YAFFS_TRACE_OS,
18832 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18833 + atomic_read(&inode->i_count),
18834 + obj ? "object exists" : "null object"));
18835 +
18836 + if (!inode->i_nlink && !is_bad_inode(inode))
18837 + deleteme = 1;
18838 + truncate_inode_pages(&inode->i_data,0);
18839 + end_writeback(inode);
18840 +
18841 + if(deleteme && obj){
18842 + dev = obj->myDev;
18843 + yaffs_GrossLock(dev);
18844 + yaffs_DeleteObject(obj);
18845 + yaffs_GrossUnlock(dev);
18846 + }
18847 + if (obj) {
18848 + dev = obj->myDev;
18849 + yaffs_GrossLock(dev);
18850 + yaffs_UnstitchObject(inode,obj);
18851 + yaffs_GrossUnlock(dev);
18852 + }
18853 +
18854 +
18855 +}
18856 +#else
18857 +
18858 +/* clear is called to tell the fs to release any per-inode data it holds.
18859 + * The object might still exist on disk and is just being thrown out of the cache
18860 + * or else the object has actually been deleted and we're being called via
18861 + * the chain
18862 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
18863 + */
18864 +
18865 +static void yaffs_clear_inode(struct inode *inode)
18866 +{
18867 + yaffs_Object *obj;
18868 + yaffs_Device *dev;
18869 +
18870 + obj = yaffs_InodeToObject(inode);
18871 +
18872 + T(YAFFS_TRACE_OS,
18873 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18874 + atomic_read(&inode->i_count),
18875 + obj ? "object exists" : "null object"));
18876 +
18877 + if (obj) {
18878 + dev = obj->myDev;
18879 + yaffs_GrossLock(dev);
18880 + yaffs_UnstitchObject(inode,obj);
18881 + yaffs_GrossUnlock(dev);
18882 + }
18883 +
18884 +}
18885 +
18886 +/* delete is called when the link count is zero and the inode
18887 + * is put (ie. nobody wants to know about it anymore, time to
18888 + * delete the file).
18889 + * NB Must call clear_inode()
18890 + */
18891 +static void yaffs_delete_inode(struct inode *inode)
18892 +{
18893 + yaffs_Object *obj = yaffs_InodeToObject(inode);
18894 + yaffs_Device *dev;
18895 +
18896 + T(YAFFS_TRACE_OS,
18897 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
18898 + atomic_read(&inode->i_count),
18899 + obj ? "object exists" : "null object"));
18900 +
18901 + if (obj) {
18902 + dev = obj->myDev;
18903 + yaffs_GrossLock(dev);
18904 + yaffs_DeleteObject(obj);
18905 + yaffs_GrossUnlock(dev);
18906 + }
18907 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
18908 + truncate_inode_pages(&inode->i_data, 0);
18909 +#endif
18910 + clear_inode(inode);
18911 +}
18912 +#endif
18913 +
18914 +
18915 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18916 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
18917 +#else
18918 +static int yaffs_file_flush(struct file *file)
18919 +#endif
18920 +{
18921 + yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
18922 +
18923 + yaffs_Device *dev = obj->myDev;
18924 +
18925 + T(YAFFS_TRACE_OS,
18926 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId,
18927 + obj->dirty ? "dirty" : "clean"));
18928 +
18929 + yaffs_GrossLock(dev);
18930 +
18931 + yaffs_FlushFile(obj, 1, 0);
18932 +
18933 + yaffs_GrossUnlock(dev);
18934 +
18935 + return 0;
18936 +}
18937 +
18938 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
18939 +{
18940 + /* Lifted from jffs2 */
18941 +
18942 + yaffs_Object *obj;
18943 + unsigned char *pg_buf;
18944 + int ret;
18945 +
18946 + yaffs_Device *dev;
18947 +
18948 + T(YAFFS_TRACE_OS,
18949 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
18950 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
18951 + (unsigned)PAGE_CACHE_SIZE));
18952 +
18953 + obj = yaffs_DentryToObject(f->f_dentry);
18954 +
18955 + dev = obj->myDev;
18956 +
18957 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
18958 + BUG_ON(!PageLocked(pg));
18959 +#else
18960 + if (!PageLocked(pg))
18961 + PAGE_BUG(pg);
18962 +#endif
18963 +
18964 + pg_buf = kmap(pg);
18965 + /* FIXME: Can kmap fail? */
18966 +
18967 + yaffs_GrossLock(dev);
18968 +
18969 + ret = yaffs_ReadDataFromFile(obj, pg_buf,
18970 + pg->index << PAGE_CACHE_SHIFT,
18971 + PAGE_CACHE_SIZE);
18972 +
18973 + yaffs_GrossUnlock(dev);
18974 +
18975 + if (ret >= 0)
18976 + ret = 0;
18977 +
18978 + if (ret) {
18979 + ClearPageUptodate(pg);
18980 + SetPageError(pg);
18981 + } else {
18982 + SetPageUptodate(pg);
18983 + ClearPageError(pg);
18984 + }
18985 +
18986 + flush_dcache_page(pg);
18987 + kunmap(pg);
18988 +
18989 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
18990 + return ret;
18991 +}
18992 +
18993 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
18994 +{
18995 + int ret = yaffs_readpage_nolock(f, pg);
18996 + UnlockPage(pg);
18997 + return ret;
18998 +}
18999 +
19000 +static int yaffs_readpage(struct file *f, struct page *pg)
19001 +{
19002 + int ret;
19003 +
19004 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
19005 + ret=yaffs_readpage_unlock(f, pg);
19006 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
19007 + return ret;
19008 +}
19009 +
19010 +/* writepage inspired by/stolen from smbfs */
19011 +
19012 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19013 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
19014 +#else
19015 +static int yaffs_writepage(struct page *page)
19016 +#endif
19017 +{
19018 + yaffs_Device *dev;
19019 + struct address_space *mapping = page->mapping;
19020 + struct inode *inode;
19021 + unsigned long end_index;
19022 + char *buffer;
19023 + yaffs_Object *obj;
19024 + int nWritten = 0;
19025 + unsigned nBytes;
19026 + loff_t i_size;
19027 +
19028 + if (!mapping)
19029 + BUG();
19030 + inode = mapping->host;
19031 + if (!inode)
19032 + BUG();
19033 + i_size = i_size_read(inode);
19034 +
19035 + end_index = i_size >> PAGE_CACHE_SHIFT;
19036 +
19037 + if(page->index < end_index)
19038 + nBytes = PAGE_CACHE_SIZE;
19039 + else {
19040 + nBytes = i_size & (PAGE_CACHE_SIZE -1);
19041 +
19042 + if (page->index > end_index || !nBytes) {
19043 + T(YAFFS_TRACE_OS,
19044 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
19045 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
19046 + (unsigned)inode->i_size));
19047 + T(YAFFS_TRACE_OS,
19048 + (TSTR(" -> don't care!!\n")));
19049 +
19050 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
19051 + set_page_writeback(page);
19052 + unlock_page(page);
19053 + end_page_writeback(page);
19054 + return 0;
19055 + }
19056 + }
19057 +
19058 + if(nBytes != PAGE_CACHE_SIZE)
19059 + zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
19060 +
19061 + get_page(page);
19062 +
19063 + buffer = kmap(page);
19064 +
19065 + obj = yaffs_InodeToObject(inode);
19066 + dev = obj->myDev;
19067 + yaffs_GrossLock(dev);
19068 +
19069 + T(YAFFS_TRACE_OS,
19070 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
19071 + (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
19072 + T(YAFFS_TRACE_OS,
19073 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
19074 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19075 +
19076 + nWritten = yaffs_WriteDataToFile(obj, buffer,
19077 + page->index << PAGE_CACHE_SHIFT, nBytes, 0);
19078 +
19079 + yaffs_MarkSuperBlockDirty(dev);
19080 +
19081 + T(YAFFS_TRACE_OS,
19082 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
19083 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
19084 +
19085 + yaffs_GrossUnlock(dev);
19086 +
19087 + kunmap(page);
19088 + set_page_writeback(page);
19089 + unlock_page(page);
19090 + end_page_writeback(page);
19091 + put_page(page);
19092 +
19093 + return (nWritten == nBytes) ? 0 : -ENOSPC;
19094 +}
19095 +
19096 +
19097 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19098 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
19099 + loff_t pos, unsigned len, unsigned flags,
19100 + struct page **pagep, void **fsdata)
19101 +{
19102 + struct page *pg = NULL;
19103 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
19104 +
19105 + int ret = 0;
19106 + int space_held = 0;
19107 +
19108 + /* Get a page */
19109 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
19110 + pg = grab_cache_page_write_begin(mapping, index, flags);
19111 +#else
19112 + pg = __grab_cache_page(mapping, index);
19113 +#endif
19114 +
19115 + *pagep = pg;
19116 + if (!pg) {
19117 + ret = -ENOMEM;
19118 + goto out;
19119 + }
19120 + T(YAFFS_TRACE_OS,
19121 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
19122 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
19123 +
19124 + /* Get fs space */
19125 + space_held = yaffs_hold_space(filp);
19126 +
19127 + if (!space_held) {
19128 + ret = -ENOSPC;
19129 + goto out;
19130 + }
19131 +
19132 + /* Update page if required */
19133 +
19134 + if (!Page_Uptodate(pg))
19135 + ret = yaffs_readpage_nolock(filp, pg);
19136 +
19137 + if (ret)
19138 + goto out;
19139 +
19140 + /* Happy path return */
19141 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
19142 +
19143 + return 0;
19144 +
19145 +out:
19146 + T(YAFFS_TRACE_OS,
19147 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
19148 + if (space_held)
19149 + yaffs_release_space(filp);
19150 + if (pg) {
19151 + unlock_page(pg);
19152 + page_cache_release(pg);
19153 + }
19154 + return ret;
19155 +}
19156 +
19157 +#else
19158 +
19159 +static int yaffs_prepare_write(struct file *f, struct page *pg,
19160 + unsigned offset, unsigned to)
19161 +{
19162 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
19163 +
19164 + if (!Page_Uptodate(pg))
19165 + return yaffs_readpage_nolock(f, pg);
19166 + return 0;
19167 +}
19168 +#endif
19169 +
19170 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
19171 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
19172 + loff_t pos, unsigned len, unsigned copied,
19173 + struct page *pg, void *fsdadata)
19174 +{
19175 + int ret = 0;
19176 + void *addr, *kva;
19177 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
19178 +
19179 + kva = kmap(pg);
19180 + addr = kva + offset_into_page;
19181 +
19182 + T(YAFFS_TRACE_OS,
19183 + ("yaffs_write_end addr %p pos %x nBytes %d\n",
19184 + addr,(unsigned)pos, copied));
19185 +
19186 + ret = yaffs_file_write(filp, addr, copied, &pos);
19187 +
19188 + if (ret != copied) {
19189 + T(YAFFS_TRACE_OS,
19190 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
19191 + ret, copied));
19192 + SetPageError(pg);
19193 + } else {
19194 + /* Nothing */
19195 + }
19196 +
19197 + kunmap(pg);
19198 +
19199 + yaffs_release_space(filp);
19200 + unlock_page(pg);
19201 + page_cache_release(pg);
19202 + return ret;
19203 +}
19204 +#else
19205 +
19206 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
19207 + unsigned to)
19208 +{
19209 + void *addr, *kva;
19210 +
19211 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
19212 + int nBytes = to - offset;
19213 + int nWritten;
19214 +
19215 + unsigned spos = pos;
19216 + unsigned saddr;
19217 +
19218 + kva = kmap(pg);
19219 + addr = kva + offset;
19220 +
19221 + saddr = (unsigned) addr;
19222 +
19223 + T(YAFFS_TRACE_OS,
19224 + (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"),
19225 + saddr, spos, nBytes));
19226 +
19227 + nWritten = yaffs_file_write(f, addr, nBytes, &pos);
19228 +
19229 + if (nWritten != nBytes) {
19230 + T(YAFFS_TRACE_OS,
19231 + (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"),
19232 + nWritten, nBytes));
19233 + SetPageError(pg);
19234 + } else {
19235 + /* Nothing */
19236 + }
19237 +
19238 + kunmap(pg);
19239 +
19240 + T(YAFFS_TRACE_OS,
19241 + (TSTR("yaffs_commit_write returning %d\n"),
19242 + nWritten == nBytes ? 0 : nWritten));
19243 +
19244 + return nWritten == nBytes ? 0 : nWritten;
19245 +}
19246 +#endif
19247 +
19248 +
19249 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
19250 +{
19251 + if (inode && obj) {
19252 +
19253 +
19254 + /* Check mode against the variant type and attempt to repair if broken. */
19255 + __u32 mode = obj->yst_mode;
19256 + switch (obj->variantType) {
19257 + case YAFFS_OBJECT_TYPE_FILE:
19258 + if (!S_ISREG(mode)) {
19259 + obj->yst_mode &= ~S_IFMT;
19260 + obj->yst_mode |= S_IFREG;
19261 + }
19262 +
19263 + break;
19264 + case YAFFS_OBJECT_TYPE_SYMLINK:
19265 + if (!S_ISLNK(mode)) {
19266 + obj->yst_mode &= ~S_IFMT;
19267 + obj->yst_mode |= S_IFLNK;
19268 + }
19269 +
19270 + break;
19271 + case YAFFS_OBJECT_TYPE_DIRECTORY:
19272 + if (!S_ISDIR(mode)) {
19273 + obj->yst_mode &= ~S_IFMT;
19274 + obj->yst_mode |= S_IFDIR;
19275 + }
19276 +
19277 + break;
19278 + case YAFFS_OBJECT_TYPE_UNKNOWN:
19279 + case YAFFS_OBJECT_TYPE_HARDLINK:
19280 + case YAFFS_OBJECT_TYPE_SPECIAL:
19281 + default:
19282 + /* TODO? */
19283 + break;
19284 + }
19285 +
19286 + inode->i_flags |= S_NOATIME;
19287 +
19288 + inode->i_ino = obj->objectId;
19289 + inode->i_mode = obj->yst_mode;
19290 + inode->i_uid = obj->yst_uid;
19291 + inode->i_gid = obj->yst_gid;
19292 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
19293 + inode->i_blksize = inode->i_sb->s_blocksize;
19294 +#endif
19295 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19296 +
19297 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
19298 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
19299 + inode->i_atime.tv_nsec = 0;
19300 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
19301 + inode->i_mtime.tv_nsec = 0;
19302 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
19303 + inode->i_ctime.tv_nsec = 0;
19304 +#else
19305 + inode->i_rdev = obj->yst_rdev;
19306 + inode->i_atime = obj->yst_atime;
19307 + inode->i_mtime = obj->yst_mtime;
19308 + inode->i_ctime = obj->yst_ctime;
19309 +#endif
19310 + inode->i_size = yaffs_GetObjectFileLength(obj);
19311 + inode->i_blocks = (inode->i_size + 511) >> 9;
19312 +
19313 + inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19314 +
19315 + T(YAFFS_TRACE_OS,
19316 + (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"),
19317 + inode->i_mode, inode->i_uid, inode->i_gid,
19318 + (int)inode->i_size, atomic_read(&inode->i_count)));
19319 +
19320 + switch (obj->yst_mode & S_IFMT) {
19321 + default: /* fifo, device or socket */
19322 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19323 + init_special_inode(inode, obj->yst_mode,
19324 + old_decode_dev(obj->yst_rdev));
19325 +#else
19326 + init_special_inode(inode, obj->yst_mode,
19327 + (dev_t) (obj->yst_rdev));
19328 +#endif
19329 + break;
19330 + case S_IFREG: /* file */
19331 + inode->i_op = &yaffs_file_inode_operations;
19332 + inode->i_fop = &yaffs_file_operations;
19333 + inode->i_mapping->a_ops =
19334 + &yaffs_file_address_operations;
19335 + break;
19336 + case S_IFDIR: /* directory */
19337 + inode->i_op = &yaffs_dir_inode_operations;
19338 + inode->i_fop = &yaffs_dir_operations;
19339 + break;
19340 + case S_IFLNK: /* symlink */
19341 + inode->i_op = &yaffs_symlink_inode_operations;
19342 + break;
19343 + }
19344 +
19345 + yaffs_InodeToObjectLV(inode) = obj;
19346 +
19347 + obj->myInode = inode;
19348 +
19349 + } else {
19350 + T(YAFFS_TRACE_OS,
19351 + (TSTR("yaffs_FileInode invalid parameters\n")));
19352 + }
19353 +
19354 +}
19355 +
19356 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
19357 + yaffs_Object *obj)
19358 +{
19359 + struct inode *inode;
19360 +
19361 + if (!sb) {
19362 + T(YAFFS_TRACE_OS,
19363 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
19364 + return NULL;
19365 +
19366 + }
19367 +
19368 + if (!obj) {
19369 + T(YAFFS_TRACE_OS,
19370 + (TSTR("yaffs_get_inode for NULL object!!\n")));
19371 + return NULL;
19372 +
19373 + }
19374 +
19375 + T(YAFFS_TRACE_OS,
19376 + (TSTR("yaffs_get_inode for object %d\n"), obj->objectId));
19377 +
19378 + inode = Y_IGET(sb, obj->objectId);
19379 + if (IS_ERR(inode))
19380 + return NULL;
19381 +
19382 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
19383 + /* iget also increments the inode's i_count */
19384 + /* NB You can't be holding grossLock or deadlock will happen! */
19385 +
19386 + return inode;
19387 +}
19388 +
19389 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
19390 + loff_t *pos)
19391 +{
19392 + yaffs_Object *obj;
19393 + int nWritten, ipos;
19394 + struct inode *inode;
19395 + yaffs_Device *dev;
19396 +
19397 + obj = yaffs_DentryToObject(f->f_dentry);
19398 +
19399 + dev = obj->myDev;
19400 +
19401 + yaffs_GrossLock(dev);
19402 +
19403 + inode = f->f_dentry->d_inode;
19404 +
19405 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
19406 + ipos = inode->i_size;
19407 + else
19408 + ipos = *pos;
19409 +
19410 + if (!obj)
19411 + T(YAFFS_TRACE_OS,
19412 + (TSTR("yaffs_file_write: hey obj is null!\n")));
19413 + else
19414 + T(YAFFS_TRACE_OS,
19415 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
19416 + "to object %d at %d(%x)\n"),
19417 + (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
19418 +
19419 + nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
19420 +
19421 + yaffs_MarkSuperBlockDirty(dev);
19422 +
19423 + T(YAFFS_TRACE_OS,
19424 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
19425 + (unsigned )n,(unsigned)n));
19426 +
19427 + if (nWritten > 0) {
19428 + ipos += nWritten;
19429 + *pos = ipos;
19430 + if (ipos > inode->i_size) {
19431 + inode->i_size = ipos;
19432 + inode->i_blocks = (ipos + 511) >> 9;
19433 +
19434 + T(YAFFS_TRACE_OS,
19435 + (TSTR("yaffs_file_write size updated to %d bytes, "
19436 + "%d blocks\n"),
19437 + ipos, (int)(inode->i_blocks)));
19438 + }
19439 +
19440 + }
19441 + yaffs_GrossUnlock(dev);
19442 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
19443 +}
19444 +
19445 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
19446 +/* For now we just assume few parallel writes and check against a small number. */
19447 +/* Todo: need to do this with a counter to handle parallel reads better */
19448 +
19449 +static ssize_t yaffs_hold_space(struct file *f)
19450 +{
19451 + yaffs_Object *obj;
19452 + yaffs_Device *dev;
19453 +
19454 + int nFreeChunks;
19455 +
19456 +
19457 + obj = yaffs_DentryToObject(f->f_dentry);
19458 +
19459 + dev = obj->myDev;
19460 +
19461 + yaffs_GrossLock(dev);
19462 +
19463 + nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
19464 +
19465 + yaffs_GrossUnlock(dev);
19466 +
19467 + return (nFreeChunks > 20) ? 1 : 0;
19468 +}
19469 +
19470 +static void yaffs_release_space(struct file *f)
19471 +{
19472 + yaffs_Object *obj;
19473 + yaffs_Device *dev;
19474 +
19475 +
19476 + obj = yaffs_DentryToObject(f->f_dentry);
19477 +
19478 + dev = obj->myDev;
19479 +
19480 + yaffs_GrossLock(dev);
19481 +
19482 +
19483 + yaffs_GrossUnlock(dev);
19484 +}
19485 +
19486 +
19487 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
19488 +{
19489 + long long retval;
19490 +
19491 + lock_kernel();
19492 +
19493 + switch (origin){
19494 + case 2:
19495 + offset += i_size_read(file->f_path.dentry->d_inode);
19496 + break;
19497 + case 1:
19498 + offset += file->f_pos;
19499 + }
19500 + retval = -EINVAL;
19501 +
19502 + if (offset >= 0){
19503 + if (offset != file->f_pos)
19504 + file->f_pos = offset;
19505 +
19506 + retval = offset;
19507 + }
19508 + unlock_kernel();
19509 + return retval;
19510 +}
19511 +
19512 +
19513 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
19514 +{
19515 + yaffs_Object *obj;
19516 + yaffs_Device *dev;
19517 + struct yaffs_SearchContext *sc;
19518 + struct inode *inode = f->f_dentry->d_inode;
19519 + unsigned long offset, curoffs;
19520 + yaffs_Object *l;
19521 + int retVal = 0;
19522 +
19523 + char name[YAFFS_MAX_NAME_LENGTH + 1];
19524 +
19525 + obj = yaffs_DentryToObject(f->f_dentry);
19526 + dev = obj->myDev;
19527 +
19528 + yaffs_GrossLock(dev);
19529 +
19530 + yaffs_DeviceToLC(dev)->readdirProcess = current;
19531 +
19532 + offset = f->f_pos;
19533 +
19534 + sc = yaffs_NewSearch(obj);
19535 + if(!sc){
19536 + retVal = -ENOMEM;
19537 + goto out;
19538 + }
19539 +
19540 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
19541 +
19542 + if (offset == 0) {
19543 + T(YAFFS_TRACE_OS,
19544 + (TSTR("yaffs_readdir: entry . ino %d \n"),
19545 + (int)inode->i_ino));
19546 + yaffs_GrossUnlock(dev);
19547 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
19548 + yaffs_GrossLock(dev);
19549 + goto out;
19550 + }
19551 + yaffs_GrossLock(dev);
19552 + offset++;
19553 + f->f_pos++;
19554 + }
19555 + if (offset == 1) {
19556 + T(YAFFS_TRACE_OS,
19557 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
19558 + (int)f->f_dentry->d_parent->d_inode->i_ino));
19559 + yaffs_GrossUnlock(dev);
19560 + if (filldir(dirent, "..", 2, offset,
19561 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
19562 + yaffs_GrossLock(dev);
19563 + goto out;
19564 + }
19565 + yaffs_GrossLock(dev);
19566 + offset++;
19567 + f->f_pos++;
19568 + }
19569 +
19570 + curoffs = 1;
19571 +
19572 + /* If the directory has changed since the open or last call to
19573 + readdir, rewind to after the 2 canned entries. */
19574 + if (f->f_version != inode->i_version) {
19575 + offset = 2;
19576 + f->f_pos = offset;
19577 + f->f_version = inode->i_version;
19578 + }
19579 +
19580 + while(sc->nextReturn){
19581 + curoffs++;
19582 + l = sc->nextReturn;
19583 + if (curoffs >= offset) {
19584 + int this_inode = yaffs_GetObjectInode(l);
19585 + int this_type = yaffs_GetObjectType(l);
19586 +
19587 + yaffs_GetObjectName(l, name,
19588 + YAFFS_MAX_NAME_LENGTH + 1);
19589 + T(YAFFS_TRACE_OS,
19590 + (TSTR("yaffs_readdir: %s inode %d\n"),
19591 + name, yaffs_GetObjectInode(l)));
19592 +
19593 + yaffs_GrossUnlock(dev);
19594 +
19595 + if (filldir(dirent,
19596 + name,
19597 + strlen(name),
19598 + offset,
19599 + this_inode,
19600 + this_type) < 0){
19601 + yaffs_GrossLock(dev);
19602 + goto out;
19603 + }
19604 +
19605 + yaffs_GrossLock(dev);
19606 +
19607 + offset++;
19608 + f->f_pos++;
19609 + }
19610 + yaffs_SearchAdvance(sc);
19611 + }
19612 +
19613 +out:
19614 + yaffs_EndSearch(sc);
19615 + yaffs_DeviceToLC(dev)->readdirProcess = NULL;
19616 + yaffs_GrossUnlock(dev);
19617 +
19618 + return retVal;
19619 +}
19620 +
19621 +
19622 +
19623 +/*
19624 + * File creation. Allocate an inode, and we're done..
19625 + */
19626 +
19627 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
19628 +#define YCRED(x) x
19629 +#else
19630 +#define YCRED(x) (x->cred)
19631 +#endif
19632 +
19633 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19634 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19635 + dev_t rdev)
19636 +#else
19637 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
19638 + int rdev)
19639 +#endif
19640 +{
19641 + struct inode *inode;
19642 +
19643 + yaffs_Object *obj = NULL;
19644 + yaffs_Device *dev;
19645 +
19646 + yaffs_Object *parent = yaffs_InodeToObject(dir);
19647 +
19648 + int error = -ENOSPC;
19649 + uid_t uid = YCRED(current)->fsuid;
19650 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19651 +
19652 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
19653 + mode |= S_ISGID;
19654 +
19655 + if (parent) {
19656 + T(YAFFS_TRACE_OS,
19657 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
19658 + parent->objectId, parent->variantType));
19659 + } else {
19660 + T(YAFFS_TRACE_OS,
19661 + (TSTR("yaffs_mknod: could not get parent object\n")));
19662 + return -EPERM;
19663 + }
19664 +
19665 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
19666 + "mode %x dev %x\n"),
19667 + dentry->d_name.name, mode, rdev));
19668 +
19669 + dev = parent->myDev;
19670 +
19671 + yaffs_GrossLock(dev);
19672 +
19673 + switch (mode & S_IFMT) {
19674 + default:
19675 + /* Special (socket, fifo, device...) */
19676 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
19677 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19678 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19679 + gid, old_encode_dev(rdev));
19680 +#else
19681 + obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
19682 + gid, rdev);
19683 +#endif
19684 + break;
19685 + case S_IFREG: /* file */
19686 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
19687 + obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
19688 + gid);
19689 + break;
19690 + case S_IFDIR: /* directory */
19691 + T(YAFFS_TRACE_OS,
19692 + (TSTR("yaffs_mknod: making directory\n")));
19693 + obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
19694 + uid, gid);
19695 + break;
19696 + case S_IFLNK: /* symlink */
19697 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
19698 + obj = NULL; /* Do we ever get here? */
19699 + break;
19700 + }
19701 +
19702 + /* Can not call yaffs_get_inode() with gross lock held */
19703 + yaffs_GrossUnlock(dev);
19704 +
19705 + if (obj) {
19706 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
19707 + d_instantiate(dentry, inode);
19708 + update_dir_time(dir);
19709 + T(YAFFS_TRACE_OS,
19710 + (TSTR("yaffs_mknod created object %d count = %d\n"),
19711 + obj->objectId, atomic_read(&inode->i_count)));
19712 + error = 0;
19713 + yaffs_FillInodeFromObject(dir,parent);
19714 + } else {
19715 + T(YAFFS_TRACE_OS,
19716 + (TSTR("yaffs_mknod failed making object\n")));
19717 + error = -ENOMEM;
19718 + }
19719 +
19720 + return error;
19721 +}
19722 +
19723 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
19724 +{
19725 + int retVal;
19726 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
19727 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
19728 + return retVal;
19729 +}
19730 +
19731 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
19732 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
19733 + struct nameidata *n)
19734 +#else
19735 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
19736 +#endif
19737 +{
19738 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
19739 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
19740 +}
19741 +
19742 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
19743 +{
19744 + int retVal;
19745 +
19746 + yaffs_Device *dev;
19747 + yaffs_Object *obj;
19748 +
19749 + T(YAFFS_TRACE_OS,
19750 + (TSTR("yaffs_unlink %d:%s\n"),
19751 + (int)(dir->i_ino),
19752 + dentry->d_name.name));
19753 + obj = yaffs_InodeToObject(dir);
19754 + dev = obj->myDev;
19755 +
19756 + yaffs_GrossLock(dev);
19757 +
19758 + retVal = yaffs_Unlink(obj, dentry->d_name.name);
19759 +
19760 + if (retVal == YAFFS_OK) {
19761 + dentry->d_inode->i_nlink--;
19762 + dir->i_version++;
19763 + yaffs_GrossUnlock(dev);
19764 + mark_inode_dirty(dentry->d_inode);
19765 + update_dir_time(dir);
19766 + return 0;
19767 + }
19768 + yaffs_GrossUnlock(dev);
19769 + return -ENOTEMPTY;
19770 +}
19771 +
19772 +/*
19773 + * Create a link...
19774 + */
19775 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
19776 + struct dentry *dentry)
19777 +{
19778 + struct inode *inode = old_dentry->d_inode;
19779 + yaffs_Object *obj = NULL;
19780 + yaffs_Object *link = NULL;
19781 + yaffs_Device *dev;
19782 +
19783 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
19784 +
19785 + obj = yaffs_InodeToObject(inode);
19786 + dev = obj->myDev;
19787 +
19788 + yaffs_GrossLock(dev);
19789 +
19790 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
19791 + link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
19792 + obj);
19793 +
19794 + if (link) {
19795 + old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
19796 + d_instantiate(dentry, old_dentry->d_inode);
19797 + atomic_inc(&old_dentry->d_inode->i_count);
19798 + T(YAFFS_TRACE_OS,
19799 + (TSTR("yaffs_link link count %d i_count %d\n"),
19800 + old_dentry->d_inode->i_nlink,
19801 + atomic_read(&old_dentry->d_inode->i_count)));
19802 + }
19803 +
19804 + yaffs_GrossUnlock(dev);
19805 +
19806 + if (link){
19807 + update_dir_time(dir);
19808 + return 0;
19809 + }
19810 +
19811 + return -EPERM;
19812 +}
19813 +
19814 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
19815 + const char *symname)
19816 +{
19817 + yaffs_Object *obj;
19818 + yaffs_Device *dev;
19819 + uid_t uid = YCRED(current)->fsuid;
19820 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
19821 +
19822 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
19823 +
19824 + dev = yaffs_InodeToObject(dir)->myDev;
19825 + yaffs_GrossLock(dev);
19826 + obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
19827 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
19828 + yaffs_GrossUnlock(dev);
19829 +
19830 + if (obj) {
19831 + struct inode *inode;
19832 +
19833 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
19834 + d_instantiate(dentry, inode);
19835 + update_dir_time(dir);
19836 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
19837 + return 0;
19838 + } else {
19839 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
19840 + }
19841 +
19842 + return -ENOMEM;
19843 +}
19844 +
19845 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19846 +static int yaffs_sync_object(struct file *file, int datasync)
19847 +#else
19848 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
19849 + int datasync)
19850 +#endif
19851 +{
19852 +
19853 + yaffs_Object *obj;
19854 + yaffs_Device *dev;
19855 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
19856 + struct dentry *dentry = file->f_path.dentry;
19857 +#endif
19858 +
19859 + obj = yaffs_DentryToObject(dentry);
19860 +
19861 + dev = obj->myDev;
19862 +
19863 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
19864 + (TSTR("yaffs_sync_object\n")));
19865 + yaffs_GrossLock(dev);
19866 + yaffs_FlushFile(obj, 1, datasync);
19867 + yaffs_GrossUnlock(dev);
19868 + return 0;
19869 +}
19870 +
19871 +/*
19872 + * The VFS layer already does all the dentry stuff for rename.
19873 + *
19874 + * NB: POSIX says you can rename an object over an old object of the same name
19875 + */
19876 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
19877 + struct inode *new_dir, struct dentry *new_dentry)
19878 +{
19879 + yaffs_Device *dev;
19880 + int retVal = YAFFS_FAIL;
19881 + yaffs_Object *target;
19882 +
19883 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
19884 + dev = yaffs_InodeToObject(old_dir)->myDev;
19885 +
19886 + yaffs_GrossLock(dev);
19887 +
19888 + /* Check if the target is an existing directory that is not empty. */
19889 + target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
19890 + new_dentry->d_name.name);
19891 +
19892 +
19893 +
19894 + if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
19895 + !ylist_empty(&target->variant.directoryVariant.children)) {
19896 +
19897 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
19898 +
19899 + retVal = YAFFS_FAIL;
19900 + } else {
19901 + /* Now does unlinking internally using shadowing mechanism */
19902 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n")));
19903 +
19904 + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
19905 + old_dentry->d_name.name,
19906 + yaffs_InodeToObject(new_dir),
19907 + new_dentry->d_name.name);
19908 + }
19909 + yaffs_GrossUnlock(dev);
19910 +
19911 + if (retVal == YAFFS_OK) {
19912 + if (target) {
19913 + new_dentry->d_inode->i_nlink--;
19914 + mark_inode_dirty(new_dentry->d_inode);
19915 + }
19916 +
19917 + update_dir_time(old_dir);
19918 + if(old_dir != new_dir)
19919 + update_dir_time(new_dir);
19920 + return 0;
19921 + } else {
19922 + return -ENOTEMPTY;
19923 + }
19924 +}
19925 +
19926 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
19927 +{
19928 + struct inode *inode = dentry->d_inode;
19929 + int error = 0;
19930 + yaffs_Device *dev;
19931 +
19932 + T(YAFFS_TRACE_OS,
19933 + (TSTR("yaffs_setattr of object %d\n"),
19934 + yaffs_InodeToObject(inode)->objectId));
19935 +
19936 + /* Fail if a requested resize >= 2GB */
19937 + if (attr->ia_valid & ATTR_SIZE &&
19938 + (attr->ia_size >> 31))
19939 + error = -EINVAL;
19940 +
19941 + if (error == 0)
19942 + error = inode_change_ok(inode, attr);
19943 + if (error == 0) {
19944 + int result;
19945 + if (!error){
19946 + error = yaffs_vfs_setattr(inode, attr);
19947 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
19948 + if (attr->ia_valid & ATTR_SIZE){
19949 + yaffs_vfs_setsize(inode,attr->ia_size);
19950 + inode->i_blocks = (inode->i_size + 511) >> 9;
19951 + }
19952 + }
19953 + dev = yaffs_InodeToObject(inode)->myDev;
19954 + if (attr->ia_valid & ATTR_SIZE){
19955 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
19956 + (int)(attr->ia_size),(int)(attr->ia_size)));
19957 + }
19958 + yaffs_GrossLock(dev);
19959 + result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
19960 + if(result == YAFFS_OK) {
19961 + error = 0;
19962 + } else {
19963 + error = -EPERM;
19964 + }
19965 + yaffs_GrossUnlock(dev);
19966 +
19967 + }
19968 +
19969 + T(YAFFS_TRACE_OS,
19970 + (TSTR("yaffs_setattr done returning %d\n"),error));
19971 +
19972 + return error;
19973 +}
19974 +
19975 +#ifdef CONFIG_YAFFS_XATTR
19976 +int yaffs_setxattr(struct dentry *dentry, const char *name,
19977 + const void *value, size_t size, int flags)
19978 +{
19979 + struct inode *inode = dentry->d_inode;
19980 + int error = 0;
19981 + yaffs_Device *dev;
19982 + yaffs_Object *obj = yaffs_InodeToObject(inode);
19983 +
19984 + T(YAFFS_TRACE_OS,
19985 + (TSTR("yaffs_setxattr of object %d\n"),
19986 + obj->objectId));
19987 +
19988 +
19989 + if (error == 0) {
19990 + int result;
19991 + dev = obj->myDev;
19992 + yaffs_GrossLock(dev);
19993 + result = yaffs_SetXAttribute(obj, name, value, size, flags);
19994 + if(result == YAFFS_OK)
19995 + error = 0;
19996 + else if(result < 0)
19997 + error = result;
19998 + yaffs_GrossUnlock(dev);
19999 +
20000 + }
20001 + T(YAFFS_TRACE_OS,
20002 + (TSTR("yaffs_setxattr done returning %d\n"),error));
20003 +
20004 + return error;
20005 +}
20006 +
20007 +
20008 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
20009 + size_t size)
20010 +{
20011 + struct inode *inode = dentry->d_inode;
20012 + int error = 0;
20013 + yaffs_Device *dev;
20014 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20015 +
20016 + T(YAFFS_TRACE_OS,
20017 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
20018 + name, obj->objectId));
20019 +
20020 + if (error == 0) {
20021 + dev = obj->myDev;
20022 + yaffs_GrossLock(dev);
20023 + error = yaffs_GetXAttribute(obj, name, buff, size);
20024 + yaffs_GrossUnlock(dev);
20025 +
20026 + }
20027 + T(YAFFS_TRACE_OS,
20028 + (TSTR("yaffs_getxattr done returning %d\n"),error));
20029 +
20030 + return error;
20031 +}
20032 +
20033 +int yaffs_removexattr(struct dentry *dentry, const char *name)
20034 +{
20035 + struct inode *inode = dentry->d_inode;
20036 + int error = 0;
20037 + yaffs_Device *dev;
20038 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20039 +
20040 + T(YAFFS_TRACE_OS,
20041 + (TSTR("yaffs_removexattr of object %d\n"),
20042 + obj->objectId));
20043 +
20044 +
20045 + if (error == 0) {
20046 + int result;
20047 + dev = obj->myDev;
20048 + yaffs_GrossLock(dev);
20049 + result = yaffs_RemoveXAttribute(obj, name);
20050 + if(result == YAFFS_OK)
20051 + error = 0;
20052 + else if(result < 0)
20053 + error = result;
20054 + yaffs_GrossUnlock(dev);
20055 +
20056 + }
20057 + T(YAFFS_TRACE_OS,
20058 + (TSTR("yaffs_removexattr done returning %d\n"),error));
20059 +
20060 + return error;
20061 +}
20062 +
20063 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
20064 +{
20065 + struct inode *inode = dentry->d_inode;
20066 + int error = 0;
20067 + yaffs_Device *dev;
20068 + yaffs_Object *obj = yaffs_InodeToObject(inode);
20069 +
20070 + T(YAFFS_TRACE_OS,
20071 + (TSTR("yaffs_listxattr of object %d\n"),
20072 + obj->objectId));
20073 +
20074 +
20075 + if (error == 0) {
20076 + dev = obj->myDev;
20077 + yaffs_GrossLock(dev);
20078 + error = yaffs_ListXAttributes(obj, buff, size);
20079 + yaffs_GrossUnlock(dev);
20080 +
20081 + }
20082 + T(YAFFS_TRACE_OS,
20083 + (TSTR("yaffs_listxattr done returning %d\n"),error));
20084 +
20085 + return error;
20086 +}
20087 +
20088 +#endif
20089 +
20090 +
20091 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20092 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
20093 +{
20094 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
20095 + struct super_block *sb = dentry->d_sb;
20096 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20097 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
20098 +{
20099 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20100 +#else
20101 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
20102 +{
20103 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20104 +#endif
20105 +
20106 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
20107 +
20108 + yaffs_GrossLock(dev);
20109 +
20110 + buf->f_type = YAFFS_MAGIC;
20111 + buf->f_bsize = sb->s_blocksize;
20112 + buf->f_namelen = 255;
20113 +
20114 + if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
20115 + /* Do this if chunk size is not a power of 2 */
20116 +
20117 + uint64_t bytesInDev;
20118 + uint64_t bytesFree;
20119 +
20120 + bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) *
20121 + ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk));
20122 +
20123 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
20124 + buf->f_blocks = bytesInDev;
20125 +
20126 + bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
20127 + ((uint64_t)(dev->nDataBytesPerChunk));
20128 +
20129 + do_div(bytesFree, sb->s_blocksize);
20130 +
20131 + buf->f_bfree = bytesFree;
20132 +
20133 + } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
20134 +
20135 + buf->f_blocks =
20136 + (dev->param.endBlock - dev->param.startBlock + 1) *
20137 + dev->param.nChunksPerBlock /
20138 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20139 + buf->f_bfree =
20140 + yaffs_GetNumberOfFreeChunks(dev) /
20141 + (sb->s_blocksize / dev->nDataBytesPerChunk);
20142 + } else {
20143 + buf->f_blocks =
20144 + (dev->param.endBlock - dev->param.startBlock + 1) *
20145 + dev->param.nChunksPerBlock *
20146 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20147 +
20148 + buf->f_bfree =
20149 + yaffs_GetNumberOfFreeChunks(dev) *
20150 + (dev->nDataBytesPerChunk / sb->s_blocksize);
20151 + }
20152 +
20153 + buf->f_files = 0;
20154 + buf->f_ffree = 0;
20155 + buf->f_bavail = buf->f_bfree;
20156 +
20157 + yaffs_GrossUnlock(dev);
20158 + return 0;
20159 +}
20160 +
20161 +
20162 +
20163 +static void yaffs_FlushInodes(struct super_block *sb)
20164 +{
20165 + struct inode *iptr;
20166 + yaffs_Object *obj;
20167 +
20168 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
20169 + obj = yaffs_InodeToObject(iptr);
20170 + if(obj){
20171 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
20172 + obj->objectId));
20173 + yaffs_FlushFile(obj,1,0);
20174 + }
20175 + }
20176 +}
20177 +
20178 +
20179 +static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
20180 +{
20181 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20182 + if(!dev)
20183 + return;
20184 +
20185 + yaffs_FlushInodes(sb);
20186 + yaffs_UpdateDirtyDirectories(dev);
20187 + yaffs_FlushEntireDeviceCache(dev);
20188 + if(do_checkpoint)
20189 + yaffs_CheckpointSave(dev);
20190 +}
20191 +
20192 +
20193 +static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
20194 +{
20195 + unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
20196 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20197 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
20198 +
20199 + if(erasedChunks < dev->nFreeChunks)
20200 + scatteredFree = (dev->nFreeChunks - erasedChunks);
20201 +
20202 + if(!context->bgRunning)
20203 + return 0;
20204 + else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
20205 + return 0;
20206 + else if(erasedChunks > dev->nFreeChunks/2)
20207 + return 0;
20208 + else if(erasedChunks > dev->nFreeChunks/4)
20209 + return 1;
20210 + else
20211 + return 2;
20212 +}
20213 +
20214 +static int yaffs_do_sync_fs(struct super_block *sb,
20215 + int request_checkpoint)
20216 +{
20217 +
20218 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20219 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
20220 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
20221 + int do_checkpoint;
20222 +
20223 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20224 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
20225 + gc_urgent,
20226 + sb->s_dirt ? "dirty" : "clean",
20227 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
20228 + oneshot_checkpoint ? " one-shot" : "" ));
20229 +
20230 + yaffs_GrossLock(dev);
20231 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
20232 + oneshot_checkpoint) &&
20233 + !dev->isCheckpointed;
20234 +
20235 + if (sb->s_dirt || do_checkpoint) {
20236 + yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
20237 + sb->s_dirt = 0;
20238 + if(oneshot_checkpoint)
20239 + yaffs_auto_checkpoint &= ~4;
20240 + }
20241 + yaffs_GrossUnlock(dev);
20242 +
20243 + return 0;
20244 +}
20245 +
20246 +/*
20247 + * yaffs background thread functions .
20248 + * yaffs_BackgroundThread() the thread function
20249 + * yaffs_BackgroundStart() launches the background thread.
20250 + * yaffs_BackgroundStop() cleans up the background thread.
20251 + *
20252 + * NB:
20253 + * The thread should only run after the yaffs is initialised
20254 + * The thread should be stopped before yaffs is unmounted.
20255 + * The thread should not do any writing while the fs is in read only.
20256 + */
20257 +
20258 +#ifdef YAFFS_COMPILE_BACKGROUND
20259 +
20260 +void yaffs_background_waker(unsigned long data)
20261 +{
20262 + wake_up_process((struct task_struct *)data);
20263 +}
20264 +
20265 +static int yaffs_BackgroundThread(void *data)
20266 +{
20267 + yaffs_Device *dev = (yaffs_Device *)data;
20268 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20269 + unsigned long now = jiffies;
20270 + unsigned long next_dir_update = now;
20271 + unsigned long next_gc = now;
20272 + unsigned long expires;
20273 + unsigned int urgency;
20274 +
20275 + int gcResult;
20276 + struct timer_list timer;
20277 +
20278 + T(YAFFS_TRACE_BACKGROUND,
20279 + (TSTR("yaffs_background starting for dev %p\n"),
20280 + (void *)dev));
20281 +
20282 +#ifdef YAFFS_COMPILE_FREEZER
20283 + set_freezable();
20284 +#endif
20285 + while(context->bgRunning){
20286 + T(YAFFS_TRACE_BACKGROUND,
20287 + (TSTR("yaffs_background\n")));
20288 +
20289 + if(kthread_should_stop())
20290 + break;
20291 +
20292 +#ifdef YAFFS_COMPILE_FREEZER
20293 + if(try_to_freeze())
20294 + continue;
20295 +#endif
20296 + yaffs_GrossLock(dev);
20297 +
20298 + now = jiffies;
20299 +
20300 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
20301 + yaffs_UpdateDirtyDirectories(dev);
20302 + next_dir_update = now + HZ;
20303 + }
20304 +
20305 + if(time_after(now,next_gc) && yaffs_bg_enable){
20306 + if(!dev->isCheckpointed){
20307 + urgency = yaffs_bg_gc_urgency(dev);
20308 + gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
20309 + if(urgency > 1)
20310 + next_gc = now + HZ/20+1;
20311 + else if(urgency > 0)
20312 + next_gc = now + HZ/10+1;
20313 + else
20314 + next_gc = now + HZ * 2;
20315 + } else /*
20316 + * gc not running so set to next_dir_update
20317 + * to cut down on wake ups
20318 + */
20319 + next_gc = next_dir_update;
20320 + }
20321 + yaffs_GrossUnlock(dev);
20322 +#if 1
20323 + expires = next_dir_update;
20324 + if (time_before(next_gc,expires))
20325 + expires = next_gc;
20326 + if(time_before(expires,now))
20327 + expires = now + HZ;
20328 +
20329 + Y_INIT_TIMER(&timer);
20330 + timer.expires = expires+1;
20331 + timer.data = (unsigned long) current;
20332 + timer.function = yaffs_background_waker;
20333 +
20334 + set_current_state(TASK_INTERRUPTIBLE);
20335 + add_timer(&timer);
20336 + schedule();
20337 + del_timer_sync(&timer);
20338 +#else
20339 + msleep(10);
20340 +#endif
20341 + }
20342 +
20343 + return 0;
20344 +}
20345 +
20346 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20347 +{
20348 + int retval = 0;
20349 + struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
20350 +
20351 + if(dev->readOnly)
20352 + return -1;
20353 +
20354 + context->bgRunning = 1;
20355 +
20356 + context->bgThread = kthread_run(yaffs_BackgroundThread,
20357 + (void *)dev,"yaffs-bg-%d",context->mount_id);
20358 +
20359 + if(IS_ERR(context->bgThread)){
20360 + retval = PTR_ERR(context->bgThread);
20361 + context->bgThread = NULL;
20362 + context->bgRunning = 0;
20363 + }
20364 + return retval;
20365 +}
20366 +
20367 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20368 +{
20369 + struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
20370 +
20371 + ctxt->bgRunning = 0;
20372 +
20373 + if( ctxt->bgThread){
20374 + kthread_stop(ctxt->bgThread);
20375 + ctxt->bgThread = NULL;
20376 + }
20377 +}
20378 +#else
20379 +static int yaffs_BackgroundThread(void *data)
20380 +{
20381 + return 0;
20382 +}
20383 +
20384 +static int yaffs_BackgroundStart(yaffs_Device *dev)
20385 +{
20386 + return 0;
20387 +}
20388 +
20389 +static void yaffs_BackgroundStop(yaffs_Device *dev)
20390 +{
20391 +}
20392 +#endif
20393 +
20394 +
20395 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20396 +static void yaffs_write_super(struct super_block *sb)
20397 +#else
20398 +static int yaffs_write_super(struct super_block *sb)
20399 +#endif
20400 +{
20401 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
20402 +
20403 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
20404 + (TSTR("yaffs_write_super%s\n"),
20405 + request_checkpoint ? " checkpt" : ""));
20406 +
20407 + yaffs_do_sync_fs(sb, request_checkpoint);
20408 +
20409 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
20410 + return 0;
20411 +#endif
20412 +}
20413 +
20414 +
20415 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20416 +static int yaffs_sync_fs(struct super_block *sb, int wait)
20417 +#else
20418 +static int yaffs_sync_fs(struct super_block *sb)
20419 +#endif
20420 +{
20421 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
20422 +
20423 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
20424 + (TSTR("yaffs_sync_fs%s\n"),
20425 + request_checkpoint ? " checkpt" : ""));
20426 +
20427 + yaffs_do_sync_fs(sb, request_checkpoint);
20428 +
20429 + return 0;
20430 +}
20431 +
20432 +#ifdef YAFFS_USE_OWN_IGET
20433 +
20434 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
20435 +{
20436 + struct inode *inode;
20437 + yaffs_Object *obj;
20438 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20439 +
20440 + T(YAFFS_TRACE_OS,
20441 + (TSTR("yaffs_iget for %lu\n"), ino));
20442 +
20443 + inode = iget_locked(sb, ino);
20444 + if (!inode)
20445 + return ERR_PTR(-ENOMEM);
20446 + if (!(inode->i_state & I_NEW))
20447 + return inode;
20448 +
20449 + /* NB This is called as a side effect of other functions, but
20450 + * we had to release the lock to prevent deadlocks, so
20451 + * need to lock again.
20452 + */
20453 +
20454 + yaffs_GrossLock(dev);
20455 +
20456 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20457 +
20458 + yaffs_FillInodeFromObject(inode, obj);
20459 +
20460 + yaffs_GrossUnlock(dev);
20461 +
20462 + unlock_new_inode(inode);
20463 + return inode;
20464 +}
20465 +
20466 +#else
20467 +
20468 +static void yaffs_read_inode(struct inode *inode)
20469 +{
20470 + /* NB This is called as a side effect of other functions, but
20471 + * we had to release the lock to prevent deadlocks, so
20472 + * need to lock again.
20473 + */
20474 +
20475 + yaffs_Object *obj;
20476 + yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
20477 +
20478 + T(YAFFS_TRACE_OS,
20479 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
20480 +
20481 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20482 + yaffs_GrossLock(dev);
20483 +
20484 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
20485 +
20486 + yaffs_FillInodeFromObject(inode, obj);
20487 +
20488 + if(current != yaffs_DeviceToLC(dev)->readdirProcess)
20489 + yaffs_GrossUnlock(dev);
20490 +}
20491 +
20492 +#endif
20493 +
20494 +static YLIST_HEAD(yaffs_context_list);
20495 +struct semaphore yaffs_context_lock;
20496 +
20497 +static void yaffs_put_super(struct super_block *sb)
20498 +{
20499 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
20500 +
20501 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
20502 +
20503 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20504 + (TSTR("Shutting down yaffs background thread\n")));
20505 + yaffs_BackgroundStop(dev);
20506 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
20507 + (TSTR("yaffs background thread shut down\n")));
20508 +
20509 + yaffs_GrossLock(dev);
20510 +
20511 + yaffs_FlushSuperBlock(sb,1);
20512 +
20513 + if (yaffs_DeviceToLC(dev)->putSuperFunc)
20514 + yaffs_DeviceToLC(dev)->putSuperFunc(sb);
20515 +
20516 +
20517 + yaffs_Deinitialise(dev);
20518 +
20519 + yaffs_GrossUnlock(dev);
20520 +
20521 + down(&yaffs_context_lock);
20522 + ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
20523 + up(&yaffs_context_lock);
20524 +
20525 + if (yaffs_DeviceToLC(dev)->spareBuffer) {
20526 + YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
20527 + yaffs_DeviceToLC(dev)->spareBuffer = NULL;
20528 + }
20529 +
20530 + kfree(dev);
20531 +}
20532 +
20533 +
20534 +static void yaffs_MTDPutSuper(struct super_block *sb)
20535 +{
20536 + struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
20537 +
20538 + if (mtd->sync)
20539 + mtd->sync(mtd);
20540 +
20541 + put_mtd_device(mtd);
20542 +}
20543 +
20544 +
20545 +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
20546 +{
20547 + struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
20548 +
20549 + T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
20550 + if (sb)
20551 + sb->s_dirt = 1;
20552 +}
20553 +
20554 +typedef struct {
20555 + int inband_tags;
20556 + int skip_checkpoint_read;
20557 + int skip_checkpoint_write;
20558 + int no_cache;
20559 + int tags_ecc_on;
20560 + int tags_ecc_overridden;
20561 + int lazy_loading_enabled;
20562 + int lazy_loading_overridden;
20563 + int empty_lost_and_found;
20564 + int empty_lost_and_found_overridden;
20565 +} yaffs_options;
20566 +
20567 +#define MAX_OPT_LEN 30
20568 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
20569 +{
20570 + char cur_opt[MAX_OPT_LEN + 1];
20571 + int p;
20572 + int error = 0;
20573 +
20574 + /* Parse through the options which is a comma seperated list */
20575 +
20576 + while (options_str && *options_str && !error) {
20577 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
20578 + p = 0;
20579 +
20580 + while(*options_str == ',')
20581 + options_str++;
20582 +
20583 + while (*options_str && *options_str != ',') {
20584 + if (p < MAX_OPT_LEN) {
20585 + cur_opt[p] = *options_str;
20586 + p++;
20587 + }
20588 + options_str++;
20589 + }
20590 +
20591 + if (!strcmp(cur_opt, "inband-tags"))
20592 + options->inband_tags = 1;
20593 + else if (!strcmp(cur_opt, "tags-ecc-off")){
20594 + options->tags_ecc_on = 0;
20595 + options->tags_ecc_overridden=1;
20596 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
20597 + options->tags_ecc_on = 1;
20598 + options->tags_ecc_overridden = 1;
20599 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
20600 + options->lazy_loading_enabled = 0;
20601 + options->lazy_loading_overridden=1;
20602 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
20603 + options->lazy_loading_enabled = 1;
20604 + options->lazy_loading_overridden = 1;
20605 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
20606 + options->empty_lost_and_found = 0;
20607 + options->empty_lost_and_found_overridden=1;
20608 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
20609 + options->empty_lost_and_found = 1;
20610 + options->empty_lost_and_found_overridden=1;
20611 + } else if (!strcmp(cur_opt, "no-cache"))
20612 + options->no_cache = 1;
20613 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
20614 + options->skip_checkpoint_read = 1;
20615 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
20616 + options->skip_checkpoint_write = 1;
20617 + else if (!strcmp(cur_opt, "no-checkpoint")) {
20618 + options->skip_checkpoint_read = 1;
20619 + options->skip_checkpoint_write = 1;
20620 + } else {
20621 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
20622 + cur_opt);
20623 + error = 1;
20624 + }
20625 + }
20626 +
20627 + return error;
20628 +}
20629 +
20630 +static struct super_block *yaffs_internal_read_super(int yaffsVersion,
20631 + struct super_block *sb,
20632 + void *data, int silent)
20633 +{
20634 + int nBlocks;
20635 + struct inode *inode = NULL;
20636 + struct dentry *root;
20637 + yaffs_Device *dev = 0;
20638 + char devname_buf[BDEVNAME_SIZE + 1];
20639 + struct mtd_info *mtd;
20640 + int err;
20641 + char *data_str = (char *)data;
20642 + struct yaffs_LinuxContext *context = NULL;
20643 + yaffs_DeviceParam *param;
20644 +
20645 + int readOnly = 0;
20646 +
20647 + yaffs_options options;
20648 +
20649 + unsigned mount_id;
20650 + int found;
20651 + struct yaffs_LinuxContext *context_iterator;
20652 + struct ylist_head *l;
20653 +
20654 + sb->s_magic = YAFFS_MAGIC;
20655 + sb->s_op = &yaffs_super_ops;
20656 + sb->s_flags |= MS_NOATIME;
20657 +
20658 + readOnly =((sb->s_flags & MS_RDONLY) != 0);
20659 +
20660 +
20661 +#ifdef YAFFS_COMPILE_EXPORTFS
20662 + sb->s_export_op = &yaffs_export_ops;
20663 +#endif
20664 +
20665 + if (!sb)
20666 + printk(KERN_INFO "yaffs: sb is NULL\n");
20667 + else if (!sb->s_dev)
20668 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
20669 + else if (!yaffs_devname(sb, devname_buf))
20670 + printk(KERN_INFO "yaffs: devname is NULL\n");
20671 + else
20672 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
20673 + sb->s_dev,
20674 + yaffs_devname(sb, devname_buf),
20675 + readOnly ? "ro" : "rw");
20676 +
20677 + if (!data_str)
20678 + data_str = "";
20679 +
20680 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
20681 +
20682 + memset(&options, 0, sizeof(options));
20683 +
20684 + if (yaffs_parse_options(&options, data_str)) {
20685 + /* Option parsing failed */
20686 + return NULL;
20687 + }
20688 +
20689 +
20690 + sb->s_blocksize = PAGE_CACHE_SIZE;
20691 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
20692 +
20693 + T(YAFFS_TRACE_OS,
20694 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
20695 + T(YAFFS_TRACE_OS,
20696 + (TSTR("yaffs_read_super: block size %d\n"),
20697 + (int)(sb->s_blocksize)));
20698 +
20699 + T(YAFFS_TRACE_ALWAYS,
20700 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
20701 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
20702 + yaffs_devname(sb, devname_buf)));
20703 +
20704 + /* Check it's an mtd device..... */
20705 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
20706 + return NULL; /* This isn't an mtd device */
20707 +
20708 + /* Get the device */
20709 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
20710 + if (!mtd) {
20711 + T(YAFFS_TRACE_ALWAYS,
20712 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
20713 + MINOR(sb->s_dev)));
20714 + return NULL;
20715 + }
20716 + /* Check it's NAND */
20717 + if (mtd->type != MTD_NANDFLASH) {
20718 + T(YAFFS_TRACE_ALWAYS,
20719 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
20720 + mtd->type));
20721 + return NULL;
20722 + }
20723 +
20724 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
20725 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
20726 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
20727 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
20728 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
20729 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
20730 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
20731 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
20732 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
20733 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
20734 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
20735 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
20736 +#else
20737 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
20738 +#endif
20739 +
20740 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
20741 +
20742 + if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
20743 + T(YAFFS_TRACE_ALWAYS,
20744 + (TSTR("yaffs: auto selecting yaffs2\n")));
20745 + yaffsVersion = 2;
20746 + }
20747 +
20748 + /* Added NCB 26/5/2006 for completeness */
20749 + if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
20750 + T(YAFFS_TRACE_ALWAYS,
20751 + (TSTR("yaffs: auto selecting yaffs1\n")));
20752 + yaffsVersion = 1;
20753 + }
20754 +
20755 +#endif
20756 +
20757 + if (yaffsVersion == 2) {
20758 + /* Check for version 2 style functions */
20759 + if (!mtd->erase ||
20760 + !mtd->block_isbad ||
20761 + !mtd->block_markbad ||
20762 + !mtd->read ||
20763 + !mtd->write ||
20764 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20765 + !mtd->read_oob || !mtd->write_oob) {
20766 +#else
20767 + !mtd->write_ecc ||
20768 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20769 +#endif
20770 + T(YAFFS_TRACE_ALWAYS,
20771 + (TSTR("yaffs: MTD device does not support required "
20772 + "functions\n")));
20773 + return NULL;
20774 + }
20775 +
20776 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
20777 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
20778 + !options.inband_tags) {
20779 + T(YAFFS_TRACE_ALWAYS,
20780 + (TSTR("yaffs: MTD device does not have the "
20781 + "right page sizes\n")));
20782 + return NULL;
20783 + }
20784 + } else {
20785 + /* Check for V1 style functions */
20786 + if (!mtd->erase ||
20787 + !mtd->read ||
20788 + !mtd->write ||
20789 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20790 + !mtd->read_oob || !mtd->write_oob) {
20791 +#else
20792 + !mtd->write_ecc ||
20793 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
20794 +#endif
20795 + T(YAFFS_TRACE_ALWAYS,
20796 + (TSTR("yaffs: MTD device does not support required "
20797 + "functions\n")));
20798 + return NULL;
20799 + }
20800 +
20801 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
20802 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
20803 + T(YAFFS_TRACE_ALWAYS,
20804 + (TSTR("yaffs: MTD device does not support have the "
20805 + "right page sizes\n")));
20806 + return NULL;
20807 + }
20808 + }
20809 +
20810 + /* OK, so if we got here, we have an MTD that's NAND and looks
20811 + * like it has the right capabilities
20812 + * Set the yaffs_Device up for mtd
20813 + */
20814 +
20815 + if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
20816 + readOnly = 1;
20817 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
20818 + sb->s_flags |= MS_RDONLY;
20819 + }
20820 +
20821 + dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
20822 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
20823 +
20824 + if(!dev || !context ){
20825 + if(dev)
20826 + kfree(dev);
20827 + if(context)
20828 + kfree(context);
20829 + dev = NULL;
20830 + context = NULL;
20831 + }
20832 +
20833 + if (!dev) {
20834 + /* Deep shit could not allocate device structure */
20835 + T(YAFFS_TRACE_ALWAYS,
20836 + (TSTR("yaffs_read_super: Failed trying to allocate "
20837 + "yaffs_Device. \n")));
20838 + return NULL;
20839 + }
20840 + memset(dev, 0, sizeof(yaffs_Device));
20841 + param = &(dev->param);
20842 +
20843 + memset(context,0,sizeof(struct yaffs_LinuxContext));
20844 + dev->osContext = context;
20845 + YINIT_LIST_HEAD(&(context->contextList));
20846 + context->dev = dev;
20847 + context->superBlock = sb;
20848 +
20849 + dev->readOnly = readOnly;
20850 +
20851 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
20852 + sb->s_fs_info = dev;
20853 +#else
20854 + sb->u.generic_sbp = dev;
20855 +#endif
20856 +
20857 + dev->driverContext = mtd;
20858 + param->name = mtd->name;
20859 +
20860 + /* Set up the memory size parameters.... */
20861 +
20862 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
20863 +
20864 + param->startBlock = 0;
20865 + param->endBlock = nBlocks - 1;
20866 + param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
20867 + param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
20868 + param->nReservedBlocks = 5;
20869 + param->nShortOpCaches = (options.no_cache) ? 0 : 10;
20870 + param->inbandTags = options.inband_tags;
20871 +
20872 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
20873 + param->disableLazyLoad = 1;
20874 +#endif
20875 +#ifdef CONFIG_YAFFS_XATTR
20876 + param->enableXattr = 1;
20877 +#endif
20878 + if(options.lazy_loading_overridden)
20879 + param->disableLazyLoad = !options.lazy_loading_enabled;
20880 +
20881 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
20882 + param->noTagsECC = 1;
20883 +#endif
20884 +
20885 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
20886 +#else
20887 + param->deferDirectoryUpdate = 1;
20888 +#endif
20889 +
20890 + if(options.tags_ecc_overridden)
20891 + param->noTagsECC = !options.tags_ecc_on;
20892 +
20893 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
20894 + param->emptyLostAndFound = 1;
20895 +#endif
20896 +
20897 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
20898 + param->refreshPeriod = 0;
20899 +#else
20900 + param->refreshPeriod = 500;
20901 +#endif
20902 +
20903 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
20904 + param->alwaysCheckErased = 1;
20905 +#endif
20906 +
20907 + if(options.empty_lost_and_found_overridden)
20908 + param->emptyLostAndFound = options.empty_lost_and_found;
20909 +
20910 + /* ... and the functions. */
20911 + if (yaffsVersion == 2) {
20912 + param->writeChunkWithTagsToNAND =
20913 + nandmtd2_WriteChunkWithTagsToNAND;
20914 + param->readChunkWithTagsFromNAND =
20915 + nandmtd2_ReadChunkWithTagsFromNAND;
20916 + param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
20917 + param->queryNANDBlock = nandmtd2_QueryNANDBlock;
20918 + yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
20919 + param->isYaffs2 = 1;
20920 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20921 + param->totalBytesPerChunk = mtd->writesize;
20922 + param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
20923 +#else
20924 + param->totalBytesPerChunk = mtd->oobblock;
20925 + param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
20926 +#endif
20927 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
20928 +
20929 + param->startBlock = 0;
20930 + param->endBlock = nBlocks - 1;
20931 + } else {
20932 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
20933 + /* use the MTD interface in yaffs_mtdif1.c */
20934 + param->writeChunkWithTagsToNAND =
20935 + nandmtd1_WriteChunkWithTagsToNAND;
20936 + param->readChunkWithTagsFromNAND =
20937 + nandmtd1_ReadChunkWithTagsFromNAND;
20938 + param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
20939 + param->queryNANDBlock = nandmtd1_QueryNANDBlock;
20940 +#else
20941 + param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
20942 + param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
20943 +#endif
20944 + param->isYaffs2 = 0;
20945 + }
20946 + /* ... and common functions */
20947 + param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
20948 + param->initialiseNAND = nandmtd_InitialiseNAND;
20949 +
20950 + yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
20951 +
20952 + param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
20953 + param->gcControl = yaffs_gc_control_callback;
20954 +
20955 + yaffs_DeviceToLC(dev)->superBlock= sb;
20956 +
20957 +
20958 +#ifndef CONFIG_YAFFS_DOES_ECC
20959 + param->useNANDECC = 1;
20960 +#endif
20961 +
20962 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
20963 + param->wideTnodesDisabled = 1;
20964 +#endif
20965 +
20966 + param->skipCheckpointRead = options.skip_checkpoint_read;
20967 + param->skipCheckpointWrite = options.skip_checkpoint_write;
20968 +
20969 + down(&yaffs_context_lock);
20970 + /* Get a mount id */
20971 + found = 0;
20972 + for(mount_id=0; ! found; mount_id++){
20973 + found = 1;
20974 + ylist_for_each(l,&yaffs_context_list){
20975 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
20976 + if(context_iterator->mount_id == mount_id)
20977 + found = 0;
20978 + }
20979 + }
20980 + context->mount_id = mount_id;
20981 +
20982 + ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
20983 + up(&yaffs_context_lock);
20984 +
20985 + /* Directory search handling...*/
20986 + YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
20987 + param->removeObjectCallback = yaffs_RemoveObjectCallback;
20988 +
20989 + init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
20990 +
20991 + yaffs_GrossLock(dev);
20992 +
20993 + err = yaffs_GutsInitialise(dev);
20994 +
20995 + T(YAFFS_TRACE_OS,
20996 + (TSTR("yaffs_read_super: guts initialised %s\n"),
20997 + (err == YAFFS_OK) ? "OK" : "FAILED"));
20998 +
20999 + if(err == YAFFS_OK)
21000 + yaffs_BackgroundStart(dev);
21001 +
21002 + if(!context->bgThread)
21003 + param->deferDirectoryUpdate = 0;
21004 +
21005 +
21006 + /* Release lock before yaffs_get_inode() */
21007 + yaffs_GrossUnlock(dev);
21008 +
21009 + /* Create root inode */
21010 + if (err == YAFFS_OK)
21011 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
21012 + yaffs_Root(dev));
21013 +
21014 + if (!inode)
21015 + return NULL;
21016 +
21017 + inode->i_op = &yaffs_dir_inode_operations;
21018 + inode->i_fop = &yaffs_dir_operations;
21019 +
21020 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
21021 +
21022 + root = d_alloc_root(inode);
21023 +
21024 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
21025 +
21026 + if (!root) {
21027 + iput(inode);
21028 + return NULL;
21029 + }
21030 + sb->s_root = root;
21031 + sb->s_dirt = !dev->isCheckpointed;
21032 + T(YAFFS_TRACE_ALWAYS,
21033 + (TSTR("yaffs_read_super: isCheckpointed %d\n"),
21034 + dev->isCheckpointed));
21035 +
21036 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
21037 + return sb;
21038 +}
21039 +
21040 +
21041 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21042 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
21043 + int silent)
21044 +{
21045 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
21046 +}
21047 +
21048 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21049 +static int yaffs_read_super(struct file_system_type *fs,
21050 + int flags, const char *dev_name,
21051 + void *data, struct vfsmount *mnt)
21052 +{
21053 +
21054 + return get_sb_bdev(fs, flags, dev_name, data,
21055 + yaffs_internal_read_super_mtd, mnt);
21056 +}
21057 +#else
21058 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
21059 + int flags, const char *dev_name,
21060 + void *data)
21061 +{
21062 +
21063 + return get_sb_bdev(fs, flags, dev_name, data,
21064 + yaffs_internal_read_super_mtd);
21065 +}
21066 +#endif
21067 +
21068 +static struct file_system_type yaffs_fs_type = {
21069 + .owner = THIS_MODULE,
21070 + .name = "yaffs",
21071 + .get_sb = yaffs_read_super,
21072 + .kill_sb = kill_block_super,
21073 + .fs_flags = FS_REQUIRES_DEV,
21074 +};
21075 +#else
21076 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
21077 + int silent)
21078 +{
21079 + return yaffs_internal_read_super(1, sb, data, silent);
21080 +}
21081 +
21082 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
21083 + FS_REQUIRES_DEV);
21084 +#endif
21085 +
21086 +
21087 +#ifdef CONFIG_YAFFS_YAFFS2
21088 +
21089 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21090 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
21091 + int silent)
21092 +{
21093 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
21094 +}
21095 +
21096 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21097 +static int yaffs2_read_super(struct file_system_type *fs,
21098 + int flags, const char *dev_name, void *data,
21099 + struct vfsmount *mnt)
21100 +{
21101 + return get_sb_bdev(fs, flags, dev_name, data,
21102 + yaffs2_internal_read_super_mtd, mnt);
21103 +}
21104 +#else
21105 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
21106 + int flags, const char *dev_name,
21107 + void *data)
21108 +{
21109 +
21110 + return get_sb_bdev(fs, flags, dev_name, data,
21111 + yaffs2_internal_read_super_mtd);
21112 +}
21113 +#endif
21114 +
21115 +static struct file_system_type yaffs2_fs_type = {
21116 + .owner = THIS_MODULE,
21117 + .name = "yaffs2",
21118 + .get_sb = yaffs2_read_super,
21119 + .kill_sb = kill_block_super,
21120 + .fs_flags = FS_REQUIRES_DEV,
21121 +};
21122 +#else
21123 +static struct super_block *yaffs2_read_super(struct super_block *sb,
21124 + void *data, int silent)
21125 +{
21126 + return yaffs_internal_read_super(2, sb, data, silent);
21127 +}
21128 +
21129 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
21130 + FS_REQUIRES_DEV);
21131 +#endif
21132 +
21133 +#endif /* CONFIG_YAFFS_YAFFS2 */
21134 +
21135 +static struct proc_dir_entry *my_proc_entry;
21136 +static struct proc_dir_entry *debug_proc_entry;
21137 +
21138 +static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
21139 +{
21140 + buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
21141 + buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
21142 + buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
21143 + buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
21144 + buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
21145 + buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
21146 + buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
21147 + buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
21148 + buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
21149 + buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
21150 + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
21151 + buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks);
21152 + buf += sprintf(buf, "alwaysCheckErased.. %d\n", dev->param.alwaysCheckErased);
21153 +
21154 + buf += sprintf(buf, "\n");
21155 +
21156 + return buf;
21157 +}
21158 +
21159 +
21160 +static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
21161 +{
21162 + buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
21163 + buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
21164 + buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
21165 + buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
21166 + buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
21167 + buf += sprintf(buf, "\n");
21168 + buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
21169 + buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
21170 + buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
21171 + buf += sprintf(buf, "\n");
21172 + buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
21173 + buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
21174 + buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
21175 + buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
21176 + buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
21177 + buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
21178 + buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
21179 + buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks);
21180 + buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
21181 + buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
21182 + buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
21183 + buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
21184 + buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed);
21185 + buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed);
21186 + buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed);
21187 + buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits);
21188 + buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles);
21189 + buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles);
21190 + buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount);
21191 + buf +=
21192 + sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions);
21193 +
21194 + return buf;
21195 +}
21196 +
21197 +static int yaffs_proc_read(char *page,
21198 + char **start,
21199 + off_t offset, int count, int *eof, void *data)
21200 +{
21201 + struct ylist_head *item;
21202 + char *buf = page;
21203 + int step = offset;
21204 + int n = 0;
21205 +
21206 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
21207 + * We use 'offset' (*ppos) to indicate where we are in devList.
21208 + * This also assumes the user has posted a read buffer large
21209 + * enough to hold the complete output; but that's life in /proc.
21210 + */
21211 +
21212 + *(int *)start = 1;
21213 +
21214 + /* Print header first */
21215 + if (step == 0)
21216 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
21217 + else if (step == 1)
21218 + buf += sprintf(buf,"\n");
21219 + else {
21220 + step-=2;
21221 +
21222 + down(&yaffs_context_lock);
21223 +
21224 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21225 + ylist_for_each(item, &yaffs_context_list) {
21226 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21227 + yaffs_Device *dev = dc->dev;
21228 +
21229 + if (n < (step & ~1)) {
21230 + n+=2;
21231 + continue;
21232 + }
21233 + if((step & 1)==0){
21234 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
21235 + buf = yaffs_dump_dev_part0(buf, dev);
21236 + } else
21237 + buf = yaffs_dump_dev_part1(buf, dev);
21238 +
21239 + break;
21240 + }
21241 + up(&yaffs_context_lock);
21242 + }
21243 +
21244 + return buf - page < count ? buf - page : count;
21245 +}
21246 +
21247 +static int yaffs_stats_proc_read(char *page,
21248 + char **start,
21249 + off_t offset, int count, int *eof, void *data)
21250 +{
21251 + struct ylist_head *item;
21252 + char *buf = page;
21253 + int n = 0;
21254 +
21255 + down(&yaffs_context_lock);
21256 +
21257 + /* Locate and print the Nth entry. Order N-squared but N is small. */
21258 + ylist_for_each(item, &yaffs_context_list) {
21259 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
21260 + yaffs_Device *dev = dc->dev;
21261 +
21262 + int erasedChunks;
21263 +
21264 + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
21265 +
21266 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
21267 + n, dev->nFreeChunks, erasedChunks,
21268 + dev->backgroundGCs, dev->oldestDirtyGCs,
21269 + dev->nObjects, dev->nTnodes);
21270 + }
21271 + up(&yaffs_context_lock);
21272 +
21273 +
21274 + return buf - page < count ? buf - page : count;
21275 +}
21276 +
21277 +/**
21278 + * Set the verbosity of the warnings and error messages.
21279 + *
21280 + * Note that the names can only be a..z or _ with the current code.
21281 + */
21282 +
21283 +static struct {
21284 + char *mask_name;
21285 + unsigned mask_bitfield;
21286 +} mask_flags[] = {
21287 + {"allocate", YAFFS_TRACE_ALLOCATE},
21288 + {"always", YAFFS_TRACE_ALWAYS},
21289 + {"background", YAFFS_TRACE_BACKGROUND},
21290 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
21291 + {"buffers", YAFFS_TRACE_BUFFERS},
21292 + {"bug", YAFFS_TRACE_BUG},
21293 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
21294 + {"deletion", YAFFS_TRACE_DELETION},
21295 + {"erase", YAFFS_TRACE_ERASE},
21296 + {"error", YAFFS_TRACE_ERROR},
21297 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
21298 + {"gc", YAFFS_TRACE_GC},
21299 + {"lock", YAFFS_TRACE_LOCK},
21300 + {"mtd", YAFFS_TRACE_MTD},
21301 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
21302 + {"os", YAFFS_TRACE_OS},
21303 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
21304 + {"scan", YAFFS_TRACE_SCAN},
21305 + {"tracing", YAFFS_TRACE_TRACING},
21306 + {"sync", YAFFS_TRACE_SYNC},
21307 + {"write", YAFFS_TRACE_WRITE},
21308 +
21309 + {"verify", YAFFS_TRACE_VERIFY},
21310 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
21311 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
21312 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
21313 +
21314 + {"all", 0xffffffff},
21315 + {"none", 0},
21316 + {NULL, 0},
21317 +};
21318 +
21319 +#define MAX_MASK_NAME_LENGTH 40
21320 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
21321 + unsigned long count, void *data)
21322 +{
21323 + unsigned rg = 0, mask_bitfield;
21324 + char *end;
21325 + char *mask_name;
21326 + const char *x;
21327 + char substring[MAX_MASK_NAME_LENGTH + 1];
21328 + int i;
21329 + int done = 0;
21330 + int add, len = 0;
21331 + int pos = 0;
21332 +
21333 + rg = yaffs_traceMask;
21334 +
21335 + while (!done && (pos < count)) {
21336 + done = 1;
21337 + while ((pos < count) && isspace(buf[pos]))
21338 + pos++;
21339 +
21340 + switch (buf[pos]) {
21341 + case '+':
21342 + case '-':
21343 + case '=':
21344 + add = buf[pos];
21345 + pos++;
21346 + break;
21347 +
21348 + default:
21349 + add = ' ';
21350 + break;
21351 + }
21352 + mask_name = NULL;
21353 +
21354 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
21355 +
21356 + if (end > buf + pos) {
21357 + mask_name = "numeral";
21358 + len = end - (buf + pos);
21359 + pos += len;
21360 + done = 0;
21361 + } else {
21362 + for (x = buf + pos, i = 0;
21363 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
21364 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
21365 + substring[i] = *x;
21366 + substring[i] = '\0';
21367 +
21368 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21369 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
21370 + mask_name = mask_flags[i].mask_name;
21371 + mask_bitfield = mask_flags[i].mask_bitfield;
21372 + done = 0;
21373 + break;
21374 + }
21375 + }
21376 + }
21377 +
21378 + if (mask_name != NULL) {
21379 + done = 0;
21380 + switch (add) {
21381 + case '-':
21382 + rg &= ~mask_bitfield;
21383 + break;
21384 + case '+':
21385 + rg |= mask_bitfield;
21386 + break;
21387 + case '=':
21388 + rg = mask_bitfield;
21389 + break;
21390 + default:
21391 + rg |= mask_bitfield;
21392 + break;
21393 + }
21394 + }
21395 + }
21396 +
21397 + yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
21398 +
21399 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
21400 +
21401 + if (rg & YAFFS_TRACE_ALWAYS) {
21402 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
21403 + char flag;
21404 + flag = ((rg & mask_flags[i].mask_bitfield) ==
21405 + mask_flags[i].mask_bitfield) ? '+' : '-';
21406 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
21407 + }
21408 + }
21409 +
21410 + return count;
21411 +}
21412 +
21413 +
21414 +static int yaffs_proc_write(struct file *file, const char *buf,
21415 + unsigned long count, void *data)
21416 +{
21417 + return yaffs_proc_write_trace_options(file, buf, count, data);
21418 +}
21419 +
21420 +/* Stuff to handle installation of file systems */
21421 +struct file_system_to_install {
21422 + struct file_system_type *fst;
21423 + int installed;
21424 +};
21425 +
21426 +static struct file_system_to_install fs_to_install[] = {
21427 + {&yaffs_fs_type, 0},
21428 + {&yaffs2_fs_type, 0},
21429 + {NULL, 0}
21430 +};
21431 +
21432 +static int __init init_yaffs_fs(void)
21433 +{
21434 + int error = 0;
21435 + struct file_system_to_install *fsinst;
21436 +
21437 + T(YAFFS_TRACE_ALWAYS,
21438 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
21439 +
21440 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
21441 + T(YAFFS_TRACE_ALWAYS,
21442 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
21443 +#endif
21444 +
21445 +
21446 +
21447 +
21448 + init_MUTEX(&yaffs_context_lock);
21449 +
21450 + /* Install the proc_fs entries */
21451 + my_proc_entry = create_proc_entry("yaffs",
21452 + S_IRUGO | S_IFREG,
21453 + YPROC_ROOT);
21454 +
21455 + if (my_proc_entry) {
21456 + my_proc_entry->write_proc = yaffs_proc_write;
21457 + my_proc_entry->read_proc = yaffs_proc_read;
21458 + my_proc_entry->data = NULL;
21459 + } else
21460 + return -ENOMEM;
21461 +
21462 + debug_proc_entry = create_proc_entry("yaffs_stats",
21463 + S_IRUGO | S_IFREG,
21464 + YPROC_ROOT);
21465 +
21466 + if (debug_proc_entry) {
21467 + debug_proc_entry->write_proc = NULL;
21468 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
21469 + debug_proc_entry->data = NULL;
21470 + } else
21471 + return -ENOMEM;
21472 +
21473 + /* Now add the file system entries */
21474 +
21475 + fsinst = fs_to_install;
21476 +
21477 + while (fsinst->fst && !error) {
21478 + error = register_filesystem(fsinst->fst);
21479 + if (!error)
21480 + fsinst->installed = 1;
21481 + fsinst++;
21482 + }
21483 +
21484 + /* Any errors? uninstall */
21485 + if (error) {
21486 + fsinst = fs_to_install;
21487 +
21488 + while (fsinst->fst) {
21489 + if (fsinst->installed) {
21490 + unregister_filesystem(fsinst->fst);
21491 + fsinst->installed = 0;
21492 + }
21493 + fsinst++;
21494 + }
21495 + }
21496 +
21497 + return error;
21498 +}
21499 +
21500 +static void __exit exit_yaffs_fs(void)
21501 +{
21502 +
21503 + struct file_system_to_install *fsinst;
21504 +
21505 + T(YAFFS_TRACE_ALWAYS,
21506 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
21507 +
21508 + remove_proc_entry("yaffs", YPROC_ROOT);
21509 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
21510 +
21511 + fsinst = fs_to_install;
21512 +
21513 + while (fsinst->fst) {
21514 + if (fsinst->installed) {
21515 + unregister_filesystem(fsinst->fst);
21516 + fsinst->installed = 0;
21517 + }
21518 + fsinst++;
21519 + }
21520 +}
21521 +
21522 +module_init(init_yaffs_fs)
21523 +module_exit(exit_yaffs_fs)
21524 +
21525 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
21526 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
21527 +MODULE_LICENSE("GPL");
21528 diff -Nrup a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c
21529 --- a/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 02:00:00.000000000 +0200
21530 +++ b/fs/yaffs2/yaffs_yaffs1.c 2010-10-03 18:03:47.535000365 +0300
21531 @@ -0,0 +1,465 @@
21532 +/*
21533 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21534 + *
21535 + * Copyright (C) 2002-2010 Aleph One Ltd.
21536 + * for Toby Churchill Ltd and Brightstar Engineering
21537 + *
21538 + * Created by Charles Manning <charles@aleph1.co.uk>
21539 + *
21540 + * This program is free software; you can redistribute it and/or modify
21541 + * it under the terms of the GNU General Public License version 2 as
21542 + * published by the Free Software Foundation.
21543 + */
21544 +#include "yaffs_yaffs1.h"
21545 +#include "yportenv.h"
21546 +#include "yaffs_trace.h"
21547 +#include "yaffs_bitmap.h"
21548 +#include "yaffs_getblockinfo.h"
21549 +#include "yaffs_nand.h"
21550 +
21551 +
21552 +int yaffs1_Scan(yaffs_Device *dev)
21553 +{
21554 + yaffs_ExtendedTags tags;
21555 + int blk;
21556 + int blockIterator;
21557 + int startIterator;
21558 + int endIterator;
21559 + int result;
21560 +
21561 + int chunk;
21562 + int c;
21563 + int deleted;
21564 + yaffs_BlockState state;
21565 + yaffs_Object *hardList = NULL;
21566 + yaffs_BlockInfo *bi;
21567 + __u32 sequenceNumber;
21568 + yaffs_ObjectHeader *oh;
21569 + yaffs_Object *in;
21570 + yaffs_Object *parent;
21571 +
21572 + int alloc_failed = 0;
21573 +
21574 + struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
21575 +
21576 +
21577 + __u8 *chunkData;
21578 +
21579 +
21580 +
21581 + T(YAFFS_TRACE_SCAN,
21582 + (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
21583 + dev->internalStartBlock, dev->internalEndBlock));
21584 +
21585 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
21586 +
21587 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
21588 +
21589 + /* Scan all the blocks to determine their state */
21590 + bi = dev->blockInfo;
21591 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
21592 + yaffs_ClearChunkBits(dev, blk);
21593 + bi->pagesInUse = 0;
21594 + bi->softDeletions = 0;
21595 +
21596 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
21597 +
21598 + bi->blockState = state;
21599 + bi->sequenceNumber = sequenceNumber;
21600 +
21601 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
21602 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
21603 +
21604 + T(YAFFS_TRACE_SCAN_DEBUG,
21605 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
21606 + state, sequenceNumber));
21607 +
21608 + if (state == YAFFS_BLOCK_STATE_DEAD) {
21609 + T(YAFFS_TRACE_BAD_BLOCKS,
21610 + (TSTR("block %d is bad" TENDSTR), blk));
21611 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
21612 + T(YAFFS_TRACE_SCAN_DEBUG,
21613 + (TSTR("Block empty " TENDSTR)));
21614 + dev->nErasedBlocks++;
21615 + dev->nFreeChunks += dev->param.nChunksPerBlock;
21616 + }
21617 + bi++;
21618 + }
21619 +
21620 + startIterator = dev->internalStartBlock;
21621 + endIterator = dev->internalEndBlock;
21622 +
21623 + /* For each block.... */
21624 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
21625 + blockIterator++) {
21626 +
21627 + YYIELD();
21628 +
21629 + YYIELD();
21630 +
21631 + blk = blockIterator;
21632 +
21633 + bi = yaffs_GetBlockInfo(dev, blk);
21634 + state = bi->blockState;
21635 +
21636 + deleted = 0;
21637 +
21638 + /* For each chunk in each block that needs scanning....*/
21639 + for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&
21640 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
21641 + /* Read the tags and decide what to do */
21642 + chunk = blk * dev->param.nChunksPerBlock + c;
21643 +
21644 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
21645 + &tags);
21646 +
21647 + /* Let's have a good look at this chunk... */
21648 +
21649 + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
21650 + /* YAFFS1 only...
21651 + * A deleted chunk
21652 + */
21653 + deleted++;
21654 + dev->nFreeChunks++;
21655 + /*T((" %d %d deleted\n",blk,c)); */
21656 + } else if (!tags.chunkUsed) {
21657 + /* An unassigned chunk in the block
21658 + * This means that either the block is empty or
21659 + * this is the one being allocated from
21660 + */
21661 +
21662 + if (c == 0) {
21663 + /* We're looking at the first chunk in the block so the block is unused */
21664 + state = YAFFS_BLOCK_STATE_EMPTY;
21665 + dev->nErasedBlocks++;
21666 + } else {
21667 + /* this is the block being allocated from */
21668 + T(YAFFS_TRACE_SCAN,
21669 + (TSTR
21670 + (" Allocating from %d %d" TENDSTR),
21671 + blk, c));
21672 + state = YAFFS_BLOCK_STATE_ALLOCATING;
21673 + dev->allocationBlock = blk;
21674 + dev->allocationPage = c;
21675 + dev->allocationBlockFinder = blk;
21676 + /* Set block finder here to encourage the allocator to go forth from here. */
21677 +
21678 + }
21679 +
21680 + dev->nFreeChunks += (dev->param.nChunksPerBlock - c);
21681 + } else if (tags.chunkId > 0) {
21682 + /* chunkId > 0 so it is a data chunk... */
21683 + unsigned int endpos;
21684 +
21685 + yaffs_SetChunkBit(dev, blk, c);
21686 + bi->pagesInUse++;
21687 +
21688 + in = yaffs_FindOrCreateObjectByNumber(dev,
21689 + tags.
21690 + objectId,
21691 + YAFFS_OBJECT_TYPE_FILE);
21692 + /* PutChunkIntoFile checks for a clash (two data chunks with
21693 + * the same chunkId).
21694 + */
21695 +
21696 + if (!in)
21697 + alloc_failed = 1;
21698 +
21699 + if (in) {
21700 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
21701 + alloc_failed = 1;
21702 + }
21703 +
21704 + endpos =
21705 + (tags.chunkId - 1) * dev->nDataBytesPerChunk +
21706 + tags.byteCount;
21707 + if (in &&
21708 + in->variantType == YAFFS_OBJECT_TYPE_FILE
21709 + && in->variant.fileVariant.scannedFileSize <
21710 + endpos) {
21711 + in->variant.fileVariant.
21712 + scannedFileSize = endpos;
21713 + if (!dev->param.useHeaderFileSize) {
21714 + in->variant.fileVariant.
21715 + fileSize =
21716 + in->variant.fileVariant.
21717 + scannedFileSize;
21718 + }
21719 +
21720 + }
21721 + /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
21722 + } else {
21723 + /* chunkId == 0, so it is an ObjectHeader.
21724 + * Thus, we read in the object header and make the object
21725 + */
21726 + yaffs_SetChunkBit(dev, blk, c);
21727 + bi->pagesInUse++;
21728 +
21729 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
21730 + chunkData,
21731 + NULL);
21732 +
21733 + oh = (yaffs_ObjectHeader *) chunkData;
21734 +
21735 + in = yaffs_FindObjectByNumber(dev,
21736 + tags.objectId);
21737 + if (in && in->variantType != oh->type) {
21738 + /* This should not happen, but somehow
21739 + * Wev'e ended up with an objectId that has been reused but not yet
21740 + * deleted, and worse still it has changed type. Delete the old object.
21741 + */
21742 +
21743 + yaffs_DeleteObject(in);
21744 +
21745 + in = 0;
21746 + }
21747 +
21748 + in = yaffs_FindOrCreateObjectByNumber(dev,
21749 + tags.
21750 + objectId,
21751 + oh->type);
21752 +
21753 + if (!in)
21754 + alloc_failed = 1;
21755 +
21756 + if (in && oh->shadowsObject > 0) {
21757 +
21758 + struct yaffs_ShadowFixerStruct *fixer;
21759 + fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
21760 + if (fixer) {
21761 + fixer->next = shadowFixerList;
21762 + shadowFixerList = fixer;
21763 + fixer->objectId = tags.objectId;
21764 + fixer->shadowedId = oh->shadowsObject;
21765 + T(YAFFS_TRACE_SCAN,
21766 + (TSTR
21767 + (" Shadow fixer: %d shadows %d" TENDSTR),
21768 + fixer->objectId, fixer->shadowedId));
21769 +
21770 + }
21771 +
21772 + }
21773 +
21774 + if (in && in->valid) {
21775 + /* We have already filled this one. We have a duplicate and need to resolve it. */
21776 +
21777 + unsigned existingSerial = in->serial;
21778 + unsigned newSerial = tags.serialNumber;
21779 +
21780 + if (((existingSerial + 1) & 3) == newSerial) {
21781 + /* Use new one - destroy the exisiting one */
21782 + yaffs_DeleteChunk(dev,
21783 + in->hdrChunk,
21784 + 1, __LINE__);
21785 + in->valid = 0;
21786 + } else {
21787 + /* Use existing - destroy this one. */
21788 + yaffs_DeleteChunk(dev, chunk, 1,
21789 + __LINE__);
21790 + }
21791 + }
21792 +
21793 + if (in && !in->valid &&
21794 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
21795 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
21796 + /* We only load some info, don't fiddle with directory structure */
21797 + in->valid = 1;
21798 + in->variantType = oh->type;
21799 +
21800 + in->yst_mode = oh->yst_mode;
21801 +#ifdef CONFIG_YAFFS_WINCE
21802 + in->win_atime[0] = oh->win_atime[0];
21803 + in->win_ctime[0] = oh->win_ctime[0];
21804 + in->win_mtime[0] = oh->win_mtime[0];
21805 + in->win_atime[1] = oh->win_atime[1];
21806 + in->win_ctime[1] = oh->win_ctime[1];
21807 + in->win_mtime[1] = oh->win_mtime[1];
21808 +#else
21809 + in->yst_uid = oh->yst_uid;
21810 + in->yst_gid = oh->yst_gid;
21811 + in->yst_atime = oh->yst_atime;
21812 + in->yst_mtime = oh->yst_mtime;
21813 + in->yst_ctime = oh->yst_ctime;
21814 + in->yst_rdev = oh->yst_rdev;
21815 +#endif
21816 + in->hdrChunk = chunk;
21817 + in->serial = tags.serialNumber;
21818 +
21819 + } else if (in && !in->valid) {
21820 + /* we need to load this info */
21821 +
21822 + in->valid = 1;
21823 + in->variantType = oh->type;
21824 +
21825 + in->yst_mode = oh->yst_mode;
21826 +#ifdef CONFIG_YAFFS_WINCE
21827 + in->win_atime[0] = oh->win_atime[0];
21828 + in->win_ctime[0] = oh->win_ctime[0];
21829 + in->win_mtime[0] = oh->win_mtime[0];
21830 + in->win_atime[1] = oh->win_atime[1];
21831 + in->win_ctime[1] = oh->win_ctime[1];
21832 + in->win_mtime[1] = oh->win_mtime[1];
21833 +#else
21834 + in->yst_uid = oh->yst_uid;
21835 + in->yst_gid = oh->yst_gid;
21836 + in->yst_atime = oh->yst_atime;
21837 + in->yst_mtime = oh->yst_mtime;
21838 + in->yst_ctime = oh->yst_ctime;
21839 + in->yst_rdev = oh->yst_rdev;
21840 +#endif
21841 + in->hdrChunk = chunk;
21842 + in->serial = tags.serialNumber;
21843 +
21844 + yaffs_SetObjectNameFromOH(in, oh);
21845 + in->dirty = 0;
21846 +
21847 + /* directory stuff...
21848 + * hook up to parent
21849 + */
21850 +
21851 + parent =
21852 + yaffs_FindOrCreateObjectByNumber
21853 + (dev, oh->parentObjectId,
21854 + YAFFS_OBJECT_TYPE_DIRECTORY);
21855 + if (!parent)
21856 + alloc_failed = 1;
21857 + if (parent && parent->variantType ==
21858 + YAFFS_OBJECT_TYPE_UNKNOWN) {
21859 + /* Set up as a directory */
21860 + parent->variantType =
21861 + YAFFS_OBJECT_TYPE_DIRECTORY;
21862 + YINIT_LIST_HEAD(&parent->variant.
21863 + directoryVariant.
21864 + children);
21865 + } else if (!parent || parent->variantType !=
21866 + YAFFS_OBJECT_TYPE_DIRECTORY) {
21867 + /* Hoosterman, another problem....
21868 + * We're trying to use a non-directory as a directory
21869 + */
21870 +
21871 + T(YAFFS_TRACE_ERROR,
21872 + (TSTR
21873 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
21874 + TENDSTR)));
21875 + parent = dev->lostNFoundDir;
21876 + }
21877 +
21878 + yaffs_AddObjectToDirectory(parent, in);
21879 +
21880 + if (0 && (parent == dev->deletedDir ||
21881 + parent == dev->unlinkedDir)) {
21882 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
21883 + dev->nDeletedFiles++;
21884 + }
21885 + /* Note re hardlinks.
21886 + * Since we might scan a hardlink before its equivalent object is scanned
21887 + * we put them all in a list.
21888 + * After scanning is complete, we should have all the objects, so we run through this
21889 + * list and fix up all the chains.
21890 + */
21891 +
21892 + switch (in->variantType) {
21893 + case YAFFS_OBJECT_TYPE_UNKNOWN:
21894 + /* Todo got a problem */
21895 + break;
21896 + case YAFFS_OBJECT_TYPE_FILE:
21897 + if (dev->param.useHeaderFileSize)
21898 +
21899 + in->variant.fileVariant.
21900 + fileSize =
21901 + oh->fileSize;
21902 +
21903 + break;
21904 + case YAFFS_OBJECT_TYPE_HARDLINK:
21905 + in->variant.hardLinkVariant.
21906 + equivalentObjectId =
21907 + oh->equivalentObjectId;
21908 + in->hardLinks.next =
21909 + (struct ylist_head *)
21910 + hardList;
21911 + hardList = in;
21912 + break;
21913 + case YAFFS_OBJECT_TYPE_DIRECTORY:
21914 + /* Do nothing */
21915 + break;
21916 + case YAFFS_OBJECT_TYPE_SPECIAL:
21917 + /* Do nothing */
21918 + break;
21919 + case YAFFS_OBJECT_TYPE_SYMLINK:
21920 + in->variant.symLinkVariant.alias =
21921 + yaffs_CloneString(oh->alias);
21922 + if (!in->variant.symLinkVariant.alias)
21923 + alloc_failed = 1;
21924 + break;
21925 + }
21926 +
21927 + }
21928 + }
21929 + }
21930 +
21931 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
21932 + /* If we got this far while scanning, then the block is fully allocated.*/
21933 + state = YAFFS_BLOCK_STATE_FULL;
21934 + }
21935 +
21936 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
21937 + /* If the block was partially allocated then treat it as fully allocated.*/
21938 + state = YAFFS_BLOCK_STATE_FULL;
21939 + dev->allocationBlock = -1;
21940 + }
21941 +
21942 + bi->blockState = state;
21943 +
21944 + /* Now let's see if it was dirty */
21945 + if (bi->pagesInUse == 0 &&
21946 + !bi->hasShrinkHeader &&
21947 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
21948 + yaffs_BlockBecameDirty(dev, blk);
21949 + }
21950 +
21951 + }
21952 +
21953 +
21954 + /* Ok, we've done all the scanning.
21955 + * Fix up the hard link chains.
21956 + * We should now have scanned all the objects, now it's time to add these
21957 + * hardlinks.
21958 + */
21959 +
21960 + yaffs_HardlinkFixup(dev, hardList);
21961 +
21962 + /* Fix up any shadowed objects */
21963 + {
21964 + struct yaffs_ShadowFixerStruct *fixer;
21965 + yaffs_Object *obj;
21966 +
21967 + while (shadowFixerList) {
21968 + fixer = shadowFixerList;
21969 + shadowFixerList = fixer->next;
21970 + /* Complete the rename transaction by deleting the shadowed object
21971 + * then setting the object header to unshadowed.
21972 + */
21973 + obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
21974 + if (obj)
21975 + yaffs_DeleteObject(obj);
21976 +
21977 + obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
21978 +
21979 + if (obj)
21980 + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
21981 +
21982 + YFREE(fixer);
21983 + }
21984 + }
21985 +
21986 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
21987 +
21988 + if (alloc_failed)
21989 + return YAFFS_FAIL;
21990 +
21991 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
21992 +
21993 +
21994 + return YAFFS_OK;
21995 +}
21996 +
21997 diff -Nrup a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h
21998 --- a/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 02:00:00.000000000 +0200
21999 +++ b/fs/yaffs2/yaffs_yaffs1.h 2010-10-03 18:03:47.551000365 +0300
22000 @@ -0,0 +1,22 @@
22001 +/*
22002 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
22003 + *
22004 + * Copyright (C) 2002-2010 Aleph One Ltd.
22005 + * for Toby Churchill Ltd and Brightstar Engineering
22006 + *
22007 + * Created by Charles Manning <charles@aleph1.co.uk>
22008 + *
22009 + * This program is free software; you can redistribute it and/or modify
22010 + * it under the terms of the GNU Lesser General Public License version 2.1 as
22011 + * published by the Free Software Foundation.
22012 + *
22013 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
22014 + */
22015 +
22016 +#ifndef __YAFFS_YAFFS1_H__
22017 +#define __YAFFS_YAFFS1_H__
22018 +
22019 +#include "yaffs_guts.h"
22020 +int yaffs1_Scan(yaffs_Device *dev);
22021 +
22022 +#endif
22023 diff -Nrup a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c
22024 --- a/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 02:00:00.000000000 +0200
22025 +++ b/fs/yaffs2/yaffs_yaffs2.c 2010-10-03 18:03:47.536000367 +0300
22026 @@ -0,0 +1,1540 @@
22027 +/*
22028 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
22029 + *
22030 + * Copyright (C) 2002-2010 Aleph One Ltd.
22031 + * for Toby Churchill Ltd and Brightstar Engineering
22032 + *
22033 + * Created by Charles Manning <charles@aleph1.co.uk>
22034 + *
22035 + * This program is free software; you can redistribute it and/or modify
22036 + * it under the terms of the GNU General Public License version 2 as
22037 + * published by the Free Software Foundation.
22038 + */
22039 +
22040 +
22041 +#include "yaffs_guts.h"
22042 +#include "yaffs_trace.h"
22043 +#include "yaffs_yaffs2.h"
22044 +#include "yaffs_checkptrw.h"
22045 +#include "yaffs_bitmap.h"
22046 +#include "yaffs_qsort.h"
22047 +#include "yaffs_nand.h"
22048 +#include "yaffs_getblockinfo.h"
22049 +#include "yaffs_verify.h"
22050 +
22051 +/*
22052 + * Checkpoints are really no benefit on very small partitions.
22053 + *
22054 + * To save space on small partitions don't bother with checkpoints unless
22055 + * the partition is at least this big.
22056 + */
22057 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
22058 +
22059 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
22060 +
22061 +
22062 +/*
22063 + * Oldest Dirty Sequence Number handling.
22064 + */
22065 +
22066 +/* yaffs2_CalcOldestDirtySequence()
22067 + * yaffs2_FindOldestDirtySequence()
22068 + * Calculate the oldest dirty sequence number if we don't know it.
22069 + */
22070 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
22071 +{
22072 + int i;
22073 + unsigned seq;
22074 + unsigned blockNo = 0;
22075 + yaffs_BlockInfo *b;
22076 +
22077 + if(!dev->param.isYaffs2)
22078 + return;
22079 +
22080 + /* Find the oldest dirty sequence number. */
22081 + seq = dev->sequenceNumber + 1;
22082 + b = dev->blockInfo;
22083 + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
22084 + if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
22085 + (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock &&
22086 + b->sequenceNumber < seq) {
22087 + seq = b->sequenceNumber;
22088 + blockNo = i;
22089 + }
22090 + b++;
22091 + }
22092 +
22093 + if(blockNo){
22094 + dev->oldestDirtySequence = seq;
22095 + dev->oldestDirtyBlock = blockNo;
22096 + }
22097 +
22098 +}
22099 +
22100 +
22101 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
22102 +{
22103 + if(!dev->param.isYaffs2)
22104 + return;
22105 +
22106 + if(!dev->oldestDirtySequence)
22107 + yaffs2_CalcOldestDirtySequence(dev);
22108 +}
22109 +
22110 +/*
22111 + * yaffs_ClearOldestDirtySequence()
22112 + * Called when a block is erased or marked bad. (ie. when its sequenceNumber
22113 + * becomes invalid). If the value matches the oldest then we clear
22114 + * dev->oldestDirtySequence to force its recomputation.
22115 + */
22116 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
22117 +{
22118 +
22119 + if(!dev->param.isYaffs2)
22120 + return;
22121 +
22122 + if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
22123 + dev->oldestDirtySequence = 0;
22124 + dev->oldestDirtyBlock = 0;
22125 + }
22126 +}
22127 +
22128 +/*
22129 + * yaffs2_UpdateOldestDirtySequence()
22130 + * Update the oldest dirty sequence number whenever we dirty a block.
22131 + * Only do this if the oldestDirtySequence is actually being tracked.
22132 + */
22133 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
22134 +{
22135 + if(!dev->param.isYaffs2)
22136 + return;
22137 +
22138 + if(dev->oldestDirtySequence){
22139 + if(dev->oldestDirtySequence > bi->sequenceNumber){
22140 + dev->oldestDirtySequence = bi->sequenceNumber;
22141 + dev->oldestDirtyBlock = blockNo;
22142 + }
22143 + }
22144 +}
22145 +
22146 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
22147 + yaffs_BlockInfo *bi)
22148 +{
22149 +
22150 + if (!dev->param.isYaffs2)
22151 + return 1; /* disqualification only applies to yaffs2. */
22152 +
22153 + if (!bi->hasShrinkHeader)
22154 + return 1; /* can gc */
22155 +
22156 + yaffs2_FindOldestDirtySequence(dev);
22157 +
22158 + /* Can't do gc of this block if there are any blocks older than this one that have
22159 + * discarded pages.
22160 + */
22161 + return (bi->sequenceNumber <= dev->oldestDirtySequence);
22162 +}
22163 +
22164 +/*
22165 + * yaffs2_FindRefreshBlock()
22166 + * periodically finds the oldest full block by sequence number for refreshing.
22167 + * Only for yaffs2.
22168 + */
22169 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
22170 +{
22171 + __u32 b ;
22172 +
22173 + __u32 oldest = 0;
22174 + __u32 oldestSequence = 0;
22175 +
22176 + yaffs_BlockInfo *bi;
22177 +
22178 + if(!dev->param.isYaffs2)
22179 + return oldest;
22180 +
22181 + /*
22182 + * If refresh period < 10 then refreshing is disabled.
22183 + */
22184 + if(dev->param.refreshPeriod < 10)
22185 + return oldest;
22186 +
22187 + /*
22188 + * Fix broken values.
22189 + */
22190 + if(dev->refreshSkip > dev->param.refreshPeriod)
22191 + dev->refreshSkip = dev->param.refreshPeriod;
22192 +
22193 + if(dev->refreshSkip > 0)
22194 + return oldest;
22195 +
22196 + /*
22197 + * Refresh skip is now zero.
22198 + * We'll do a refresh this time around....
22199 + * Update the refresh skip and find the oldest block.
22200 + */
22201 + dev->refreshSkip = dev->param.refreshPeriod;
22202 + dev->refreshCount++;
22203 + bi = dev->blockInfo;
22204 + for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
22205 +
22206 + if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
22207 +
22208 + if(oldest < 1 ||
22209 + bi->sequenceNumber < oldestSequence){
22210 + oldest = b;
22211 + oldestSequence = bi->sequenceNumber;
22212 + }
22213 + }
22214 + bi++;
22215 + }
22216 +
22217 + if (oldest > 0) {
22218 + T(YAFFS_TRACE_GC,
22219 + (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
22220 + dev->refreshCount, oldest, oldestSequence));
22221 + }
22222 +
22223 + return oldest;
22224 +}
22225 +
22226 +int yaffs2_CheckpointRequired(yaffs_Device *dev)
22227 +{
22228 + int nblocks;
22229 +
22230 + if(!dev->param.isYaffs2)
22231 + return 0;
22232 +
22233 + nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
22234 +
22235 + return !dev->param.skipCheckpointWrite &&
22236 + !dev->readOnly &&
22237 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
22238 +}
22239 +
22240 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
22241 +{
22242 + int retval;
22243 +
22244 + if(!dev->param.isYaffs2)
22245 + return 0;
22246 +
22247 + if (!dev->nCheckpointBlocksRequired &&
22248 + yaffs2_CheckpointRequired(dev)){
22249 + /* Not a valid value so recalculate */
22250 + int nBytes = 0;
22251 + int nBlocks;
22252 + int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
22253 +
22254 + nBytes += sizeof(yaffs_CheckpointValidity);
22255 + nBytes += sizeof(yaffs_CheckpointDevice);
22256 + nBytes += devBlocks * sizeof(yaffs_BlockInfo);
22257 + nBytes += devBlocks * dev->chunkBitmapStride;
22258 + nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
22259 + nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
22260 + nBytes += sizeof(yaffs_CheckpointValidity);
22261 + nBytes += sizeof(__u32); /* checksum*/
22262 +
22263 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
22264 +
22265 + nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
22266 +
22267 + dev->nCheckpointBlocksRequired = nBlocks;
22268 + }
22269 +
22270 + retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
22271 + if(retval < 0)
22272 + retval = 0;
22273 + return retval;
22274 +}
22275 +
22276 +/*--------------------- Checkpointing --------------------*/
22277 +
22278 +
22279 +static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
22280 +{
22281 + yaffs_CheckpointValidity cp;
22282 +
22283 + memset(&cp, 0, sizeof(cp));
22284 +
22285 + cp.structType = sizeof(cp);
22286 + cp.magic = YAFFS_MAGIC;
22287 + cp.version = YAFFS_CHECKPOINT_VERSION;
22288 + cp.head = (head) ? 1 : 0;
22289 +
22290 + return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
22291 + 1 : 0;
22292 +}
22293 +
22294 +static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
22295 +{
22296 + yaffs_CheckpointValidity cp;
22297 + int ok;
22298 +
22299 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22300 +
22301 + if (ok)
22302 + ok = (cp.structType == sizeof(cp)) &&
22303 + (cp.magic == YAFFS_MAGIC) &&
22304 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
22305 + (cp.head == ((head) ? 1 : 0));
22306 + return ok ? 1 : 0;
22307 +}
22308 +
22309 +static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
22310 + yaffs_Device *dev)
22311 +{
22312 + cp->nErasedBlocks = dev->nErasedBlocks;
22313 + cp->allocationBlock = dev->allocationBlock;
22314 + cp->allocationPage = dev->allocationPage;
22315 + cp->nFreeChunks = dev->nFreeChunks;
22316 +
22317 + cp->nDeletedFiles = dev->nDeletedFiles;
22318 + cp->nUnlinkedFiles = dev->nUnlinkedFiles;
22319 + cp->nBackgroundDeletions = dev->nBackgroundDeletions;
22320 + cp->sequenceNumber = dev->sequenceNumber;
22321 +
22322 +}
22323 +
22324 +static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
22325 + yaffs_CheckpointDevice *cp)
22326 +{
22327 + dev->nErasedBlocks = cp->nErasedBlocks;
22328 + dev->allocationBlock = cp->allocationBlock;
22329 + dev->allocationPage = cp->allocationPage;
22330 + dev->nFreeChunks = cp->nFreeChunks;
22331 +
22332 + dev->nDeletedFiles = cp->nDeletedFiles;
22333 + dev->nUnlinkedFiles = cp->nUnlinkedFiles;
22334 + dev->nBackgroundDeletions = cp->nBackgroundDeletions;
22335 + dev->sequenceNumber = cp->sequenceNumber;
22336 +}
22337 +
22338 +
22339 +static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
22340 +{
22341 + yaffs_CheckpointDevice cp;
22342 + __u32 nBytes;
22343 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22344 +
22345 + int ok;
22346 +
22347 + /* Write device runtime values*/
22348 + yaffs2_DeviceToCheckpointDevice(&cp, dev);
22349 + cp.structType = sizeof(cp);
22350 +
22351 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22352 +
22353 + /* Write block info */
22354 + if (ok) {
22355 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22356 + ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
22357 + }
22358 +
22359 + /* Write chunk bits */
22360 + if (ok) {
22361 + nBytes = nBlocks * dev->chunkBitmapStride;
22362 + ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
22363 + }
22364 + return ok ? 1 : 0;
22365 +
22366 +}
22367 +
22368 +static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
22369 +{
22370 + yaffs_CheckpointDevice cp;
22371 + __u32 nBytes;
22372 + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
22373 +
22374 + int ok;
22375 +
22376 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22377 + if (!ok)
22378 + return 0;
22379 +
22380 + if (cp.structType != sizeof(cp))
22381 + return 0;
22382 +
22383 +
22384 + yaffs2_CheckpointDeviceToDevice(dev, &cp);
22385 +
22386 + nBytes = nBlocks * sizeof(yaffs_BlockInfo);
22387 +
22388 + ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
22389 +
22390 + if (!ok)
22391 + return 0;
22392 + nBytes = nBlocks * dev->chunkBitmapStride;
22393 +
22394 + ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
22395 +
22396 + return ok ? 1 : 0;
22397 +}
22398 +
22399 +static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
22400 + yaffs_Object *obj)
22401 +{
22402 +
22403 + cp->objectId = obj->objectId;
22404 + cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
22405 + cp->hdrChunk = obj->hdrChunk;
22406 + cp->variantType = obj->variantType;
22407 + cp->deleted = obj->deleted;
22408 + cp->softDeleted = obj->softDeleted;
22409 + cp->unlinked = obj->unlinked;
22410 + cp->fake = obj->fake;
22411 + cp->renameAllowed = obj->renameAllowed;
22412 + cp->unlinkAllowed = obj->unlinkAllowed;
22413 + cp->serial = obj->serial;
22414 + cp->nDataChunks = obj->nDataChunks;
22415 +
22416 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22417 + cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
22418 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22419 + cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
22420 +}
22421 +
22422 +static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
22423 +{
22424 +
22425 + yaffs_Object *parent;
22426 +
22427 + if (obj->variantType != cp->variantType) {
22428 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
22429 + TCONT("chunk %d does not match existing object type %d")
22430 + TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
22431 + obj->variantType));
22432 + return 0;
22433 + }
22434 +
22435 + obj->objectId = cp->objectId;
22436 +
22437 + if (cp->parentId)
22438 + parent = yaffs_FindOrCreateObjectByNumber(
22439 + obj->myDev,
22440 + cp->parentId,
22441 + YAFFS_OBJECT_TYPE_DIRECTORY);
22442 + else
22443 + parent = NULL;
22444 +
22445 + if (parent) {
22446 + if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
22447 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
22448 + TCONT(" chunk %d Parent type, %d, not directory")
22449 + TENDSTR),
22450 + cp->objectId, cp->parentId, cp->variantType,
22451 + cp->hdrChunk, parent->variantType));
22452 + return 0;
22453 + }
22454 + yaffs_AddObjectToDirectory(parent, obj);
22455 + }
22456 +
22457 + obj->hdrChunk = cp->hdrChunk;
22458 + obj->variantType = cp->variantType;
22459 + obj->deleted = cp->deleted;
22460 + obj->softDeleted = cp->softDeleted;
22461 + obj->unlinked = cp->unlinked;
22462 + obj->fake = cp->fake;
22463 + obj->renameAllowed = cp->renameAllowed;
22464 + obj->unlinkAllowed = cp->unlinkAllowed;
22465 + obj->serial = cp->serial;
22466 + obj->nDataChunks = cp->nDataChunks;
22467 +
22468 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22469 + obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
22470 + else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
22471 + obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
22472 +
22473 + if (obj->hdrChunk > 0)
22474 + obj->lazyLoaded = 1;
22475 + return 1;
22476 +}
22477 +
22478 +
22479 +
22480 +static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
22481 + __u32 level, int chunkOffset)
22482 +{
22483 + int i;
22484 + yaffs_Device *dev = in->myDev;
22485 + int ok = 1;
22486 +
22487 + if (tn) {
22488 + if (level > 0) {
22489 +
22490 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
22491 + if (tn->internal[i]) {
22492 + ok = yaffs2_CheckpointTnodeWorker(in,
22493 + tn->internal[i],
22494 + level - 1,
22495 + (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
22496 + }
22497 + }
22498 + } else if (level == 0) {
22499 + __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
22500 + ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
22501 + if (ok)
22502 + ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22503 + }
22504 + }
22505 +
22506 + return ok;
22507 +
22508 +}
22509 +
22510 +static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
22511 +{
22512 + __u32 endMarker = ~0;
22513 + int ok = 1;
22514 +
22515 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22516 + ok = yaffs2_CheckpointTnodeWorker(obj,
22517 + obj->variant.fileVariant.top,
22518 + obj->variant.fileVariant.topLevel,
22519 + 0);
22520 + if (ok)
22521 + ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
22522 + sizeof(endMarker));
22523 + }
22524 +
22525 + return ok ? 1 : 0;
22526 +}
22527 +
22528 +static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
22529 +{
22530 + __u32 baseChunk;
22531 + int ok = 1;
22532 + yaffs_Device *dev = obj->myDev;
22533 + yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
22534 + yaffs_Tnode *tn;
22535 + int nread = 0;
22536 +
22537 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22538 +
22539 + while (ok && (~baseChunk)) {
22540 + nread++;
22541 + /* Read level 0 tnode */
22542 +
22543 +
22544 + tn = yaffs_GetTnode(dev);
22545 + if (tn){
22546 + ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
22547 + } else
22548 + ok = 0;
22549 +
22550 + if (tn && ok)
22551 + ok = yaffs_AddOrFindLevel0Tnode(dev,
22552 + fileStructPtr,
22553 + baseChunk,
22554 + tn) ? 1 : 0;
22555 +
22556 + if (ok)
22557 + ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
22558 +
22559 + }
22560 +
22561 + T(YAFFS_TRACE_CHECKPOINT, (
22562 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
22563 + nread, baseChunk, ok));
22564 +
22565 + return ok ? 1 : 0;
22566 +}
22567 +
22568 +
22569 +static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
22570 +{
22571 + yaffs_Object *obj;
22572 + yaffs_CheckpointObject cp;
22573 + int i;
22574 + int ok = 1;
22575 + struct ylist_head *lh;
22576 +
22577 +
22578 + /* Iterate through the objects in each hash entry,
22579 + * dumping them to the checkpointing stream.
22580 + */
22581 +
22582 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
22583 + ylist_for_each(lh, &dev->objectBucket[i].list) {
22584 + if (lh) {
22585 + obj = ylist_entry(lh, yaffs_Object, hashLink);
22586 + if (!obj->deferedFree) {
22587 + yaffs2_ObjectToCheckpointObject(&cp, obj);
22588 + cp.structType = sizeof(cp);
22589 +
22590 + T(YAFFS_TRACE_CHECKPOINT, (
22591 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
22592 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
22593 +
22594 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22595 +
22596 + if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
22597 + ok = yaffs2_WriteCheckpointTnodes(obj);
22598 + }
22599 + }
22600 + }
22601 + }
22602 +
22603 + /* Dump end of list */
22604 + memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
22605 + cp.structType = sizeof(cp);
22606 +
22607 + if (ok)
22608 + ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
22609 +
22610 + return ok ? 1 : 0;
22611 +}
22612 +
22613 +static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
22614 +{
22615 + yaffs_Object *obj;
22616 + yaffs_CheckpointObject cp;
22617 + int ok = 1;
22618 + int done = 0;
22619 + yaffs_Object *hardList = NULL;
22620 +
22621 + while (ok && !done) {
22622 + ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
22623 + if (cp.structType != sizeof(cp)) {
22624 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
22625 + cp.structType, (int)sizeof(cp), ok));
22626 + ok = 0;
22627 + }
22628 +
22629 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
22630 + cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
22631 +
22632 + if (ok && cp.objectId == ~0)
22633 + done = 1;
22634 + else if (ok) {
22635 + obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
22636 + if (obj) {
22637 + ok = yaffs2_CheckpointObjectToObject(obj, &cp);
22638 + if (!ok)
22639 + break;
22640 + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
22641 + ok = yaffs2_ReadCheckpointTnodes(obj);
22642 + } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
22643 + obj->hardLinks.next =
22644 + (struct ylist_head *) hardList;
22645 + hardList = obj;
22646 + }
22647 + } else
22648 + ok = 0;
22649 + }
22650 + }
22651 +
22652 + if (ok)
22653 + yaffs_HardlinkFixup(dev, hardList);
22654 +
22655 + return ok ? 1 : 0;
22656 +}
22657 +
22658 +static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
22659 +{
22660 + __u32 checkpointSum;
22661 + int ok;
22662 +
22663 + yaffs2_GetCheckpointSum(dev, &checkpointSum);
22664 +
22665 + ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
22666 +
22667 + if (!ok)
22668 + return 0;
22669 +
22670 + return 1;
22671 +}
22672 +
22673 +static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
22674 +{
22675 + __u32 checkpointSum0;
22676 + __u32 checkpointSum1;
22677 + int ok;
22678 +
22679 + yaffs2_GetCheckpointSum(dev, &checkpointSum0);
22680 +
22681 + ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
22682 +
22683 + if (!ok)
22684 + return 0;
22685 +
22686 + if (checkpointSum0 != checkpointSum1)
22687 + return 0;
22688 +
22689 + return 1;
22690 +}
22691 +
22692 +
22693 +static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
22694 +{
22695 + int ok = 1;
22696 +
22697 + if (!yaffs2_CheckpointRequired(dev)) {
22698 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
22699 + ok = 0;
22700 + }
22701 +
22702 + if (ok)
22703 + ok = yaffs2_CheckpointOpen(dev, 1);
22704 +
22705 + if (ok) {
22706 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22707 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
22708 + }
22709 + if (ok) {
22710 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
22711 + ok = yaffs2_WriteCheckpointDevice(dev);
22712 + }
22713 + if (ok) {
22714 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
22715 + ok = yaffs2_WriteCheckpointObjects(dev);
22716 + }
22717 + if (ok) {
22718 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
22719 + ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
22720 + }
22721 +
22722 + if (ok)
22723 + ok = yaffs2_WriteCheckpointSum(dev);
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 dev->isCheckpointed;
22734 +}
22735 +
22736 +static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
22737 +{
22738 + int ok = 1;
22739 +
22740 + if(!dev->param.isYaffs2)
22741 + ok = 0;
22742 +
22743 + if (ok && dev->param.skipCheckpointRead) {
22744 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
22745 + ok = 0;
22746 + }
22747 +
22748 + if (ok)
22749 + ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
22750 +
22751 + if (ok) {
22752 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22753 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
22754 + }
22755 + if (ok) {
22756 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
22757 + ok = yaffs2_ReadCheckpointDevice(dev);
22758 + }
22759 + if (ok) {
22760 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
22761 + ok = yaffs2_ReadCheckpointObjects(dev);
22762 + }
22763 + if (ok) {
22764 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
22765 + ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
22766 + }
22767 +
22768 + if (ok) {
22769 + ok = yaffs2_ReadCheckpointSum(dev);
22770 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
22771 + }
22772 +
22773 + if (!yaffs2_CheckpointClose(dev))
22774 + ok = 0;
22775 +
22776 + if (ok)
22777 + dev->isCheckpointed = 1;
22778 + else
22779 + dev->isCheckpointed = 0;
22780 +
22781 + return ok ? 1 : 0;
22782 +
22783 +}
22784 +
22785 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
22786 +{
22787 + if (dev->isCheckpointed ||
22788 + dev->blocksInCheckpoint > 0) {
22789 + dev->isCheckpointed = 0;
22790 + yaffs2_CheckpointInvalidateStream(dev);
22791 + }
22792 + if (dev->param.markSuperBlockDirty)
22793 + dev->param.markSuperBlockDirty(dev);
22794 +}
22795 +
22796 +
22797 +int yaffs_CheckpointSave(yaffs_Device *dev)
22798 +{
22799 +
22800 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22801 +
22802 + yaffs_VerifyObjects(dev);
22803 + yaffs_VerifyBlocks(dev);
22804 + yaffs_VerifyFreeChunks(dev);
22805 +
22806 + if (!dev->isCheckpointed) {
22807 + yaffs2_InvalidateCheckpoint(dev);
22808 + yaffs2_WriteCheckpointData(dev);
22809 + }
22810 +
22811 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22812 +
22813 + return dev->isCheckpointed;
22814 +}
22815 +
22816 +int yaffs2_CheckpointRestore(yaffs_Device *dev)
22817 +{
22818 + int retval;
22819 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22820 +
22821 + retval = yaffs2_ReadCheckpointData(dev);
22822 +
22823 + if (dev->isCheckpointed) {
22824 + yaffs_VerifyObjects(dev);
22825 + yaffs_VerifyBlocks(dev);
22826 + yaffs_VerifyFreeChunks(dev);
22827 + }
22828 +
22829 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
22830 +
22831 + return retval;
22832 +}
22833 +
22834 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
22835 +{
22836 + /* if newsSize > oldFileSize.
22837 + * We're going to be writing a hole.
22838 + * If the hole is small then write zeros otherwise write a start of hole marker.
22839 + */
22840 +
22841 +
22842 + loff_t oldFileSize;
22843 + int increase;
22844 + int smallHole ;
22845 + int result = YAFFS_OK;
22846 + yaffs_Device *dev = NULL;
22847 +
22848 + __u8 *localBuffer = NULL;
22849 +
22850 + int smallIncreaseOk = 0;
22851 +
22852 + if(!obj)
22853 + return YAFFS_FAIL;
22854 +
22855 + if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
22856 + return YAFFS_FAIL;
22857 +
22858 + dev = obj->myDev;
22859 +
22860 + /* Bail out if not yaffs2 mode */
22861 + if(!dev->param.isYaffs2)
22862 + return YAFFS_OK;
22863 +
22864 + oldFileSize = obj->variant.fileVariant.fileSize;
22865 +
22866 + if (newSize <= oldFileSize)
22867 + return YAFFS_OK;
22868 +
22869 + increase = newSize - oldFileSize;
22870 +
22871 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
22872 + yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
22873 + smallHole = 1;
22874 + else
22875 + smallHole = 0;
22876 +
22877 + if(smallHole)
22878 + localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
22879 +
22880 + if(localBuffer){
22881 + /* fill hole with zero bytes */
22882 + int pos = oldFileSize;
22883 + int thisWrite;
22884 + int written;
22885 + memset(localBuffer,0,dev->nDataBytesPerChunk);
22886 + smallIncreaseOk = 1;
22887 +
22888 + while(increase > 0 && smallIncreaseOk){
22889 + thisWrite = increase;
22890 + if(thisWrite > dev->nDataBytesPerChunk)
22891 + thisWrite = dev->nDataBytesPerChunk;
22892 + written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
22893 + if(written == thisWrite){
22894 + pos += thisWrite;
22895 + increase -= thisWrite;
22896 + } else
22897 + smallIncreaseOk = 0;
22898 + }
22899 +
22900 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
22901 +
22902 + /* If we were out of space then reverse any chunks we've added */
22903 + if(!smallIncreaseOk)
22904 + yaffs_ResizeDown(obj, oldFileSize);
22905 + }
22906 +
22907 + if (!smallIncreaseOk &&
22908 + obj->parent &&
22909 + obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
22910 + obj->parent->objectId != YAFFS_OBJECTID_DELETED){
22911 + /* Write a hole start header with the old file size */
22912 + yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
22913 + }
22914 +
22915 + return result;
22916 +
22917 +}
22918 +
22919 +
22920 +typedef struct {
22921 + int seq;
22922 + int block;
22923 +} yaffs_BlockIndex;
22924 +
22925 +
22926 +static int yaffs2_ybicmp(const void *a, const void *b)
22927 +{
22928 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
22929 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
22930 + register int ablock = ((yaffs_BlockIndex *)a)->block;
22931 + register int bblock = ((yaffs_BlockIndex *)b)->block;
22932 + if (aseq == bseq)
22933 + return ablock - bblock;
22934 + else
22935 + return aseq - bseq;
22936 +}
22937 +
22938 +int yaffs2_ScanBackwards(yaffs_Device *dev)
22939 +{
22940 + yaffs_ExtendedTags tags;
22941 + int blk;
22942 + int blockIterator;
22943 + int startIterator;
22944 + int endIterator;
22945 + int nBlocksToScan = 0;
22946 +
22947 + int chunk;
22948 + int result;
22949 + int c;
22950 + int deleted;
22951 + yaffs_BlockState state;
22952 + yaffs_Object *hardList = NULL;
22953 + yaffs_BlockInfo *bi;
22954 + __u32 sequenceNumber;
22955 + yaffs_ObjectHeader *oh;
22956 + yaffs_Object *in;
22957 + yaffs_Object *parent;
22958 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
22959 + int itsUnlinked;
22960 + __u8 *chunkData;
22961 +
22962 + int fileSize;
22963 + int isShrink;
22964 + int foundChunksInBlock;
22965 + int equivalentObjectId;
22966 + int alloc_failed = 0;
22967 +
22968 +
22969 + yaffs_BlockIndex *blockIndex = NULL;
22970 + int altBlockIndex = 0;
22971 +
22972 + T(YAFFS_TRACE_SCAN,
22973 + (TSTR
22974 + ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
22975 + TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
22976 +
22977 +
22978 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
22979 +
22980 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
22981 +
22982 + if (!blockIndex) {
22983 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
22984 + altBlockIndex = 1;
22985 + }
22986 +
22987 + if (!blockIndex) {
22988 + T(YAFFS_TRACE_SCAN,
22989 + (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
22990 + return YAFFS_FAIL;
22991 + }
22992 +
22993 + dev->blocksInCheckpoint = 0;
22994 +
22995 + chunkData = yaffs_GetTempBuffer(dev, __LINE__);
22996 +
22997 + /* Scan all the blocks to determine their state */
22998 + bi = dev->blockInfo;
22999 + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
23000 + yaffs_ClearChunkBits(dev, blk);
23001 + bi->pagesInUse = 0;
23002 + bi->softDeletions = 0;
23003 +
23004 + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
23005 +
23006 + bi->blockState = state;
23007 + bi->sequenceNumber = sequenceNumber;
23008 +
23009 + if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
23010 + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
23011 + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
23012 + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
23013 +
23014 + T(YAFFS_TRACE_SCAN_DEBUG,
23015 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
23016 + state, sequenceNumber));
23017 +
23018 +
23019 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
23020 + dev->blocksInCheckpoint++;
23021 +
23022 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
23023 + T(YAFFS_TRACE_BAD_BLOCKS,
23024 + (TSTR("block %d is bad" TENDSTR), blk));
23025 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
23026 + T(YAFFS_TRACE_SCAN_DEBUG,
23027 + (TSTR("Block empty " TENDSTR)));
23028 + dev->nErasedBlocks++;
23029 + dev->nFreeChunks += dev->param.nChunksPerBlock;
23030 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
23031 +
23032 + /* Determine the highest sequence number */
23033 + if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
23034 + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
23035 +
23036 + blockIndex[nBlocksToScan].seq = sequenceNumber;
23037 + blockIndex[nBlocksToScan].block = blk;
23038 +
23039 + nBlocksToScan++;
23040 +
23041 + if (sequenceNumber >= dev->sequenceNumber)
23042 + dev->sequenceNumber = sequenceNumber;
23043 + } else {
23044 + /* TODO: Nasty sequence number! */
23045 + T(YAFFS_TRACE_SCAN,
23046 + (TSTR
23047 + ("Block scanning block %d has bad sequence number %d"
23048 + TENDSTR), blk, sequenceNumber));
23049 +
23050 + }
23051 + }
23052 + bi++;
23053 + }
23054 +
23055 + T(YAFFS_TRACE_SCAN,
23056 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
23057 +
23058 +
23059 +
23060 + YYIELD();
23061 +
23062 + /* Sort the blocks by sequence number*/
23063 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
23064 +
23065 + YYIELD();
23066 +
23067 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
23068 +
23069 + /* Now scan the blocks looking at the data. */
23070 + startIterator = 0;
23071 + endIterator = nBlocksToScan - 1;
23072 + T(YAFFS_TRACE_SCAN_DEBUG,
23073 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
23074 +
23075 + /* For each block.... backwards */
23076 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
23077 + blockIterator--) {
23078 + /* Cooperative multitasking! This loop can run for so
23079 + long that watchdog timers expire. */
23080 + YYIELD();
23081 +
23082 + /* get the block to scan in the correct order */
23083 + blk = blockIndex[blockIterator].block;
23084 +
23085 + bi = yaffs_GetBlockInfo(dev, blk);
23086 +
23087 +
23088 + state = bi->blockState;
23089 +
23090 + deleted = 0;
23091 +
23092 + /* For each chunk in each block that needs scanning.... */
23093 + foundChunksInBlock = 0;
23094 + for (c = dev->param.nChunksPerBlock - 1;
23095 + !alloc_failed && c >= 0 &&
23096 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23097 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
23098 + /* Scan backwards...
23099 + * Read the tags and decide what to do
23100 + */
23101 +
23102 + chunk = blk * dev->param.nChunksPerBlock + c;
23103 +
23104 + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
23105 + &tags);
23106 +
23107 + /* Let's have a good look at this chunk... */
23108 +
23109 + if (!tags.chunkUsed) {
23110 + /* An unassigned chunk in the block.
23111 + * If there are used chunks after this one, then
23112 + * it is a chunk that was skipped due to failing the erased
23113 + * check. Just skip it so that it can be deleted.
23114 + * But, more typically, We get here when this is an unallocated
23115 + * chunk and his means that either the block is empty or
23116 + * this is the one being allocated from
23117 + */
23118 +
23119 + if (foundChunksInBlock) {
23120 + /* This is a chunk that was skipped due to failing the erased check */
23121 + } else if (c == 0) {
23122 + /* We're looking at the first chunk in the block so the block is unused */
23123 + state = YAFFS_BLOCK_STATE_EMPTY;
23124 + dev->nErasedBlocks++;
23125 + } else {
23126 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
23127 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
23128 + if (dev->sequenceNumber == bi->sequenceNumber) {
23129 + /* this is the block being allocated from */
23130 +
23131 + T(YAFFS_TRACE_SCAN,
23132 + (TSTR
23133 + (" Allocating from %d %d"
23134 + TENDSTR), blk, c));
23135 +
23136 + state = YAFFS_BLOCK_STATE_ALLOCATING;
23137 + dev->allocationBlock = blk;
23138 + dev->allocationPage = c;
23139 + dev->allocationBlockFinder = blk;
23140 + } else {
23141 + /* This is a partially written block that is not
23142 + * the current allocation block.
23143 + */
23144 +
23145 + T(YAFFS_TRACE_SCAN,
23146 + (TSTR("Partially written block %d detected" TENDSTR),
23147 + blk));
23148 + }
23149 + }
23150 + }
23151 +
23152 + dev->nFreeChunks++;
23153 +
23154 + } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
23155 + T(YAFFS_TRACE_SCAN,
23156 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
23157 + blk, c));
23158 +
23159 + dev->nFreeChunks++;
23160 +
23161 + } else if (tags.objectId > YAFFS_MAX_OBJECT_ID ||
23162 + tags.chunkId > YAFFS_MAX_CHUNK_ID ||
23163 + (tags.chunkId > 0 && tags.byteCount > dev->nDataBytesPerChunk) ||
23164 + tags.sequenceNumber != bi->sequenceNumber ) {
23165 + T(YAFFS_TRACE_SCAN,
23166 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunkId = %d, byteCount = %d, ignored"TENDSTR),
23167 + blk, c,tags.objectId, tags.chunkId, tags.byteCount));
23168 +
23169 + dev->nFreeChunks++;
23170 +
23171 + } else if (tags.chunkId > 0) {
23172 + /* chunkId > 0 so it is a data chunk... */
23173 + unsigned int endpos;
23174 + __u32 chunkBase =
23175 + (tags.chunkId - 1) * dev->nDataBytesPerChunk;
23176 +
23177 + foundChunksInBlock = 1;
23178 +
23179 +
23180 + yaffs_SetChunkBit(dev, blk, c);
23181 + bi->pagesInUse++;
23182 +
23183 + in = yaffs_FindOrCreateObjectByNumber(dev,
23184 + tags.
23185 + objectId,
23186 + YAFFS_OBJECT_TYPE_FILE);
23187 + if (!in) {
23188 + /* Out of memory */
23189 + alloc_failed = 1;
23190 + }
23191 +
23192 + if (in &&
23193 + in->variantType == YAFFS_OBJECT_TYPE_FILE
23194 + && chunkBase < in->variant.fileVariant.shrinkSize) {
23195 + /* This has not been invalidated by a resize */
23196 + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
23197 + alloc_failed = 1;
23198 + }
23199 +
23200 + /* File size is calculated by looking at the data chunks if we have not
23201 + * seen an object header yet. Stop this practice once we find an object header.
23202 + */
23203 + endpos = chunkBase + tags.byteCount;
23204 +
23205 + if (!in->valid && /* have not got an object header yet */
23206 + in->variant.fileVariant.scannedFileSize < endpos) {
23207 + in->variant.fileVariant.scannedFileSize = endpos;
23208 + in->variant.fileVariant.fileSize = endpos;
23209 + }
23210 +
23211 + } else if (in) {
23212 + /* This chunk has been invalidated by a resize, or a past file deletion
23213 + * so delete the chunk*/
23214 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23215 +
23216 + }
23217 + } else {
23218 + /* chunkId == 0, so it is an ObjectHeader.
23219 + * Thus, we read in the object header and make the object
23220 + */
23221 + foundChunksInBlock = 1;
23222 +
23223 + yaffs_SetChunkBit(dev, blk, c);
23224 + bi->pagesInUse++;
23225 +
23226 + oh = NULL;
23227 + in = NULL;
23228 +
23229 + if (tags.extraHeaderInfoAvailable) {
23230 + in = yaffs_FindOrCreateObjectByNumber(dev,
23231 + tags.objectId,
23232 + tags.extraObjectType);
23233 + if (!in)
23234 + alloc_failed = 1;
23235 + }
23236 +
23237 + if (!in ||
23238 + (!in->valid && dev->param.disableLazyLoad) ||
23239 + tags.extraShadows ||
23240 + (!in->valid &&
23241 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23242 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
23243 +
23244 + /* If we don't have valid info then we need to read the chunk
23245 + * TODO In future we can probably defer reading the chunk and
23246 + * living with invalid data until needed.
23247 + */
23248 +
23249 + result = yaffs_ReadChunkWithTagsFromNAND(dev,
23250 + chunk,
23251 + chunkData,
23252 + NULL);
23253 +
23254 + oh = (yaffs_ObjectHeader *) chunkData;
23255 +
23256 + if (dev->param.inbandTags) {
23257 + /* Fix up the header if they got corrupted by inband tags */
23258 + oh->shadowsObject = oh->inbandShadowsObject;
23259 + oh->isShrink = oh->inbandIsShrink;
23260 + }
23261 +
23262 + if (!in) {
23263 + in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
23264 + if (!in)
23265 + alloc_failed = 1;
23266 + }
23267 +
23268 + }
23269 +
23270 + if (!in) {
23271 + /* TODO Hoosterman we have a problem! */
23272 + T(YAFFS_TRACE_ERROR,
23273 + (TSTR
23274 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
23275 + TENDSTR), tags.objectId, chunk));
23276 + continue;
23277 + }
23278 +
23279 + if (in->valid) {
23280 + /* We have already filled this one.
23281 + * We have a duplicate that will be discarded, but
23282 + * we first have to suck out resize info if it is a file.
23283 + */
23284 +
23285 + if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
23286 + ((oh &&
23287 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
23288 + (tags.extraHeaderInfoAvailable &&
23289 + tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
23290 + __u32 thisSize =
23291 + (oh) ? oh->fileSize : tags.
23292 + extraFileLength;
23293 + __u32 parentObjectId =
23294 + (oh) ? oh->
23295 + parentObjectId : tags.
23296 + extraParentObjectId;
23297 +
23298 +
23299 + isShrink =
23300 + (oh) ? oh->isShrink : tags.
23301 + extraIsShrinkHeader;
23302 +
23303 + /* If it is deleted (unlinked at start also means deleted)
23304 + * we treat the file size as being zeroed at this point.
23305 + */
23306 + if (parentObjectId ==
23307 + YAFFS_OBJECTID_DELETED
23308 + || parentObjectId ==
23309 + YAFFS_OBJECTID_UNLINKED) {
23310 + thisSize = 0;
23311 + isShrink = 1;
23312 + }
23313 +
23314 + if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
23315 + in->variant.fileVariant.shrinkSize = thisSize;
23316 +
23317 + if (isShrink)
23318 + bi->hasShrinkHeader = 1;
23319 +
23320 + }
23321 + /* Use existing - destroy this one. */
23322 + yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
23323 +
23324 + }
23325 +
23326 + if (!in->valid && in->variantType !=
23327 + (oh ? oh->type : tags.extraObjectType))
23328 + T(YAFFS_TRACE_ERROR, (
23329 + TSTR("yaffs tragedy: Bad object type, "
23330 + TCONT("%d != %d, for object %d at chunk ")
23331 + TCONT("%d during scan")
23332 + TENDSTR), oh ?
23333 + oh->type : tags.extraObjectType,
23334 + in->variantType, tags.objectId,
23335 + chunk));
23336 +
23337 + if (!in->valid &&
23338 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
23339 + tags.objectId ==
23340 + YAFFS_OBJECTID_LOSTNFOUND)) {
23341 + /* We only load some info, don't fiddle with directory structure */
23342 + in->valid = 1;
23343 +
23344 + if (oh) {
23345 +
23346 + in->yst_mode = oh->yst_mode;
23347 +#ifdef CONFIG_YAFFS_WINCE
23348 + in->win_atime[0] = oh->win_atime[0];
23349 + in->win_ctime[0] = oh->win_ctime[0];
23350 + in->win_mtime[0] = oh->win_mtime[0];
23351 + in->win_atime[1] = oh->win_atime[1];
23352 + in->win_ctime[1] = oh->win_ctime[1];
23353 + in->win_mtime[1] = oh->win_mtime[1];
23354 +#else
23355 + in->yst_uid = oh->yst_uid;
23356 + in->yst_gid = oh->yst_gid;
23357 + in->yst_atime = oh->yst_atime;
23358 + in->yst_mtime = oh->yst_mtime;
23359 + in->yst_ctime = oh->yst_ctime;
23360 + in->yst_rdev = oh->yst_rdev;
23361 +
23362 + in->lazyLoaded = 0;
23363 +
23364 +#endif
23365 + } else
23366 + in->lazyLoaded = 1;
23367 +
23368 + in->hdrChunk = chunk;
23369 +
23370 + } else if (!in->valid) {
23371 + /* we need to load this info */
23372 +
23373 + in->valid = 1;
23374 + in->hdrChunk = chunk;
23375 +
23376 + if (oh) {
23377 + in->variantType = oh->type;
23378 +
23379 + in->yst_mode = oh->yst_mode;
23380 +#ifdef CONFIG_YAFFS_WINCE
23381 + in->win_atime[0] = oh->win_atime[0];
23382 + in->win_ctime[0] = oh->win_ctime[0];
23383 + in->win_mtime[0] = oh->win_mtime[0];
23384 + in->win_atime[1] = oh->win_atime[1];
23385 + in->win_ctime[1] = oh->win_ctime[1];
23386 + in->win_mtime[1] = oh->win_mtime[1];
23387 +#else
23388 + in->yst_uid = oh->yst_uid;
23389 + in->yst_gid = oh->yst_gid;
23390 + in->yst_atime = oh->yst_atime;
23391 + in->yst_mtime = oh->yst_mtime;
23392 + in->yst_ctime = oh->yst_ctime;
23393 + in->yst_rdev = oh->yst_rdev;
23394 +#endif
23395 +
23396 + if (oh->shadowsObject > 0)
23397 + yaffs_HandleShadowedObject(dev,
23398 + oh->
23399 + shadowsObject,
23400 + 1);
23401 +
23402 +
23403 +
23404 + yaffs_SetObjectNameFromOH(in, oh);
23405 + parent =
23406 + yaffs_FindOrCreateObjectByNumber
23407 + (dev, oh->parentObjectId,
23408 + YAFFS_OBJECT_TYPE_DIRECTORY);
23409 +
23410 + fileSize = oh->fileSize;
23411 + isShrink = oh->isShrink;
23412 + equivalentObjectId = oh->equivalentObjectId;
23413 +
23414 + } else {
23415 + in->variantType = tags.extraObjectType;
23416 + parent =
23417 + yaffs_FindOrCreateObjectByNumber
23418 + (dev, tags.extraParentObjectId,
23419 + YAFFS_OBJECT_TYPE_DIRECTORY);
23420 + fileSize = tags.extraFileLength;
23421 + isShrink = tags.extraIsShrinkHeader;
23422 + equivalentObjectId = tags.extraEquivalentObjectId;
23423 + in->lazyLoaded = 1;
23424 +
23425 + }
23426 + in->dirty = 0;
23427 +
23428 + if (!parent)
23429 + alloc_failed = 1;
23430 +
23431 + /* directory stuff...
23432 + * hook up to parent
23433 + */
23434 +
23435 + if (parent && parent->variantType ==
23436 + YAFFS_OBJECT_TYPE_UNKNOWN) {
23437 + /* Set up as a directory */
23438 + parent->variantType =
23439 + YAFFS_OBJECT_TYPE_DIRECTORY;
23440 + YINIT_LIST_HEAD(&parent->variant.
23441 + directoryVariant.
23442 + children);
23443 + } else if (!parent || parent->variantType !=
23444 + YAFFS_OBJECT_TYPE_DIRECTORY) {
23445 + /* Hoosterman, another problem....
23446 + * We're trying to use a non-directory as a directory
23447 + */
23448 +
23449 + T(YAFFS_TRACE_ERROR,
23450 + (TSTR
23451 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
23452 + TENDSTR)));
23453 + parent = dev->lostNFoundDir;
23454 + }
23455 +
23456 + yaffs_AddObjectToDirectory(parent, in);
23457 +
23458 + itsUnlinked = (parent == dev->deletedDir) ||
23459 + (parent == dev->unlinkedDir);
23460 +
23461 + if (isShrink) {
23462 + /* Mark the block as having a shrinkHeader */
23463 + bi->hasShrinkHeader = 1;
23464 + }
23465 +
23466 + /* Note re hardlinks.
23467 + * Since we might scan a hardlink before its equivalent object is scanned
23468 + * we put them all in a list.
23469 + * After scanning is complete, we should have all the objects, so we run
23470 + * through this list and fix up all the chains.
23471 + */
23472 +
23473 + switch (in->variantType) {
23474 + case YAFFS_OBJECT_TYPE_UNKNOWN:
23475 + /* Todo got a problem */
23476 + break;
23477 + case YAFFS_OBJECT_TYPE_FILE:
23478 +
23479 + if (in->variant.fileVariant.
23480 + scannedFileSize < fileSize) {
23481 + /* This covers the case where the file size is greater
23482 + * than where the data is
23483 + * This will happen if the file is resized to be larger
23484 + * than its current data extents.
23485 + */
23486 + in->variant.fileVariant.fileSize = fileSize;
23487 + in->variant.fileVariant.scannedFileSize = fileSize;
23488 + }
23489 +
23490 + if (in->variant.fileVariant.shrinkSize > fileSize)
23491 + in->variant.fileVariant.shrinkSize = fileSize;
23492 +
23493 +
23494 + break;
23495 + case YAFFS_OBJECT_TYPE_HARDLINK:
23496 + if (!itsUnlinked) {
23497 + in->variant.hardLinkVariant.equivalentObjectId =
23498 + equivalentObjectId;
23499 + in->hardLinks.next =
23500 + (struct ylist_head *) hardList;
23501 + hardList = in;
23502 + }
23503 + break;
23504 + case YAFFS_OBJECT_TYPE_DIRECTORY:
23505 + /* Do nothing */
23506 + break;
23507 + case YAFFS_OBJECT_TYPE_SPECIAL:
23508 + /* Do nothing */
23509 + break;
23510 + case YAFFS_OBJECT_TYPE_SYMLINK:
23511 + if (oh) {
23512 + in->variant.symLinkVariant.alias =
23513 + yaffs_CloneString(oh->alias);
23514 + if (!in->variant.symLinkVariant.alias)
23515 + alloc_failed = 1;
23516 + }
23517 + break;
23518 + }
23519 +
23520 + }
23521 +
23522 + }
23523 +
23524 + } /* End of scanning for each chunk */
23525 +
23526 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
23527 + /* If we got this far while scanning, then the block is fully allocated. */
23528 + state = YAFFS_BLOCK_STATE_FULL;
23529 + }
23530 +
23531 +
23532 + bi->blockState = state;
23533 +
23534 + /* Now let's see if it was dirty */
23535 + if (bi->pagesInUse == 0 &&
23536 + !bi->hasShrinkHeader &&
23537 + bi->blockState == YAFFS_BLOCK_STATE_FULL) {
23538 + yaffs_BlockBecameDirty(dev, blk);
23539 + }
23540 +
23541 + }
23542 +
23543 + yaffs_SkipRestOfBlock(dev);
23544 +
23545 + if (altBlockIndex)
23546 + YFREE_ALT(blockIndex);
23547 + else
23548 + YFREE(blockIndex);
23549 +
23550 + /* Ok, we've done all the scanning.
23551 + * Fix up the hard link chains.
23552 + * We should now have scanned all the objects, now it's time to add these
23553 + * hardlinks.
23554 + */
23555 + yaffs_HardlinkFixup(dev, hardList);
23556 +
23557 +
23558 + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
23559 +
23560 + if (alloc_failed)
23561 + return YAFFS_FAIL;
23562 +
23563 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
23564 +
23565 + return YAFFS_OK;
23566 +}
23567 diff -Nrup a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h
23568 --- a/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 02:00:00.000000000 +0200
23569 +++ b/fs/yaffs2/yaffs_yaffs2.h 2010-10-03 18:03:47.552000367 +0300
23570 @@ -0,0 +1,36 @@
23571 +/*
23572 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
23573 + *
23574 + * Copyright (C) 2002-2010 Aleph One Ltd.
23575 + * for Toby Churchill Ltd and Brightstar Engineering
23576 + *
23577 + * Created by Charles Manning <charles@aleph1.co.uk>
23578 + *
23579 + * This program is free software; you can redistribute it and/or modify
23580 + * it under the terms of the GNU General Public License version 2 as
23581 + * published by the Free Software Foundation.
23582 + */
23583 +
23584 +#ifndef __YAFFS_YAFFS2_H__
23585 +#define __YAFFS_YAFFS2_H__
23586 +
23587 +#include "yaffs_guts.h"
23588 +
23589 +void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev);
23590 +void yaffs2_FindOldestDirtySequence(yaffs_Device *dev);
23591 +void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi);
23592 +void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi);
23593 +int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi);
23594 +__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev);
23595 +int yaffs2_CheckpointRequired(yaffs_Device *dev);
23596 +int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev);
23597 +
23598 +
23599 +void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
23600 +int yaffs2_CheckpointSave(yaffs_Device *dev);
23601 +int yaffs2_CheckpointRestore(yaffs_Device *dev);
23602 +
23603 +int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
23604 +int yaffs2_ScanBackwards(yaffs_Device *dev);
23605 +
23606 +#endif
23607 diff -Nrup a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h
23608 --- a/fs/yaffs2/yportenv.h 2010-10-03 17:48:22.725000364 +0300
23609 +++ b/fs/yaffs2/yportenv.h 2010-10-03 18:03:47.555000363 +0300
23610 @@ -1,7 +1,7 @@
23611 /*
23612 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
23613 *
23614 - * Copyright (C) 2002-2007 Aleph One Ltd.
23615 + * Copyright (C) 2002-2010 Aleph One Ltd.
23616 * for Toby Churchill Ltd and Brightstar Engineering
23617 *
23618 * Created by Charles Manning <charles@aleph1.co.uk>
23619 @@ -41,12 +41,14 @@
23620 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
23621 #include <linux/config.h>
23622 #endif
23623 +
23624 #include <linux/kernel.h>
23625 #include <linux/mm.h>
23626 #include <linux/sched.h>
23627 #include <linux/string.h>
23628 #include <linux/slab.h>
23629 #include <linux/vmalloc.h>
23630 +#include <linux/xattr.h>
23631
23632 #define YCHAR char
23633 #define YUCHAR unsigned char
23634 @@ -55,11 +57,11 @@
23635 #define yaffs_strcpy(a, b) strcpy(a, b)
23636 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23637 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
23638 -#define yaffs_strlen(s) strlen(s)
23639 +#define yaffs_strnlen(s,m) strnlen(s,m)
23640 #define yaffs_sprintf sprintf
23641 #define yaffs_toupper(a) toupper(a)
23642
23643 -#define Y_INLINE inline
23644 +#define Y_INLINE __inline__
23645
23646 #define YAFFS_LOSTNFOUND_NAME "lost+found"
23647 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23648 @@ -71,11 +73,11 @@
23649 #define YFREE_ALT(x) vfree(x)
23650 #define YMALLOC_DMA(x) YMALLOC(x)
23651
23652 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
23653 #define YYIELD() schedule()
23654 +#define Y_DUMP_STACK() dump_stack()
23655
23656 -#define YAFFS_ROOT_MODE 0666
23657 -#define YAFFS_LOSTNFOUND_MODE 0666
23658 +#define YAFFS_ROOT_MODE 0755
23659 +#define YAFFS_LOSTNFOUND_MODE 0700
23660
23661 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23662 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
23663 @@ -89,15 +91,10 @@
23664 #define yaffs_strcmp(a, b) strcmp(a, b)
23665
23666 #define TENDSTR "\n"
23667 -#define TSTR(x) KERN_WARNING x
23668 +#define TSTR(x) KERN_DEBUG x
23669 #define TCONT(x) x
23670 #define TOUT(p) printk p
23671
23672 -#define yaffs_trace(mask, fmt, args...) \
23673 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
23674 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
23675 - } while (0)
23676 -
23677 #define compile_time_assertion(assertion) \
23678 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
23679
23680 @@ -116,7 +113,6 @@
23681 #include "stdio.h"
23682 #include "string.h"
23683
23684 -#include "devextras.h"
23685
23686 #define YMALLOC(x) malloc(x)
23687 #define YFREE(x) free(x)
23688 @@ -129,7 +125,7 @@
23689 #define yaffs_strcat(a, b) strcat(a, b)
23690 #define yaffs_strcpy(a, b) strcpy(a, b)
23691 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
23692 -#define yaffs_strlen(s) strlen(s)
23693 +#define yaffs_strnlen(s,m) strnlen(s,m)
23694 #define yaffs_sprintf sprintf
23695 #define yaffs_toupper(a) toupper(a)
23696
23697 @@ -146,8 +142,8 @@
23698 #define YAFFS_LOSTNFOUND_PREFIX "obj"
23699 /* #define YPRINTF(x) printf x */
23700
23701 -#define YAFFS_ROOT_MODE 0666
23702 -#define YAFFS_LOSTNFOUND_MODE 0666
23703 +#define YAFFS_ROOT_MODE 0755
23704 +#define YAFFS_LOSTNFOUND_MODE 0700
23705
23706 #define yaffs_SumCompare(x, y) ((x) == (y))
23707 #define yaffs_strcmp(a, b) strcmp(a, b)
23708 @@ -158,46 +154,180 @@
23709
23710 #endif
23711
23712 -/* see yaffs_fs.c */
23713 -extern unsigned int yaffs_traceMask;
23714 -extern unsigned int yaffs_wr_attempts;
23715 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
23716
23717 -/*
23718 - * Tracing flags.
23719 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
23720 - */
23721 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
23722 +
23723 +#ifndef O_RDONLY
23724 +#define O_RDONLY 00
23725 +#endif
23726 +
23727 +#ifndef O_WRONLY
23728 +#define O_WRONLY 01
23729 +#endif
23730 +
23731 +#ifndef O_RDWR
23732 +#define O_RDWR 02
23733 +#endif
23734 +
23735 +#ifndef O_CREAT
23736 +#define O_CREAT 0100
23737 +#endif
23738 +
23739 +#ifndef O_EXCL
23740 +#define O_EXCL 0200
23741 +#endif
23742 +
23743 +#ifndef O_TRUNC
23744 +#define O_TRUNC 01000
23745 +#endif
23746 +
23747 +#ifndef O_APPEND
23748 +#define O_APPEND 02000
23749 +#endif
23750 +
23751 +#ifndef SEEK_SET
23752 +#define SEEK_SET 0
23753 +#endif
23754 +
23755 +#ifndef SEEK_CUR
23756 +#define SEEK_CUR 1
23757 +#endif
23758 +
23759 +#ifndef SEEK_END
23760 +#define SEEK_END 2
23761 +#endif
23762 +
23763 +#ifndef EBUSY
23764 +#define EBUSY 16
23765 +#endif
23766 +
23767 +#ifndef ENODEV
23768 +#define ENODEV 19
23769 +#endif
23770 +
23771 +#ifndef EINVAL
23772 +#define EINVAL 22
23773 +#endif
23774 +
23775 +#ifndef EBADF
23776 +#define EBADF 9
23777 +#endif
23778 +
23779 +#ifndef EACCES
23780 +#define EACCES 13
23781 +#endif
23782 +
23783 +#ifndef EXDEV
23784 +#define EXDEV 18
23785 +#endif
23786 +
23787 +#ifndef ENOENT
23788 +#define ENOENT 2
23789 +#endif
23790 +
23791 +#ifndef ENOSPC
23792 +#define ENOSPC 28
23793 +#endif
23794 +
23795 +#ifndef ERANGE
23796 +#define ERANGE 34
23797 +#endif
23798 +
23799 +#ifndef ENODATA
23800 +#define ENODATA 61
23801 +#endif
23802 +
23803 +#ifndef ENOTEMPTY
23804 +#define ENOTEMPTY 39
23805 +#endif
23806 +
23807 +#ifndef ENAMETOOLONG
23808 +#define ENAMETOOLONG 36
23809 +#endif
23810 +
23811 +#ifndef ENOMEM
23812 +#define ENOMEM 12
23813 +#endif
23814 +
23815 +#ifndef EEXIST
23816 +#define EEXIST 17
23817 +#endif
23818 +
23819 +#ifndef ENOTDIR
23820 +#define ENOTDIR 20
23821 +#endif
23822 +
23823 +#ifndef EISDIR
23824 +#define EISDIR 21
23825 +#endif
23826 +
23827 +
23828 +// Mode flags
23829 +
23830 +#ifndef S_IFMT
23831 +#define S_IFMT 0170000
23832 +#endif
23833 +
23834 +#ifndef S_IFLNK
23835 +#define S_IFLNK 0120000
23836 +#endif
23837
23838 -#define YAFFS_TRACE_OS 0x00000002
23839 -#define YAFFS_TRACE_ALLOCATE 0x00000004
23840 -#define YAFFS_TRACE_SCAN 0x00000008
23841 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
23842 -#define YAFFS_TRACE_ERASE 0x00000020
23843 -#define YAFFS_TRACE_GC 0x00000040
23844 -#define YAFFS_TRACE_WRITE 0x00000080
23845 -#define YAFFS_TRACE_TRACING 0x00000100
23846 -#define YAFFS_TRACE_DELETION 0x00000200
23847 -#define YAFFS_TRACE_BUFFERS 0x00000400
23848 -#define YAFFS_TRACE_NANDACCESS 0x00000800
23849 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
23850 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
23851 -#define YAFFS_TRACE_MTD 0x00004000
23852 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
23853 -
23854 -#define YAFFS_TRACE_VERIFY 0x00010000
23855 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
23856 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
23857 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
23858 -
23859 -
23860 -#define YAFFS_TRACE_ERROR 0x40000000
23861 -#define YAFFS_TRACE_BUG 0x80000000
23862 -#define YAFFS_TRACE_ALWAYS 0xF0000000
23863 +#ifndef S_IFDIR
23864 +#define S_IFDIR 0040000
23865 +#endif
23866 +
23867 +#ifndef S_IFREG
23868 +#define S_IFREG 0100000
23869 +#endif
23870
23871 +#ifndef S_IREAD
23872 +#define S_IREAD 0000400
23873 +#endif
23874 +
23875 +#ifndef S_IWRITE
23876 +#define S_IWRITE 0000200
23877 +#endif
23878
23879 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
23880 +#ifndef S_IEXEC
23881 +#define S_IEXEC 0000100
23882 +#endif
23883 +
23884 +#ifndef XATTR_CREATE
23885 +#define XATTR_CREATE 1
23886 +#endif
23887 +
23888 +#ifndef XATTR_REPLACE
23889 +#define XATTR_REPLACE 2
23890 +#endif
23891 +
23892 +#ifndef R_OK
23893 +#define R_OK 4
23894 +#define W_OK 2
23895 +#define X_OK 1
23896 +#define F_OK 0
23897 +#endif
23898 +
23899 +#else
23900 +#include <errno.h>
23901 +#include <sys/stat.h>
23902 +#include <fcntl.h>
23903 +#endif
23904 +
23905 +#endif
23906 +
23907 +#ifndef Y_DUMP_STACK
23908 +#define Y_DUMP_STACK() do { } while (0)
23909 +#endif
23910
23911 #ifndef YBUG
23912 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
23913 +#define YBUG() do {\
23914 + T(YAFFS_TRACE_BUG,\
23915 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
23916 + __LINE__));\
23917 + Y_DUMP_STACK();\
23918 +} while (0)
23919 #endif
23920
23921 +
23922 #endif