refresh 2.6.37 patches
[openwrt/openwrt.git] / target / linux / generic / patches-2.6.37 / 511-yaffs-git-2010-10-20.patch
1 --- a/fs/Kconfig
2 +++ b/fs/Kconfig
3 @@ -44,7 +44,6 @@ source "fs/gfs2/Kconfig"
4 source "fs/ocfs2/Kconfig"
5 source "fs/btrfs/Kconfig"
6 source "fs/nilfs2/Kconfig"
7 -source "fs/yaffs2/Kconfig"
8
9 endif # BLOCK
10
11 @@ -177,6 +176,10 @@ source "fs/hfsplus/Kconfig"
12 source "fs/befs/Kconfig"
13 source "fs/bfs/Kconfig"
14 source "fs/efs/Kconfig"
15 +
16 +# Patched by YAFFS
17 +source "fs/yaffs2/Kconfig"
18 +
19 source "fs/jffs2/Kconfig"
20 # UBIFS File system configuration
21 source "fs/ubifs/Kconfig"
22 --- a/fs/Makefile
23 +++ b/fs/Makefile
24 @@ -122,5 +122,6 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/
25 obj-$(CONFIG_GFS2_FS) += gfs2/
26 obj-$(CONFIG_EXOFS_FS) += exofs/
27 obj-$(CONFIG_CEPH_FS) += ceph/
28 -obj-$(CONFIG_YAFFS_FS) += yaffs2/
29
30 +# Patched by YAFFS
31 +obj-$(CONFIG_YAFFS_FS) += yaffs2/
32 --- a/fs/yaffs2/devextras.h
33 +++ b/fs/yaffs2/devextras.h
34 @@ -1,7 +1,7 @@
35 /*
36 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
37 *
38 - * Copyright (C) 2002-2007 Aleph One Ltd.
39 + * Copyright (C) 2002-2010 Aleph One Ltd.
40 * for Toby Churchill Ltd and Brightstar Engineering
41 *
42 * Created by Charles Manning <charles@aleph1.co.uk>
43 @@ -24,6 +24,8 @@
44 #define __EXTRAS_H__
45
46
47 +#include "yportenv.h"
48 +
49 #if !(defined __KERNEL__)
50
51 /* Definition of types */
52 @@ -33,103 +35,6 @@ typedef unsigned __u32;
53
54 #endif
55
56 -/*
57 - * This is a simple doubly linked list implementation that matches the
58 - * way the Linux kernel doubly linked list implementation works.
59 - */
60 -
61 -struct ylist_head {
62 - struct ylist_head *next; /* next in chain */
63 - struct ylist_head *prev; /* previous in chain */
64 -};
65 -
66 -
67 -/* Initialise a static list */
68 -#define YLIST_HEAD(name) \
69 -struct ylist_head name = { &(name), &(name)}
70 -
71 -
72 -
73 -/* Initialise a list head to an empty list */
74 -#define YINIT_LIST_HEAD(p) \
75 -do { \
76 - (p)->next = (p);\
77 - (p)->prev = (p); \
78 -} while (0)
79 -
80 -
81 -/* Add an element to a list */
82 -static __inline__ void ylist_add(struct ylist_head *newEntry,
83 - struct ylist_head *list)
84 -{
85 - struct ylist_head *listNext = list->next;
86 -
87 - list->next = newEntry;
88 - newEntry->prev = list;
89 - newEntry->next = listNext;
90 - listNext->prev = newEntry;
91 -
92 -}
93 -
94 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
95 - struct ylist_head *list)
96 -{
97 - struct ylist_head *listPrev = list->prev;
98 -
99 - list->prev = newEntry;
100 - newEntry->next = list;
101 - newEntry->prev = listPrev;
102 - listPrev->next = newEntry;
103 -
104 -}
105 -
106 -
107 -/* Take an element out of its current list, with or without
108 - * reinitialising the links.of the entry*/
109 -static __inline__ void ylist_del(struct ylist_head *entry)
110 -{
111 - struct ylist_head *listNext = entry->next;
112 - struct ylist_head *listPrev = entry->prev;
113 -
114 - listNext->prev = listPrev;
115 - listPrev->next = listNext;
116 -
117 -}
118 -
119 -static __inline__ void ylist_del_init(struct ylist_head *entry)
120 -{
121 - ylist_del(entry);
122 - entry->next = entry->prev = entry;
123 -}
124 -
125 -
126 -/* Test if the list is empty */
127 -static __inline__ int ylist_empty(struct ylist_head *entry)
128 -{
129 - return (entry->next == entry);
130 -}
131 -
132 -
133 -/* ylist_entry takes a pointer to a list entry and offsets it to that
134 - * we can find a pointer to the object it is embedded in.
135 - */
136 -
137 -
138 -#define ylist_entry(entry, type, member) \
139 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
140 -
141 -
142 -/* ylist_for_each and list_for_each_safe iterate over lists.
143 - * ylist_for_each_safe uses temporary storage to make the list delete safe
144 - */
145 -
146 -#define ylist_for_each(itervar, list) \
147 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
148 -
149 -#define ylist_for_each_safe(itervar, saveVar, list) \
150 - for (itervar = (list)->next, saveVar = (list)->next->next; \
151 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
152 -
153
154 #if !(defined __KERNEL__)
155
156 --- a/fs/yaffs2/Kconfig
157 +++ b/fs/yaffs2/Kconfig
158 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
159
160 If unsure, say Y.
161
162 -config YAFFS_DISABLE_LAZY_LOAD
163 - bool "Disable lazy loading"
164 - depends on YAFFS_YAFFS2
165 +config YAFFS_DISABLE_TAGS_ECC
166 + bool "Disable YAFFS from doing ECC on tags by default"
167 + depends on YAFFS_FS && YAFFS_YAFFS2
168 default n
169 help
170 - "Lazy loading" defers loading file details until they are
171 - required. This saves mount time, but makes the first look-up
172 - a bit longer.
173 -
174 - Lazy loading will only happen if enabled by this option being 'n'
175 - and if the appropriate tags are available, else yaffs2 will
176 - automatically fall back to immediate loading and do the right
177 - thing.
178 -
179 - Lazy laoding will be required by checkpointing.
180 -
181 - Setting this to 'y' will disable lazy loading.
182 + This defaults Yaffs to using its own ECC calculations on tags instead of
183 + just relying on the MTD.
184 + This behavior can also be overridden with tags_ecc_on and
185 + tags_ecc_off mount options.
186
187 If unsure, say N.
188
189 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
190 but makes look-ups faster.
191
192 If unsure, say Y.
193 +
194 +config YAFFS_EMPTY_LOST_AND_FOUND
195 + bool "Empty lost and found on boot"
196 + depends on YAFFS_FS
197 + default n
198 + help
199 + If this is enabled then the contents of lost and found is
200 + automatically dumped at mount.
201 +
202 + If unsure, say N.
203 +
204 +config YAFFS_DISABLE_BLOCK_REFRESHING
205 + bool "Disable yaffs2 block refreshing"
206 + depends on YAFFS_FS
207 + default n
208 + help
209 + If this is set, then block refreshing is disabled.
210 + Block refreshing infrequently refreshes the oldest block in
211 + a yaffs2 file system. This mechanism helps to refresh flash to
212 + mitigate against data loss. This is particularly useful for MLC.
213 +
214 + If unsure, say N.
215 +
216 +config YAFFS_DISABLE_BACKGROUND
217 + bool "Disable yaffs2 background processing"
218 + depends on YAFFS_FS
219 + default n
220 + help
221 + If this is set, then background processing is disabled.
222 + Background processing makes many foreground activities faster.
223 +
224 + If unsure, say N.
225 +
226 +config YAFFS_XATTR
227 + bool "Enable yaffs2 xattr support"
228 + depends on YAFFS_FS
229 + default y
230 + help
231 + If this is set then yaffs2 will provide xattr support.
232 + If unsure, say Y.
233 +
234 +
235 --- a/fs/yaffs2/Makefile
236 +++ b/fs/yaffs2/Makefile
237 @@ -4,7 +4,14 @@
238
239 obj-$(CONFIG_YAFFS_FS) += yaffs.o
240
241 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
242 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
243 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
244 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
245 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
246 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
247 +yaffs-y += yaffs_nameval.o
248 +yaffs-y += yaffs_allocator.o
249 +yaffs-y += yaffs_yaffs1.o
250 +yaffs-y += yaffs_yaffs2.o
251 +yaffs-y += yaffs_bitmap.o
252 +yaffs-y += yaffs_verify.o
253 +
254 --- a/fs/yaffs2/moduleconfig.h
255 +++ b/fs/yaffs2/moduleconfig.h
256 @@ -1,7 +1,7 @@
257 /*
258 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
259 *
260 - * Copyright (C) 2002-2007 Aleph One Ltd.
261 + * Copyright (C) 2002-2010 Aleph One Ltd.
262 * for Toby Churchill Ltd and Brightstar Engineering
263 *
264 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
265 @@ -29,25 +29,46 @@
266 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
267 /* #define CONFIG_YAFFS_DOES_ECC */
268
269 +/* Default: Selected */
270 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
271 +#define CONFIG_YAFFS_DOES_TAGS_ECC
272 +
273 /* Default: Not selected */
274 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
275 /* CONFIG_YAFFS_DOES_ECC is set */
276 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
277
278 -/* Default: Selected */
279 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
280 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
281 +/* Default: Not selected */
282 +/* Meaning: Always test whether chunks are erased before writing to them.
283 + Use during mtd debugging and init. */
284 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
285 +
286 +/* Default: Not Selected */
287 +/* Meaning: At mount automatically empty all files from lost and found. */
288 +/* This is done to fix an old problem where rmdir was not checking for an */
289 +/* empty directory. This can also be achieved with a mount option. */
290 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
291
292 /* Default: Selected */
293 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
294 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
295
296 -/* Default: 10 */
297 -/* Meaning: set the count of blocks to reserve for checkpointing */
298 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
299 +/* Default: Unselected */
300 +/* Meaning: Select to disable block refreshing. */
301 +/* Block Refreshing periodically rewrites the oldest block. */
302 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
303 +
304 +/* Default: Unselected */
305 +/* Meaning: Select to disable background processing */
306 +/* #define CONFIG_DISABLE_BACKGROUND */
307 +
308 +
309 +/* Default: Selected */
310 +/* Meaning: Enable XATTR support */
311 +#define CONFIG_YAFFS_XATTR
312
313 /*
314 -Older-style on-NAND data format has a "pageStatus" byte to record
315 +Older-style on-NAND data format has a "page_status" byte to record
316 chunk/page state. This byte is zeroed when the page is discarded.
317 Choose this option if you have existing on-NAND data in this format
318 that you need to continue to support. New data written also uses the
319 @@ -57,7 +78,7 @@ adjusted to use the older-style format.
320 MTD versions in yaffs_mtdif1.c.
321 */
322 /* Default: Not selected */
323 -/* Meaning: Use older-style on-NAND data format with pageStatus byte */
324 +/* Meaning: Use older-style on-NAND data format with page_status byte */
325 /* #define CONFIG_YAFFS_9BYTE_TAGS */
326
327 #endif /* YAFFS_OUT_OF_TREE */
328 --- /dev/null
329 +++ b/fs/yaffs2/yaffs_allocator.c
330 @@ -0,0 +1,409 @@
331 +/*
332 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
333 + *
334 + * Copyright (C) 2002-2010 Aleph One Ltd.
335 + * for Toby Churchill Ltd and Brightstar Engineering
336 + *
337 + * Created by Charles Manning <charles@aleph1.co.uk>
338 + *
339 + * This program is free software; you can redistribute it and/or modify
340 + * it under the terms of the GNU Lesser General Public License version 2.1 as
341 + * published by the Free Software Foundation.
342 + *
343 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
344 + */
345 +
346 +
347 +#include "yaffs_allocator.h"
348 +#include "yaffs_guts.h"
349 +#include "yaffs_trace.h"
350 +#include "yportenv.h"
351 +
352 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
353 +
354 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
355 +{
356 + dev = dev;
357 +}
358 +
359 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
360 +{
361 + dev = dev;
362 +}
363 +
364 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
365 +{
366 + return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
367 +}
368 +
369 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
370 +{
371 + dev = dev;
372 + YFREE(tn);
373 +}
374 +
375 +void yaffs_init_raw_objs(yaffs_dev_t *dev)
376 +{
377 + dev = dev;
378 +}
379 +
380 +void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
381 +{
382 + dev = dev;
383 +}
384 +
385 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
386 +{
387 + dev = dev;
388 + return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
389 +}
390 +
391 +
392 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
393 +{
394 +
395 + dev = dev;
396 + YFREE(obj);
397 +}
398 +
399 +#else
400 +
401 +struct yaffs_tnode_list {
402 + struct yaffs_tnode_list *next;
403 + yaffs_tnode_t *tnodes;
404 +};
405 +
406 +typedef struct yaffs_tnode_list yaffs_tnodelist_t;
407 +
408 +struct yaffs_obj_tList_struct {
409 + yaffs_obj_t *objects;
410 + struct yaffs_obj_tList_struct *next;
411 +};
412 +
413 +typedef struct yaffs_obj_tList_struct yaffs_obj_tList;
414 +
415 +
416 +struct yaffs_AllocatorStruct {
417 + int n_tnodesCreated;
418 + yaffs_tnode_t *freeTnodes;
419 + int nFreeTnodes;
420 + yaffs_tnodelist_t *allocatedTnodeList;
421 +
422 + int n_objCreated;
423 + yaffs_obj_t *freeObjects;
424 + int nFreeObjects;
425 +
426 + yaffs_obj_tList *allocatedObjectList;
427 +};
428 +
429 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
430 +
431 +
432 +static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
433 +{
434 +
435 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
436 +
437 + yaffs_tnodelist_t *tmp;
438 +
439 + if(!allocator){
440 + YBUG();
441 + return;
442 + }
443 +
444 + while (allocator->allocatedTnodeList) {
445 + tmp = allocator->allocatedTnodeList->next;
446 +
447 + YFREE(allocator->allocatedTnodeList->tnodes);
448 + YFREE(allocator->allocatedTnodeList);
449 + allocator->allocatedTnodeList = tmp;
450 +
451 + }
452 +
453 + allocator->freeTnodes = NULL;
454 + allocator->nFreeTnodes = 0;
455 + allocator->n_tnodesCreated = 0;
456 +}
457 +
458 +static void yaffs_init_raw_tnodes(yaffs_dev_t *dev)
459 +{
460 + yaffs_Allocator *allocator = dev->allocator;
461 +
462 + if(allocator){
463 + allocator->allocatedTnodeList = NULL;
464 + allocator->freeTnodes = NULL;
465 + allocator->nFreeTnodes = 0;
466 + allocator->n_tnodesCreated = 0;
467 + } else
468 + YBUG();
469 +}
470 +
471 +static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes)
472 +{
473 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
474 + int i;
475 + yaffs_tnode_t *newTnodes;
476 + __u8 *mem;
477 + yaffs_tnode_t *curr;
478 + yaffs_tnode_t *next;
479 + yaffs_tnodelist_t *tnl;
480 +
481 + if(!allocator){
482 + YBUG();
483 + return YAFFS_FAIL;
484 + }
485 +
486 + if (n_tnodes < 1)
487 + return YAFFS_OK;
488 +
489 +
490 + /* make these things */
491 +
492 + newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
493 + mem = (__u8 *)newTnodes;
494 +
495 + if (!newTnodes) {
496 + T(YAFFS_TRACE_ERROR,
497 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
498 + return YAFFS_FAIL;
499 + }
500 +
501 + /* New hookup for wide tnodes */
502 + for (i = 0; i < n_tnodes - 1; i++) {
503 + curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
504 + next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
505 + curr->internal[0] = next;
506 + }
507 +
508 + curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
509 + curr->internal[0] = allocator->freeTnodes;
510 + allocator->freeTnodes = (yaffs_tnode_t *)mem;
511 +
512 + allocator->nFreeTnodes += n_tnodes;
513 + allocator->n_tnodesCreated += n_tnodes;
514 +
515 + /* Now add this bunch of tnodes to a list for freeing up.
516 + * NB If we can't add this to the management list it isn't fatal
517 + * but it just means we can't free this bunch of tnodes later.
518 + */
519 +
520 + tnl = YMALLOC(sizeof(yaffs_tnodelist_t));
521 + if (!tnl) {
522 + T(YAFFS_TRACE_ERROR,
523 + (TSTR
524 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
525 + return YAFFS_FAIL;
526 + } else {
527 + tnl->tnodes = newTnodes;
528 + tnl->next = allocator->allocatedTnodeList;
529 + allocator->allocatedTnodeList = tnl;
530 + }
531 +
532 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
533 +
534 + return YAFFS_OK;
535 +}
536 +
537 +
538 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
539 +{
540 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
541 + yaffs_tnode_t *tn = NULL;
542 +
543 + if(!allocator){
544 + YBUG();
545 + return NULL;
546 + }
547 +
548 + /* If there are none left make more */
549 + if (!allocator->freeTnodes)
550 + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
551 +
552 + if (allocator->freeTnodes) {
553 + tn = allocator->freeTnodes;
554 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
555 + allocator->nFreeTnodes--;
556 + }
557 +
558 + return tn;
559 +}
560 +
561 +/* FreeTnode frees up a tnode and puts it back on the free list */
562 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
563 +{
564 + yaffs_Allocator *allocator = dev->allocator;
565 +
566 + if(!allocator){
567 + YBUG();
568 + return;
569 + }
570 +
571 + if (tn) {
572 + tn->internal[0] = allocator->freeTnodes;
573 + allocator->freeTnodes = tn;
574 + allocator->nFreeTnodes++;
575 + }
576 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
577 +}
578 +
579 +
580 +
581 +static void yaffs_init_raw_objs(yaffs_dev_t *dev)
582 +{
583 + yaffs_Allocator *allocator = dev->allocator;
584 +
585 + if(allocator) {
586 + allocator->allocatedObjectList = NULL;
587 + allocator->freeObjects = NULL;
588 + allocator->nFreeObjects = 0;
589 + } else
590 + YBUG();
591 +}
592 +
593 +static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
594 +{
595 + yaffs_Allocator *allocator = dev->allocator;
596 + yaffs_obj_tList *tmp;
597 +
598 + if(!allocator){
599 + YBUG();
600 + return;
601 + }
602 +
603 + while (allocator->allocatedObjectList) {
604 + tmp = allocator->allocatedObjectList->next;
605 + YFREE(allocator->allocatedObjectList->objects);
606 + YFREE(allocator->allocatedObjectList);
607 +
608 + allocator->allocatedObjectList = tmp;
609 + }
610 +
611 + allocator->freeObjects = NULL;
612 + allocator->nFreeObjects = 0;
613 + allocator->n_objCreated = 0;
614 +}
615 +
616 +
617 +static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
618 +{
619 + yaffs_Allocator *allocator = dev->allocator;
620 +
621 + int i;
622 + yaffs_obj_t *newObjects;
623 + yaffs_obj_tList *list;
624 +
625 + if(!allocator){
626 + YBUG();
627 + return YAFFS_FAIL;
628 + }
629 +
630 + if (n_obj < 1)
631 + return YAFFS_OK;
632 +
633 + /* make these things */
634 + newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
635 + list = YMALLOC(sizeof(yaffs_obj_tList));
636 +
637 + if (!newObjects || !list) {
638 + if (newObjects){
639 + YFREE(newObjects);
640 + newObjects = NULL;
641 + }
642 + if (list){
643 + YFREE(list);
644 + list = NULL;
645 + }
646 + T(YAFFS_TRACE_ALLOCATE,
647 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
648 + return YAFFS_FAIL;
649 + }
650 +
651 + /* Hook them into the free list */
652 + for (i = 0; i < n_obj - 1; i++) {
653 + newObjects[i].siblings.next =
654 + (struct ylist_head *)(&newObjects[i + 1]);
655 + }
656 +
657 + newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
658 + allocator->freeObjects = newObjects;
659 + allocator->nFreeObjects += n_obj;
660 + allocator->n_objCreated += n_obj;
661 +
662 + /* Now add this bunch of Objects to a list for freeing up. */
663 +
664 + list->objects = newObjects;
665 + list->next = allocator->allocatedObjectList;
666 + allocator->allocatedObjectList = list;
667 +
668 + return YAFFS_OK;
669 +}
670 +
671 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
672 +{
673 + yaffs_obj_t *obj = NULL;
674 + yaffs_Allocator *allocator = dev->allocator;
675 +
676 + if(!allocator) {
677 + YBUG();
678 + return obj;
679 + }
680 +
681 + /* If there are none left make more */
682 + if (!allocator->freeObjects)
683 + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
684 +
685 + if (allocator->freeObjects) {
686 + obj = allocator->freeObjects;
687 + allocator->freeObjects =
688 + (yaffs_obj_t *) (allocator->freeObjects->siblings.next);
689 + allocator->nFreeObjects--;
690 + }
691 +
692 + return obj;
693 +}
694 +
695 +
696 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
697 +{
698 +
699 + yaffs_Allocator *allocator = dev->allocator;
700 +
701 + if(!allocator)
702 + YBUG();
703 + else {
704 + /* Link into the free list. */
705 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
706 + allocator->freeObjects = obj;
707 + allocator->nFreeObjects++;
708 + }
709 +}
710 +
711 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
712 +{
713 + if(dev->allocator){
714 + yaffs_deinit_raw_tnodes(dev);
715 + yaffs_deinit_raw_objs(dev);
716 +
717 + YFREE(dev->allocator);
718 + dev->allocator=NULL;
719 + } else
720 + YBUG();
721 +}
722 +
723 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
724 +{
725 + yaffs_Allocator *allocator;
726 +
727 + if(!dev->allocator){
728 + allocator = YMALLOC(sizeof(yaffs_Allocator));
729 + if(allocator){
730 + dev->allocator = allocator;
731 + yaffs_init_raw_tnodes(dev);
732 + yaffs_init_raw_objs(dev);
733 + }
734 + } else
735 + YBUG();
736 +}
737 +
738 +
739 +#endif
740 --- /dev/null
741 +++ b/fs/yaffs2/yaffs_allocator.h
742 @@ -0,0 +1,30 @@
743 +/*
744 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
745 + *
746 + * Copyright (C) 2002-2010 Aleph One Ltd.
747 + * for Toby Churchill Ltd and Brightstar Engineering
748 + *
749 + * Created by Charles Manning <charles@aleph1.co.uk>
750 + *
751 + * This program is free software; you can redistribute it and/or modify
752 + * it under the terms of the GNU Lesser General Public License version 2.1 as
753 + * published by the Free Software Foundation.
754 + *
755 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
756 + */
757 +
758 +#ifndef __YAFFS_ALLOCATOR_H__
759 +#define __YAFFS_ALLOCATOR_H__
760 +
761 +#include "yaffs_guts.h"
762 +
763 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev);
764 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev);
765 +
766 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev);
767 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn);
768 +
769 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev);
770 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj);
771 +
772 +#endif
773 --- /dev/null
774 +++ b/fs/yaffs2/yaffs_bitmap.c
775 @@ -0,0 +1,105 @@
776 +/*
777 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
778 + *
779 + * Copyright (C) 2002-2010 Aleph One Ltd.
780 + * for Toby Churchill Ltd and Brightstar Engineering
781 + *
782 + * Created by Charles Manning <charles@aleph1.co.uk>
783 + *
784 + * This program is free software; you can redistribute it and/or modify
785 + * it under the terms of the GNU General Public License version 2 as
786 + * published by the Free Software Foundation.
787 + */
788 +
789 +#include "yaffs_bitmap.h"
790 +#include "yaffs_trace.h"
791 +/*
792 + * Chunk bitmap manipulations
793 + */
794 +
795 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_dev_t *dev, int blk)
796 +{
797 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
798 + T(YAFFS_TRACE_ERROR,
799 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
800 + blk));
801 + YBUG();
802 + }
803 + return dev->chunk_bits +
804 + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
805 +}
806 +
807 +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk)
808 +{
809 + if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
810 + chunk < 0 || chunk >= dev->param.chunks_per_block) {
811 + T(YAFFS_TRACE_ERROR,
812 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
813 + blk, chunk));
814 + YBUG();
815 + }
816 +}
817 +
818 +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk)
819 +{
820 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
821 +
822 + memset(blkBits, 0, dev->chunk_bit_stride);
823 +}
824 +
825 +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
826 +{
827 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
828 +
829 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
830 +
831 + blkBits[chunk / 8] &= ~(1 << (chunk & 7));
832 +}
833 +
834 +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
835 +{
836 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
837 +
838 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
839 +
840 + blkBits[chunk / 8] |= (1 << (chunk & 7));
841 +}
842 +
843 +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
844 +{
845 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
846 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
847 +
848 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
849 +}
850 +
851 +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk)
852 +{
853 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
854 + int i;
855 + for (i = 0; i < dev->chunk_bit_stride; i++) {
856 + if (*blkBits)
857 + return 1;
858 + blkBits++;
859 + }
860 + return 0;
861 +}
862 +
863 +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk)
864 +{
865 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
866 + int i;
867 + int n = 0;
868 + for (i = 0; i < dev->chunk_bit_stride; i++) {
869 + __u8 x = *blkBits;
870 + while (x) {
871 + if (x & 1)
872 + n++;
873 + x >>= 1;
874 + }
875 +
876 + blkBits++;
877 + }
878 + return n;
879 +}
880 +
881 --- /dev/null
882 +++ b/fs/yaffs2/yaffs_bitmap.h
883 @@ -0,0 +1,31 @@
884 +/*
885 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
886 + *
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 + *
892 + * This program is free software; you can redistribute it and/or modify
893 + * it under the terms of the GNU General Public License version 2 as
894 + * published by the Free Software Foundation.
895 + */
896 +
897 +/*
898 + * Chunk bitmap manipulations
899 + */
900 +
901 +#ifndef __YAFFS_BITMAP_H__
902 +#define __YAFFS_BITMAP_H__
903 +
904 +#include "yaffs_guts.h"
905 +
906 +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk);
907 +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk);
908 +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
909 +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
910 +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
911 +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk);
912 +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk);
913 +
914 +#endif
915 --- a/fs/yaffs2/yaffs_checkptrw.c
916 +++ b/fs/yaffs2/yaffs_checkptrw.c
917 @@ -1,7 +1,7 @@
918 /*
919 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
920 *
921 - * Copyright (C) 2002-2007 Aleph One Ltd.
922 + * Copyright (C) 2002-2010 Aleph One Ltd.
923 * for Toby Churchill Ltd and Brightstar Engineering
924 *
925 * Created by Charles Manning <charles@aleph1.co.uk>
926 @@ -11,16 +11,12 @@
927 * published by the Free Software Foundation.
928 */
929
930 -const char *yaffs_checkptrw_c_version =
931 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
932 -
933 -
934 #include "yaffs_checkptrw.h"
935 #include "yaffs_getblockinfo.h"
936
937 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
938 +static int yaffs2_checkpt_space_ok(yaffs_dev_t *dev)
939 {
940 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
941 + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
942
943 T(YAFFS_TRACE_CHECKPOINT,
944 (TSTR("checkpt blocks available = %d" TENDSTR),
945 @@ -30,53 +26,56 @@ static int yaffs_CheckpointSpaceOk(yaffs
946 }
947
948
949 -static int yaffs_CheckpointErase(yaffs_Device *dev)
950 +static int yaffs_checkpt_erase(yaffs_dev_t *dev)
951 {
952 int i;
953
954 - if (!dev->eraseBlockInNAND)
955 + if (!dev->param.erase_fn)
956 return 0;
957 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
958 - dev->internalStartBlock, dev->internalEndBlock));
959 + dev->internal_start_block, dev->internal_end_block));
960
961 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
962 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
963 - if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
964 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
965 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
966 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
967 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
968 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
969 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
970 - dev->nErasedBlocks++;
971 - dev->nFreeChunks += dev->nChunksPerBlock;
972 +
973 + dev->n_erasures++;
974 +
975 + if (dev->param.erase_fn(dev, i - dev->block_offset /* realign */)) {
976 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
977 + dev->n_erased_blocks++;
978 + dev->n_free_chunks += dev->param.chunks_per_block;
979 } else {
980 - dev->markNANDBlockBad(dev, i);
981 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
982 + dev->param.bad_block_fn(dev, i);
983 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
984 }
985 }
986 }
987
988 - dev->blocksInCheckpoint = 0;
989 + dev->blocks_in_checkpt = 0;
990
991 return 1;
992 }
993
994
995 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
996 +static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
997 {
998 int i;
999 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
1000 + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
1001 T(YAFFS_TRACE_CHECKPOINT,
1002 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
1003 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
1004 + dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block));
1005
1006 - if (dev->checkpointNextBlock >= 0 &&
1007 - dev->checkpointNextBlock <= dev->internalEndBlock &&
1008 + if (dev->checkpt_next_block >= 0 &&
1009 + dev->checkpt_next_block <= dev->internal_end_block &&
1010 blocksAvailable > 0) {
1011
1012 - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
1013 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
1014 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
1015 - dev->checkpointNextBlock = i + 1;
1016 - dev->checkpointCurrentBlock = i;
1017 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
1018 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
1019 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
1020 + dev->checkpt_next_block = i + 1;
1021 + dev->checkpt_cur_block = i;
1022 T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
1023 return;
1024 }
1025 @@ -84,34 +83,34 @@ static void yaffs_CheckpointFindNextEras
1026 }
1027 T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
1028
1029 - dev->checkpointNextBlock = -1;
1030 - dev->checkpointCurrentBlock = -1;
1031 + dev->checkpt_next_block = -1;
1032 + dev->checkpt_cur_block = -1;
1033 }
1034
1035 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
1036 +static void yaffs2_checkpt_find_block(yaffs_dev_t *dev)
1037 {
1038 int i;
1039 - yaffs_ExtendedTags tags;
1040 + yaffs_ext_tags tags;
1041
1042 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
1043 - dev->blocksInCheckpoint, dev->checkpointNextBlock));
1044 + dev->blocks_in_checkpt, dev->checkpt_next_block));
1045
1046 - if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
1047 - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
1048 - int chunk = i * dev->nChunksPerBlock;
1049 - int realignedChunk = chunk - dev->chunkOffset;
1050 + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
1051 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
1052 + int chunk = i * dev->param.chunks_per_block;
1053 + int realignedChunk = chunk - dev->chunk_offset;
1054
1055 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
1056 + dev->param.read_chunk_tags_fn(dev, realignedChunk,
1057 NULL, &tags);
1058 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
1059 - i, tags.objectId, tags.sequenceNumber, tags.eccResult));
1060 + i, tags.obj_id, tags.seq_number, tags.ecc_result));
1061
1062 - if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1063 + if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1064 /* Right kind of block */
1065 - dev->checkpointNextBlock = tags.objectId;
1066 - dev->checkpointCurrentBlock = i;
1067 - dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
1068 - dev->blocksInCheckpoint++;
1069 + dev->checkpt_next_block = tags.obj_id;
1070 + dev->checkpt_cur_block = i;
1071 + dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
1072 + dev->blocks_in_checkpt++;
1073 T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
1074 return;
1075 }
1076 @@ -119,122 +118,127 @@ static void yaffs_CheckpointFindNextChec
1077
1078 T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
1079
1080 - dev->checkpointNextBlock = -1;
1081 - dev->checkpointCurrentBlock = -1;
1082 + dev->checkpt_next_block = -1;
1083 + dev->checkpt_cur_block = -1;
1084 }
1085
1086
1087 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
1088 +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
1089 {
1090
1091 +
1092 + dev->checkpt_open_write = forWriting;
1093 +
1094 /* Got the functions we need? */
1095 - if (!dev->writeChunkWithTagsToNAND ||
1096 - !dev->readChunkWithTagsFromNAND ||
1097 - !dev->eraseBlockInNAND ||
1098 - !dev->markNANDBlockBad)
1099 + if (!dev->param.write_chunk_tags_fn ||
1100 + !dev->param.read_chunk_tags_fn ||
1101 + !dev->param.erase_fn ||
1102 + !dev->param.bad_block_fn)
1103 return 0;
1104
1105 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
1106 + if (forWriting && !yaffs2_checkpt_space_ok(dev))
1107 return 0;
1108
1109 - if (!dev->checkpointBuffer)
1110 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1111 - if (!dev->checkpointBuffer)
1112 + if (!dev->checkpt_buffer)
1113 + dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
1114 + if (!dev->checkpt_buffer)
1115 return 0;
1116
1117
1118 - dev->checkpointPageSequence = 0;
1119 -
1120 - dev->checkpointOpenForWrite = forWriting;
1121 -
1122 - dev->checkpointByteCount = 0;
1123 - dev->checkpointSum = 0;
1124 - dev->checkpointXor = 0;
1125 - dev->checkpointCurrentBlock = -1;
1126 - dev->checkpointCurrentChunk = -1;
1127 - dev->checkpointNextBlock = dev->internalStartBlock;
1128 + dev->checkpt_page_seq = 0;
1129 + dev->checkpt_byte_count = 0;
1130 + dev->checkpt_sum = 0;
1131 + dev->checkpt_xor = 0;
1132 + dev->checkpt_cur_block = -1;
1133 + dev->checkpt_cur_chunk = -1;
1134 + dev->checkpt_next_block = dev->internal_start_block;
1135
1136 /* Erase all the blocks in the checkpoint area */
1137 if (forWriting) {
1138 - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1139 - dev->checkpointByteOffset = 0;
1140 - return yaffs_CheckpointErase(dev);
1141 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1142 + dev->checkpt_byte_offs = 0;
1143 + return yaffs_checkpt_erase(dev);
1144 } else {
1145 int i;
1146 /* Set to a value that will kick off a read */
1147 - dev->checkpointByteOffset = dev->nDataBytesPerChunk;
1148 + dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
1149 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
1150 * going to be way more than we need */
1151 - dev->blocksInCheckpoint = 0;
1152 - dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1153 - dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1154 - for (i = 0; i < dev->checkpointMaxBlocks; i++)
1155 - dev->checkpointBlockList[i] = -1;
1156 + dev->blocks_in_checkpt = 0;
1157 + dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2;
1158 + dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
1159 + if(!dev->checkpt_block_list)
1160 + return 0;
1161 +
1162 + for (i = 0; i < dev->checkpt_max_blocks; i++)
1163 + dev->checkpt_block_list[i] = -1;
1164 }
1165
1166 return 1;
1167 }
1168
1169 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1170 +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum)
1171 {
1172 __u32 compositeSum;
1173 - compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1174 + compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
1175 *sum = compositeSum;
1176 return 1;
1177 }
1178
1179 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1180 +static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
1181 {
1182 int chunk;
1183 int realignedChunk;
1184
1185 - yaffs_ExtendedTags tags;
1186 + yaffs_ext_tags tags;
1187
1188 - if (dev->checkpointCurrentBlock < 0) {
1189 - yaffs_CheckpointFindNextErasedBlock(dev);
1190 - dev->checkpointCurrentChunk = 0;
1191 + if (dev->checkpt_cur_block < 0) {
1192 + yaffs2_checkpt_find_erased_block(dev);
1193 + dev->checkpt_cur_chunk = 0;
1194 }
1195
1196 - if (dev->checkpointCurrentBlock < 0)
1197 + if (dev->checkpt_cur_block < 0)
1198 return 0;
1199
1200 - tags.chunkDeleted = 0;
1201 - tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
1202 - tags.chunkId = dev->checkpointPageSequence + 1;
1203 - tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1204 - tags.byteCount = dev->nDataBytesPerChunk;
1205 - if (dev->checkpointCurrentChunk == 0) {
1206 + tags.is_deleted = 0;
1207 + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
1208 + tags.chunk_id = dev->checkpt_page_seq + 1;
1209 + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1210 + tags.n_bytes = dev->data_bytes_per_chunk;
1211 + if (dev->checkpt_cur_chunk == 0) {
1212 /* First chunk we write for the block? Set block state to
1213 checkpoint */
1214 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
1215 - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1216 - dev->blocksInCheckpoint++;
1217 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block);
1218 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1219 + dev->blocks_in_checkpt++;
1220 }
1221
1222 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1223 + chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk;
1224
1225
1226 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1227 - chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
1228 + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id));
1229
1230 - realignedChunk = chunk - dev->chunkOffset;
1231 + realignedChunk = chunk - dev->chunk_offset;
1232
1233 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1234 - dev->checkpointBuffer, &tags);
1235 - dev->checkpointByteOffset = 0;
1236 - dev->checkpointPageSequence++;
1237 - dev->checkpointCurrentChunk++;
1238 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1239 - dev->checkpointCurrentChunk = 0;
1240 - dev->checkpointCurrentBlock = -1;
1241 + dev->n_page_writes++;
1242 +
1243 + dev->param.write_chunk_tags_fn(dev, realignedChunk,
1244 + dev->checkpt_buffer, &tags);
1245 + dev->checkpt_byte_offs = 0;
1246 + dev->checkpt_page_seq++;
1247 + dev->checkpt_cur_chunk++;
1248 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
1249 + dev->checkpt_cur_chunk = 0;
1250 + dev->checkpt_cur_block = -1;
1251 }
1252 - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1253 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1254
1255 return 1;
1256 }
1257
1258
1259 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1260 +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes)
1261 {
1262 int i = 0;
1263 int ok = 1;
1264 @@ -244,36 +248,36 @@ int yaffs_CheckpointWrite(yaffs_Device *
1265
1266
1267
1268 - if (!dev->checkpointBuffer)
1269 + if (!dev->checkpt_buffer)
1270 return 0;
1271
1272 - if (!dev->checkpointOpenForWrite)
1273 + if (!dev->checkpt_open_write)
1274 return -1;
1275
1276 - while (i < nBytes && ok) {
1277 - dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
1278 - dev->checkpointSum += *dataBytes;
1279 - dev->checkpointXor ^= *dataBytes;
1280 + while (i < n_bytes && ok) {
1281 + dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes;
1282 + dev->checkpt_sum += *dataBytes;
1283 + dev->checkpt_xor ^= *dataBytes;
1284
1285 - dev->checkpointByteOffset++;
1286 + dev->checkpt_byte_offs++;
1287 i++;
1288 dataBytes++;
1289 - dev->checkpointByteCount++;
1290 + dev->checkpt_byte_count++;
1291
1292
1293 - if (dev->checkpointByteOffset < 0 ||
1294 - dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1295 - ok = yaffs_CheckpointFlushBuffer(dev);
1296 + if (dev->checkpt_byte_offs < 0 ||
1297 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
1298 + ok = yaffs2_checkpt_flush_buffer(dev);
1299 }
1300
1301 return i;
1302 }
1303
1304 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1305 +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes)
1306 {
1307 int i = 0;
1308 int ok = 1;
1309 - yaffs_ExtendedTags tags;
1310 + yaffs_ext_tags tags;
1311
1312
1313 int chunk;
1314 @@ -281,113 +285,116 @@ int yaffs_CheckpointRead(yaffs_Device *d
1315
1316 __u8 *dataBytes = (__u8 *)data;
1317
1318 - if (!dev->checkpointBuffer)
1319 + if (!dev->checkpt_buffer)
1320 return 0;
1321
1322 - if (dev->checkpointOpenForWrite)
1323 + if (dev->checkpt_open_write)
1324 return -1;
1325
1326 - while (i < nBytes && ok) {
1327 + while (i < n_bytes && ok) {
1328
1329
1330 - if (dev->checkpointByteOffset < 0 ||
1331 - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1332 + if (dev->checkpt_byte_offs < 0 ||
1333 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
1334
1335 - if (dev->checkpointCurrentBlock < 0) {
1336 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1337 - dev->checkpointCurrentChunk = 0;
1338 + if (dev->checkpt_cur_block < 0) {
1339 + yaffs2_checkpt_find_block(dev);
1340 + dev->checkpt_cur_chunk = 0;
1341 }
1342
1343 - if (dev->checkpointCurrentBlock < 0)
1344 + if (dev->checkpt_cur_block < 0)
1345 ok = 0;
1346 else {
1347 - chunk = dev->checkpointCurrentBlock *
1348 - dev->nChunksPerBlock +
1349 - dev->checkpointCurrentChunk;
1350 -
1351 - realignedChunk = chunk - dev->chunkOffset;
1352 + chunk = dev->checkpt_cur_block *
1353 + dev->param.chunks_per_block +
1354 + dev->checkpt_cur_chunk;
1355 +
1356 + realignedChunk = chunk - dev->chunk_offset;
1357 +
1358 + dev->n_page_reads++;
1359
1360 /* read in the next chunk */
1361 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1362 - dev->readChunkWithTagsFromNAND(dev,
1363 + dev->param.read_chunk_tags_fn(dev,
1364 realignedChunk,
1365 - dev->checkpointBuffer,
1366 + dev->checkpt_buffer,
1367 &tags);
1368
1369 - if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
1370 - tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
1371 - tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1372 + if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
1373 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
1374 + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1375 ok = 0;
1376
1377 - dev->checkpointByteOffset = 0;
1378 - dev->checkpointPageSequence++;
1379 - dev->checkpointCurrentChunk++;
1380 + dev->checkpt_byte_offs = 0;
1381 + dev->checkpt_page_seq++;
1382 + dev->checkpt_cur_chunk++;
1383
1384 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1385 - dev->checkpointCurrentBlock = -1;
1386 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
1387 + dev->checkpt_cur_block = -1;
1388 }
1389 }
1390
1391 if (ok) {
1392 - *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
1393 - dev->checkpointSum += *dataBytes;
1394 - dev->checkpointXor ^= *dataBytes;
1395 - dev->checkpointByteOffset++;
1396 + *dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
1397 + dev->checkpt_sum += *dataBytes;
1398 + dev->checkpt_xor ^= *dataBytes;
1399 + dev->checkpt_byte_offs++;
1400 i++;
1401 dataBytes++;
1402 - dev->checkpointByteCount++;
1403 + dev->checkpt_byte_count++;
1404 }
1405 }
1406
1407 return i;
1408 }
1409
1410 -int yaffs_CheckpointClose(yaffs_Device *dev)
1411 +int yaffs_checkpt_close(yaffs_dev_t *dev)
1412 {
1413
1414 - if (dev->checkpointOpenForWrite) {
1415 - if (dev->checkpointByteOffset != 0)
1416 - yaffs_CheckpointFlushBuffer(dev);
1417 - } else {
1418 + if (dev->checkpt_open_write) {
1419 + if (dev->checkpt_byte_offs != 0)
1420 + yaffs2_checkpt_flush_buffer(dev);
1421 + } else if(dev->checkpt_block_list){
1422 int i;
1423 - for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1424 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1425 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1426 - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1427 + for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) {
1428 + int blk = dev->checkpt_block_list[i];
1429 + yaffs_block_info_t *bi = NULL;
1430 + if( dev->internal_start_block <= blk && blk <= dev->internal_end_block)
1431 + bi = yaffs_get_block_info(dev, blk);
1432 + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
1433 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1434 else {
1435 /* Todo this looks odd... */
1436 }
1437 }
1438 - YFREE(dev->checkpointBlockList);
1439 - dev->checkpointBlockList = NULL;
1440 + YFREE(dev->checkpt_block_list);
1441 + dev->checkpt_block_list = NULL;
1442 }
1443
1444 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1445 - dev->nErasedBlocks -= dev->blocksInCheckpoint;
1446 + dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block;
1447 + dev->n_erased_blocks -= dev->blocks_in_checkpt;
1448
1449
1450 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
1451 - dev->checkpointByteCount));
1452 + dev->checkpt_byte_count));
1453
1454 - if (dev->checkpointBuffer) {
1455 + if (dev->checkpt_buffer) {
1456 /* free the buffer */
1457 - YFREE(dev->checkpointBuffer);
1458 - dev->checkpointBuffer = NULL;
1459 + YFREE(dev->checkpt_buffer);
1460 + dev->checkpt_buffer = NULL;
1461 return 1;
1462 } else
1463 return 0;
1464 }
1465
1466 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1467 +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev)
1468 {
1469 - /* Erase the first checksum block */
1470 -
1471 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1472 + /* Erase the checkpoint data */
1473
1474 - if (!yaffs_CheckpointSpaceOk(dev))
1475 - return 0;
1476 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1477 + dev->blocks_in_checkpt));
1478
1479 - return yaffs_CheckpointErase(dev);
1480 + return yaffs_checkpt_erase(dev);
1481 }
1482
1483
1484 --- a/fs/yaffs2/yaffs_checkptrw.h
1485 +++ b/fs/yaffs2/yaffs_checkptrw.h
1486 @@ -1,7 +1,7 @@
1487 /*
1488 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1489 *
1490 - * Copyright (C) 2002-2007 Aleph One Ltd.
1491 + * Copyright (C) 2002-2010 Aleph One Ltd.
1492 * for Toby Churchill Ltd and Brightstar Engineering
1493 *
1494 * Created by Charles Manning <charles@aleph1.co.uk>
1495 @@ -18,18 +18,17 @@
1496
1497 #include "yaffs_guts.h"
1498
1499 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1500 +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting);
1501
1502 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1503 +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes);
1504
1505 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1506 +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes);
1507
1508 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1509 +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum);
1510
1511 -int yaffs_CheckpointClose(yaffs_Device *dev);
1512 +int yaffs_checkpt_close(yaffs_dev_t *dev);
1513
1514 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1515 +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev);
1516
1517
1518 #endif
1519 -
1520 --- a/fs/yaffs2/yaffs_ecc.c
1521 +++ b/fs/yaffs2/yaffs_ecc.c
1522 @@ -1,7 +1,7 @@
1523 /*
1524 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1525 *
1526 - * Copyright (C) 2002-2007 Aleph One Ltd.
1527 + * Copyright (C) 2002-2010 Aleph One Ltd.
1528 * for Toby Churchill Ltd and Brightstar Engineering
1529 *
1530 * Created by Charles Manning <charles@aleph1.co.uk>
1531 @@ -28,9 +28,6 @@
1532 * this bytes influence on the line parity.
1533 */
1534
1535 -const char *yaffs_ecc_c_version =
1536 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1537 -
1538 #include "yportenv.h"
1539
1540 #include "yaffs_ecc.h"
1541 @@ -72,7 +69,7 @@ static const unsigned char column_parity
1542
1543 /* Count the bits in an unsigned char or a U32 */
1544
1545 -static int yaffs_CountBits(unsigned char x)
1546 +static int yaffs_count_bits(unsigned char x)
1547 {
1548 int r = 0;
1549 while (x) {
1550 @@ -83,7 +80,7 @@ static int yaffs_CountBits(unsigned char
1551 return r;
1552 }
1553
1554 -static int yaffs_CountBits32(unsigned x)
1555 +static int yaffs_count_bits32(unsigned x)
1556 {
1557 int r = 0;
1558 while (x) {
1559 @@ -95,7 +92,7 @@ static int yaffs_CountBits32(unsigned x)
1560 }
1561
1562 /* Calculate the ECC for a 256-byte block of data */
1563 -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
1564 +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
1565 {
1566 unsigned int i;
1567
1568 @@ -166,7 +163,7 @@ void yaffs_ECCCalculate(const unsigned c
1569
1570 /* Correct the ECC on a 256 byte block of data */
1571
1572 -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1573 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1574 const unsigned char *test_ecc)
1575 {
1576 unsigned char d0, d1, d2; /* deltas */
1577 @@ -226,9 +223,9 @@ int yaffs_ECCCorrect(unsigned char *data
1578 return 1; /* Corrected the error */
1579 }
1580
1581 - if ((yaffs_CountBits(d0) +
1582 - yaffs_CountBits(d1) +
1583 - yaffs_CountBits(d2)) == 1) {
1584 + if ((yaffs_count_bits(d0) +
1585 + yaffs_count_bits(d1) +
1586 + yaffs_count_bits(d2)) == 1) {
1587 /* Reccoverable error in ecc */
1588
1589 read_ecc[0] = test_ecc[0];
1590 @@ -248,7 +245,7 @@ int yaffs_ECCCorrect(unsigned char *data
1591 /*
1592 * ECCxxxOther does ECC calcs on arbitrary n bytes of data
1593 */
1594 -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1595 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1596 yaffs_ECCOther *eccOther)
1597 {
1598 unsigned int i;
1599 @@ -258,7 +255,7 @@ void yaffs_ECCCalculateOther(const unsig
1600 unsigned line_parity_prime = 0;
1601 unsigned char b;
1602
1603 - for (i = 0; i < nBytes; i++) {
1604 + for (i = 0; i < n_bytes; i++) {
1605 b = column_parity_table[*data++];
1606 col_parity ^= b;
1607
1608 @@ -275,7 +272,7 @@ void yaffs_ECCCalculateOther(const unsig
1609 eccOther->lineParityPrime = line_parity_prime;
1610 }
1611
1612 -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1613 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1614 yaffs_ECCOther *read_ecc,
1615 const yaffs_ECCOther *test_ecc)
1616 {
1617 @@ -304,7 +301,7 @@ int yaffs_ECCCorrectOther(unsigned char
1618 if (cDelta & 0x02)
1619 bit |= 0x01;
1620
1621 - if (lDelta >= nBytes)
1622 + if (lDelta >= n_bytes)
1623 return -1;
1624
1625 data[lDelta] ^= (1 << bit);
1626 @@ -312,8 +309,8 @@ int yaffs_ECCCorrectOther(unsigned char
1627 return 1; /* corrected */
1628 }
1629
1630 - if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
1631 - yaffs_CountBits(cDelta)) == 1) {
1632 + if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) +
1633 + yaffs_count_bits(cDelta)) == 1) {
1634 /* Reccoverable error in ecc */
1635
1636 *read_ecc = *test_ecc;
1637 --- a/fs/yaffs2/yaffs_ecc.h
1638 +++ b/fs/yaffs2/yaffs_ecc.h
1639 @@ -1,7 +1,7 @@
1640 /*
1641 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1642 *
1643 - * Copyright (C) 2002-2007 Aleph One Ltd.
1644 + * Copyright (C) 2002-2010 Aleph One Ltd.
1645 * for Toby Churchill Ltd and Brightstar Engineering
1646 *
1647 * Created by Charles Manning <charles@aleph1.co.uk>
1648 @@ -32,13 +32,13 @@ typedef struct {
1649 unsigned lineParityPrime;
1650 } yaffs_ECCOther;
1651
1652 -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
1653 -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1654 +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
1655 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1656 const unsigned char *test_ecc);
1657
1658 -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1659 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1660 yaffs_ECCOther *ecc);
1661 -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1662 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1663 yaffs_ECCOther *read_ecc,
1664 const yaffs_ECCOther *test_ecc);
1665 #endif
1666 --- a/fs/yaffs2/yaffs_fs.c
1667 +++ /dev/null
1668 @@ -1,2529 +0,0 @@
1669 -/*
1670 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1671 - *
1672 - * Copyright (C) 2002-2009 Aleph One Ltd.
1673 - * for Toby Churchill Ltd and Brightstar Engineering
1674 - *
1675 - * Created by Charles Manning <charles@aleph1.co.uk>
1676 - * Acknowledgements:
1677 - * Luc van OostenRyck for numerous patches.
1678 - * Nick Bane for numerous patches.
1679 - * Nick Bane for 2.5/2.6 integration.
1680 - * Andras Toth for mknod rdev issue.
1681 - * Michael Fischer for finding the problem with inode inconsistency.
1682 - * Some code bodily lifted from JFFS
1683 - *
1684 - * This program is free software; you can redistribute it and/or modify
1685 - * it under the terms of the GNU General Public License version 2 as
1686 - * published by the Free Software Foundation.
1687 - */
1688 -
1689 -/*
1690 - *
1691 - * This is the file system front-end to YAFFS that hooks it up to
1692 - * the VFS.
1693 - *
1694 - * Special notes:
1695 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1696 - * this superblock
1697 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1698 - * superblock
1699 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1700 - */
1701 -
1702 -const char *yaffs_fs_c_version =
1703 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1704 -extern const char *yaffs_guts_c_version;
1705 -
1706 -#include <linux/version.h>
1707 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1708 -#include <linux/config.h>
1709 -#endif
1710 -#include <linux/kernel.h>
1711 -#include <linux/module.h>
1712 -#include <linux/slab.h>
1713 -#include <linux/init.h>
1714 -#include <linux/fs.h>
1715 -#include <linux/proc_fs.h>
1716 -#include <linux/smp_lock.h>
1717 -#include <linux/pagemap.h>
1718 -#include <linux/mtd/mtd.h>
1719 -#include <linux/interrupt.h>
1720 -#include <linux/string.h>
1721 -#include <linux/ctype.h>
1722 -
1723 -#include "asm/div64.h"
1724 -
1725 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1726 -
1727 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1728 -#include <linux/statfs.h>
1729 -#define UnlockPage(p) unlock_page(p)
1730 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1731 -
1732 -/* FIXME: use sb->s_id instead ? */
1733 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1734 -
1735 -#else
1736 -
1737 -#include <linux/locks.h>
1738 -#define BDEVNAME_SIZE 0
1739 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1740 -
1741 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1742 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1743 -#define __user
1744 -#endif
1745 -
1746 -#endif
1747 -
1748 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1749 -#define YPROC_ROOT (&proc_root)
1750 -#else
1751 -#define YPROC_ROOT NULL
1752 -#endif
1753 -
1754 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1755 -#define WRITE_SIZE_STR "writesize"
1756 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1757 -#else
1758 -#define WRITE_SIZE_STR "oobblock"
1759 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1760 -#endif
1761 -
1762 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1763 -#define YAFFS_USE_WRITE_BEGIN_END 1
1764 -#else
1765 -#define YAFFS_USE_WRITE_BEGIN_END 0
1766 -#endif
1767 -
1768 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1769 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1770 -{
1771 - uint64_t result = partition_size;
1772 - do_div(result, block_size);
1773 - return (uint32_t)result;
1774 -}
1775 -#else
1776 -#define YCALCBLOCKS(s, b) ((s)/(b))
1777 -#endif
1778 -
1779 -#include <linux/uaccess.h>
1780 -
1781 -#include "yportenv.h"
1782 -#include "yaffs_guts.h"
1783 -
1784 -#include <linux/mtd/mtd.h>
1785 -#include "yaffs_mtdif.h"
1786 -#include "yaffs_mtdif1.h"
1787 -#include "yaffs_mtdif2.h"
1788 -
1789 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1790 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1791 -unsigned int yaffs_auto_checkpoint = 1;
1792 -
1793 -/* Module Parameters */
1794 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1795 -module_param(yaffs_traceMask, uint, 0644);
1796 -module_param(yaffs_wr_attempts, uint, 0644);
1797 -module_param(yaffs_auto_checkpoint, uint, 0644);
1798 -#else
1799 -MODULE_PARM(yaffs_traceMask, "i");
1800 -MODULE_PARM(yaffs_wr_attempts, "i");
1801 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1802 -#endif
1803 -
1804 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1805 -/* use iget and read_inode */
1806 -#define Y_IGET(sb, inum) iget((sb), (inum))
1807 -static void yaffs_read_inode(struct inode *inode);
1808 -
1809 -#else
1810 -/* Call local equivalent */
1811 -#define YAFFS_USE_OWN_IGET
1812 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1813 -
1814 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1815 -#endif
1816 -
1817 -/*#define T(x) printk x */
1818 -
1819 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1820 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1821 -#else
1822 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1823 -#endif
1824 -
1825 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1826 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1827 -
1828 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1829 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1830 -#else
1831 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1832 -#endif
1833 -
1834 -static void yaffs_put_super(struct super_block *sb);
1835 -
1836 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1837 - loff_t *pos);
1838 -static ssize_t yaffs_hold_space(struct file *f);
1839 -static void yaffs_release_space(struct file *f);
1840 -
1841 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1842 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1843 -#else
1844 -static int yaffs_file_flush(struct file *file);
1845 -#endif
1846 -
1847 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1848 - int datasync);
1849 -
1850 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1851 -
1852 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1853 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1854 - struct nameidata *n);
1855 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1856 - struct nameidata *n);
1857 -#else
1858 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1859 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1860 -#endif
1861 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1862 - struct dentry *dentry);
1863 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1864 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1865 - const char *symname);
1866 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1867 -
1868 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1869 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1870 - dev_t dev);
1871 -#else
1872 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1873 - int dev);
1874 -#endif
1875 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1876 - struct inode *new_dir, struct dentry *new_dentry);
1877 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1878 -
1879 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1880 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1881 -static void yaffs_write_super(struct super_block *sb);
1882 -#else
1883 -static int yaffs_sync_fs(struct super_block *sb);
1884 -static int yaffs_write_super(struct super_block *sb);
1885 -#endif
1886 -
1887 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1888 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1889 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1890 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1891 -#else
1892 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1893 -#endif
1894 -
1895 -#ifdef YAFFS_HAS_PUT_INODE
1896 -static void yaffs_put_inode(struct inode *inode);
1897 -#endif
1898 -
1899 -static void yaffs_delete_inode(struct inode *);
1900 -static void yaffs_clear_inode(struct inode *);
1901 -
1902 -static int yaffs_readpage(struct file *file, struct page *page);
1903 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1904 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1905 -#else
1906 -static int yaffs_writepage(struct page *page);
1907 -#endif
1908 -
1909 -
1910 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1911 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1912 - loff_t pos, unsigned len, unsigned flags,
1913 - struct page **pagep, void **fsdata);
1914 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1915 - loff_t pos, unsigned len, unsigned copied,
1916 - struct page *pg, void *fsdadata);
1917 -#else
1918 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1919 - unsigned offset, unsigned to);
1920 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1921 - unsigned to);
1922 -
1923 -#endif
1924 -
1925 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1926 - int buflen);
1927 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1928 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1929 -#else
1930 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1931 -#endif
1932 -
1933 -static struct address_space_operations yaffs_file_address_operations = {
1934 - .readpage = yaffs_readpage,
1935 - .writepage = yaffs_writepage,
1936 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1937 - .write_begin = yaffs_write_begin,
1938 - .write_end = yaffs_write_end,
1939 -#else
1940 - .prepare_write = yaffs_prepare_write,
1941 - .commit_write = yaffs_commit_write,
1942 -#endif
1943 -};
1944 -
1945 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1946 -static const struct file_operations yaffs_file_operations = {
1947 - .read = do_sync_read,
1948 - .write = do_sync_write,
1949 - .aio_read = generic_file_aio_read,
1950 - .aio_write = generic_file_aio_write,
1951 - .mmap = generic_file_mmap,
1952 - .flush = yaffs_file_flush,
1953 - .fsync = yaffs_sync_object,
1954 - .splice_read = generic_file_splice_read,
1955 - .splice_write = generic_file_splice_write,
1956 - .llseek = generic_file_llseek,
1957 -};
1958 -
1959 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1960 -
1961 -static const struct file_operations yaffs_file_operations = {
1962 - .read = do_sync_read,
1963 - .write = do_sync_write,
1964 - .aio_read = generic_file_aio_read,
1965 - .aio_write = generic_file_aio_write,
1966 - .mmap = generic_file_mmap,
1967 - .flush = yaffs_file_flush,
1968 - .fsync = yaffs_sync_object,
1969 - .sendfile = generic_file_sendfile,
1970 -};
1971 -
1972 -#else
1973 -
1974 -static const struct file_operations yaffs_file_operations = {
1975 - .read = generic_file_read,
1976 - .write = generic_file_write,
1977 - .mmap = generic_file_mmap,
1978 - .flush = yaffs_file_flush,
1979 - .fsync = yaffs_sync_object,
1980 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1981 - .sendfile = generic_file_sendfile,
1982 -#endif
1983 -};
1984 -#endif
1985 -
1986 -static const struct inode_operations yaffs_file_inode_operations = {
1987 - .setattr = yaffs_setattr,
1988 -};
1989 -
1990 -static const struct inode_operations yaffs_symlink_inode_operations = {
1991 - .readlink = yaffs_readlink,
1992 - .follow_link = yaffs_follow_link,
1993 - .setattr = yaffs_setattr,
1994 -};
1995 -
1996 -static const struct inode_operations yaffs_dir_inode_operations = {
1997 - .create = yaffs_create,
1998 - .lookup = yaffs_lookup,
1999 - .link = yaffs_link,
2000 - .unlink = yaffs_unlink,
2001 - .symlink = yaffs_symlink,
2002 - .mkdir = yaffs_mkdir,
2003 - .rmdir = yaffs_unlink,
2004 - .mknod = yaffs_mknod,
2005 - .rename = yaffs_rename,
2006 - .setattr = yaffs_setattr,
2007 -};
2008 -
2009 -static const struct file_operations yaffs_dir_operations = {
2010 - .read = generic_read_dir,
2011 - .readdir = yaffs_readdir,
2012 - .fsync = yaffs_sync_object,
2013 -};
2014 -
2015 -static const struct super_operations yaffs_super_ops = {
2016 - .statfs = yaffs_statfs,
2017 -
2018 -#ifndef YAFFS_USE_OWN_IGET
2019 - .read_inode = yaffs_read_inode,
2020 -#endif
2021 -#ifdef YAFFS_HAS_PUT_INODE
2022 - .put_inode = yaffs_put_inode,
2023 -#endif
2024 - .put_super = yaffs_put_super,
2025 - .delete_inode = yaffs_delete_inode,
2026 - .clear_inode = yaffs_clear_inode,
2027 - .sync_fs = yaffs_sync_fs,
2028 - .write_super = yaffs_write_super,
2029 -};
2030 -
2031 -static void yaffs_GrossLock(yaffs_Device *dev)
2032 -{
2033 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
2034 - down(&dev->grossLock);
2035 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
2036 -}
2037 -
2038 -static void yaffs_GrossUnlock(yaffs_Device *dev)
2039 -{
2040 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
2041 - up(&dev->grossLock);
2042 -}
2043 -
2044 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
2045 - int buflen)
2046 -{
2047 - unsigned char *alias;
2048 - int ret;
2049 -
2050 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2051 -
2052 - yaffs_GrossLock(dev);
2053 -
2054 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
2055 -
2056 - yaffs_GrossUnlock(dev);
2057 -
2058 - if (!alias)
2059 - return -ENOMEM;
2060 -
2061 - ret = vfs_readlink(dentry, buffer, buflen, alias);
2062 - kfree(alias);
2063 - return ret;
2064 -}
2065 -
2066 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2067 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
2068 -#else
2069 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
2070 -#endif
2071 -{
2072 - unsigned char *alias;
2073 - int ret;
2074 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2075 -
2076 - yaffs_GrossLock(dev);
2077 -
2078 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
2079 -
2080 - yaffs_GrossUnlock(dev);
2081 -
2082 - if (!alias) {
2083 - ret = -ENOMEM;
2084 - goto out;
2085 - }
2086 -
2087 - ret = vfs_follow_link(nd, alias);
2088 - kfree(alias);
2089 -out:
2090 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2091 - return ERR_PTR(ret);
2092 -#else
2093 - return ret;
2094 -#endif
2095 -}
2096 -
2097 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2098 - yaffs_Object *obj);
2099 -
2100 -/*
2101 - * Lookup is used to find objects in the fs
2102 - */
2103 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2104 -
2105 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
2106 - struct nameidata *n)
2107 -#else
2108 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
2109 -#endif
2110 -{
2111 - yaffs_Object *obj;
2112 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
2113 -
2114 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
2115 -
2116 - yaffs_GrossLock(dev);
2117 -
2118 - T(YAFFS_TRACE_OS,
2119 - ("yaffs_lookup for %d:%s\n",
2120 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
2121 -
2122 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
2123 - dentry->d_name.name);
2124 -
2125 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
2126 -
2127 - /* Can't hold gross lock when calling yaffs_get_inode() */
2128 - yaffs_GrossUnlock(dev);
2129 -
2130 - if (obj) {
2131 - T(YAFFS_TRACE_OS,
2132 - ("yaffs_lookup found %d\n", obj->objectId));
2133 -
2134 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2135 -
2136 - if (inode) {
2137 - T(YAFFS_TRACE_OS,
2138 - ("yaffs_loookup dentry \n"));
2139 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
2140 - * d_add even if NULL inode */
2141 -#if 0
2142 - /*dget(dentry); // try to solve directory bug */
2143 - d_add(dentry, inode);
2144 -
2145 - /* return dentry; */
2146 - return NULL;
2147 -#endif
2148 - }
2149 -
2150 - } else {
2151 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
2152 -
2153 - }
2154 -
2155 -/* added NCB for 2.5/6 compatability - forces add even if inode is
2156 - * NULL which creates dentry hash */
2157 - d_add(dentry, inode);
2158 -
2159 - return NULL;
2160 -}
2161 -
2162 -
2163 -#ifdef YAFFS_HAS_PUT_INODE
2164 -
2165 -/* For now put inode is just for debugging
2166 - * Put inode is called when the inode **structure** is put.
2167 - */
2168 -static void yaffs_put_inode(struct inode *inode)
2169 -{
2170 - T(YAFFS_TRACE_OS,
2171 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
2172 - atomic_read(&inode->i_count)));
2173 -
2174 -}
2175 -#endif
2176 -
2177 -/* clear is called to tell the fs to release any per-inode data it holds */
2178 -static void yaffs_clear_inode(struct inode *inode)
2179 -{
2180 - yaffs_Object *obj;
2181 - yaffs_Device *dev;
2182 -
2183 - obj = yaffs_InodeToObject(inode);
2184 -
2185 - T(YAFFS_TRACE_OS,
2186 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
2187 - atomic_read(&inode->i_count),
2188 - obj ? "object exists" : "null object"));
2189 -
2190 - if (obj) {
2191 - dev = obj->myDev;
2192 - yaffs_GrossLock(dev);
2193 -
2194 - /* Clear the association between the inode and
2195 - * the yaffs_Object.
2196 - */
2197 - obj->myInode = NULL;
2198 - yaffs_InodeToObjectLV(inode) = NULL;
2199 -
2200 - /* If the object freeing was deferred, then the real
2201 - * free happens now.
2202 - * This should fix the inode inconsistency problem.
2203 - */
2204 -
2205 - yaffs_HandleDeferedFree(obj);
2206 -
2207 - yaffs_GrossUnlock(dev);
2208 - }
2209 -
2210 -}
2211 -
2212 -/* delete is called when the link count is zero and the inode
2213 - * is put (ie. nobody wants to know about it anymore, time to
2214 - * delete the file).
2215 - * NB Must call clear_inode()
2216 - */
2217 -static void yaffs_delete_inode(struct inode *inode)
2218 -{
2219 - yaffs_Object *obj = yaffs_InodeToObject(inode);
2220 - yaffs_Device *dev;
2221 -
2222 - T(YAFFS_TRACE_OS,
2223 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
2224 - atomic_read(&inode->i_count),
2225 - obj ? "object exists" : "null object"));
2226 -
2227 - if (obj) {
2228 - dev = obj->myDev;
2229 - yaffs_GrossLock(dev);
2230 - yaffs_DeleteObject(obj);
2231 - yaffs_GrossUnlock(dev);
2232 - }
2233 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2234 - truncate_inode_pages(&inode->i_data, 0);
2235 -#endif
2236 - clear_inode(inode);
2237 -}
2238 -
2239 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2240 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
2241 -#else
2242 -static int yaffs_file_flush(struct file *file)
2243 -#endif
2244 -{
2245 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
2246 -
2247 - yaffs_Device *dev = obj->myDev;
2248 -
2249 - T(YAFFS_TRACE_OS,
2250 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
2251 - obj->dirty ? "dirty" : "clean"));
2252 -
2253 - yaffs_GrossLock(dev);
2254 -
2255 - yaffs_FlushFile(obj, 1);
2256 -
2257 - yaffs_GrossUnlock(dev);
2258 -
2259 - return 0;
2260 -}
2261 -
2262 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
2263 -{
2264 - /* Lifted from jffs2 */
2265 -
2266 - yaffs_Object *obj;
2267 - unsigned char *pg_buf;
2268 - int ret;
2269 -
2270 - yaffs_Device *dev;
2271 -
2272 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
2273 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
2274 - (unsigned)PAGE_CACHE_SIZE));
2275 -
2276 - obj = yaffs_DentryToObject(f->f_dentry);
2277 -
2278 - dev = obj->myDev;
2279 -
2280 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2281 - BUG_ON(!PageLocked(pg));
2282 -#else
2283 - if (!PageLocked(pg))
2284 - PAGE_BUG(pg);
2285 -#endif
2286 -
2287 - pg_buf = kmap(pg);
2288 - /* FIXME: Can kmap fail? */
2289 -
2290 - yaffs_GrossLock(dev);
2291 -
2292 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
2293 - pg->index << PAGE_CACHE_SHIFT,
2294 - PAGE_CACHE_SIZE);
2295 -
2296 - yaffs_GrossUnlock(dev);
2297 -
2298 - if (ret >= 0)
2299 - ret = 0;
2300 -
2301 - if (ret) {
2302 - ClearPageUptodate(pg);
2303 - SetPageError(pg);
2304 - } else {
2305 - SetPageUptodate(pg);
2306 - ClearPageError(pg);
2307 - }
2308 -
2309 - flush_dcache_page(pg);
2310 - kunmap(pg);
2311 -
2312 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
2313 - return ret;
2314 -}
2315 -
2316 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
2317 -{
2318 - int ret = yaffs_readpage_nolock(f, pg);
2319 - UnlockPage(pg);
2320 - return ret;
2321 -}
2322 -
2323 -static int yaffs_readpage(struct file *f, struct page *pg)
2324 -{
2325 - return yaffs_readpage_unlock(f, pg);
2326 -}
2327 -
2328 -/* writepage inspired by/stolen from smbfs */
2329 -
2330 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2331 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
2332 -#else
2333 -static int yaffs_writepage(struct page *page)
2334 -#endif
2335 -{
2336 - struct address_space *mapping = page->mapping;
2337 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
2338 - struct inode *inode;
2339 - unsigned long end_index;
2340 - char *buffer;
2341 - yaffs_Object *obj;
2342 - int nWritten = 0;
2343 - unsigned nBytes;
2344 -
2345 - if (!mapping)
2346 - BUG();
2347 - inode = mapping->host;
2348 - if (!inode)
2349 - BUG();
2350 -
2351 - if (offset > inode->i_size) {
2352 - T(YAFFS_TRACE_OS,
2353 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
2354 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
2355 - (unsigned)inode->i_size));
2356 - T(YAFFS_TRACE_OS,
2357 - (" -> don't care!!\n"));
2358 - unlock_page(page);
2359 - return 0;
2360 - }
2361 -
2362 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
2363 -
2364 - /* easy case */
2365 - if (page->index < end_index)
2366 - nBytes = PAGE_CACHE_SIZE;
2367 - else
2368 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
2369 -
2370 - get_page(page);
2371 -
2372 - buffer = kmap(page);
2373 -
2374 - obj = yaffs_InodeToObject(inode);
2375 - yaffs_GrossLock(obj->myDev);
2376 -
2377 - T(YAFFS_TRACE_OS,
2378 - ("yaffs_writepage at %08x, size %08x\n",
2379 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
2380 - T(YAFFS_TRACE_OS,
2381 - ("writepag0: obj = %05x, ino = %05x\n",
2382 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2383 -
2384 - nWritten = yaffs_WriteDataToFile(obj, buffer,
2385 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
2386 -
2387 - T(YAFFS_TRACE_OS,
2388 - ("writepag1: obj = %05x, ino = %05x\n",
2389 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2390 -
2391 - yaffs_GrossUnlock(obj->myDev);
2392 -
2393 - kunmap(page);
2394 - SetPageUptodate(page);
2395 - UnlockPage(page);
2396 - put_page(page);
2397 -
2398 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2399 -}
2400 -
2401 -
2402 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2403 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2404 - loff_t pos, unsigned len, unsigned flags,
2405 - struct page **pagep, void **fsdata)
2406 -{
2407 - struct page *pg = NULL;
2408 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2409 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2410 - uint32_t to = offset + len;
2411 -
2412 - int ret = 0;
2413 - int space_held = 0;
2414 -
2415 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2416 - /* Get a page */
2417 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2418 - pg = grab_cache_page_write_begin(mapping, index, flags);
2419 -#else
2420 - pg = __grab_cache_page(mapping, index);
2421 -#endif
2422 -
2423 - *pagep = pg;
2424 - if (!pg) {
2425 - ret = -ENOMEM;
2426 - goto out;
2427 - }
2428 - /* Get fs space */
2429 - space_held = yaffs_hold_space(filp);
2430 -
2431 - if (!space_held) {
2432 - ret = -ENOSPC;
2433 - goto out;
2434 - }
2435 -
2436 - /* Update page if required */
2437 -
2438 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2439 - ret = yaffs_readpage_nolock(filp, pg);
2440 -
2441 - if (ret)
2442 - goto out;
2443 -
2444 - /* Happy path return */
2445 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2446 -
2447 - return 0;
2448 -
2449 -out:
2450 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2451 - if (space_held)
2452 - yaffs_release_space(filp);
2453 - if (pg) {
2454 - unlock_page(pg);
2455 - page_cache_release(pg);
2456 - }
2457 - return ret;
2458 -}
2459 -
2460 -#else
2461 -
2462 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2463 - unsigned offset, unsigned to)
2464 -{
2465 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2466 -
2467 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2468 - return yaffs_readpage_nolock(f, pg);
2469 - return 0;
2470 -}
2471 -#endif
2472 -
2473 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2474 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2475 - loff_t pos, unsigned len, unsigned copied,
2476 - struct page *pg, void *fsdadata)
2477 -{
2478 - int ret = 0;
2479 - void *addr, *kva;
2480 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2481 -
2482 - kva = kmap(pg);
2483 - addr = kva + offset_into_page;
2484 -
2485 - T(YAFFS_TRACE_OS,
2486 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2487 - (unsigned) addr,
2488 - (int)pos, copied));
2489 -
2490 - ret = yaffs_file_write(filp, addr, copied, &pos);
2491 -
2492 - if (ret != copied) {
2493 - T(YAFFS_TRACE_OS,
2494 - ("yaffs_write_end not same size ret %d copied %d\n",
2495 - ret, copied));
2496 - SetPageError(pg);
2497 - ClearPageUptodate(pg);
2498 - } else {
2499 - SetPageUptodate(pg);
2500 - }
2501 -
2502 - kunmap(pg);
2503 -
2504 - yaffs_release_space(filp);
2505 - unlock_page(pg);
2506 - page_cache_release(pg);
2507 - return ret;
2508 -}
2509 -#else
2510 -
2511 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2512 - unsigned to)
2513 -{
2514 - void *addr, *kva;
2515 -
2516 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2517 - int nBytes = to - offset;
2518 - int nWritten;
2519 -
2520 - unsigned spos = pos;
2521 - unsigned saddr;
2522 -
2523 - kva = kmap(pg);
2524 - addr = kva + offset;
2525 -
2526 - saddr = (unsigned) addr;
2527 -
2528 - T(YAFFS_TRACE_OS,
2529 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2530 - saddr, spos, nBytes));
2531 -
2532 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2533 -
2534 - if (nWritten != nBytes) {
2535 - T(YAFFS_TRACE_OS,
2536 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2537 - nWritten, nBytes));
2538 - SetPageError(pg);
2539 - ClearPageUptodate(pg);
2540 - } else {
2541 - SetPageUptodate(pg);
2542 - }
2543 -
2544 - kunmap(pg);
2545 -
2546 - T(YAFFS_TRACE_OS,
2547 - ("yaffs_commit_write returning %d\n",
2548 - nWritten == nBytes ? 0 : nWritten));
2549 -
2550 - return nWritten == nBytes ? 0 : nWritten;
2551 -}
2552 -#endif
2553 -
2554 -
2555 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2556 -{
2557 - if (inode && obj) {
2558 -
2559 -
2560 - /* Check mode against the variant type and attempt to repair if broken. */
2561 - __u32 mode = obj->yst_mode;
2562 - switch (obj->variantType) {
2563 - case YAFFS_OBJECT_TYPE_FILE:
2564 - if (!S_ISREG(mode)) {
2565 - obj->yst_mode &= ~S_IFMT;
2566 - obj->yst_mode |= S_IFREG;
2567 - }
2568 -
2569 - break;
2570 - case YAFFS_OBJECT_TYPE_SYMLINK:
2571 - if (!S_ISLNK(mode)) {
2572 - obj->yst_mode &= ~S_IFMT;
2573 - obj->yst_mode |= S_IFLNK;
2574 - }
2575 -
2576 - break;
2577 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2578 - if (!S_ISDIR(mode)) {
2579 - obj->yst_mode &= ~S_IFMT;
2580 - obj->yst_mode |= S_IFDIR;
2581 - }
2582 -
2583 - break;
2584 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2585 - case YAFFS_OBJECT_TYPE_HARDLINK:
2586 - case YAFFS_OBJECT_TYPE_SPECIAL:
2587 - default:
2588 - /* TODO? */
2589 - break;
2590 - }
2591 -
2592 - inode->i_flags |= S_NOATIME;
2593 -
2594 - inode->i_ino = obj->objectId;
2595 - inode->i_mode = obj->yst_mode;
2596 - inode->i_uid = obj->yst_uid;
2597 - inode->i_gid = obj->yst_gid;
2598 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2599 - inode->i_blksize = inode->i_sb->s_blocksize;
2600 -#endif
2601 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2602 -
2603 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2604 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2605 - inode->i_atime.tv_nsec = 0;
2606 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2607 - inode->i_mtime.tv_nsec = 0;
2608 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2609 - inode->i_ctime.tv_nsec = 0;
2610 -#else
2611 - inode->i_rdev = obj->yst_rdev;
2612 - inode->i_atime = obj->yst_atime;
2613 - inode->i_mtime = obj->yst_mtime;
2614 - inode->i_ctime = obj->yst_ctime;
2615 -#endif
2616 - inode->i_size = yaffs_GetObjectFileLength(obj);
2617 - inode->i_blocks = (inode->i_size + 511) >> 9;
2618 -
2619 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2620 -
2621 - T(YAFFS_TRACE_OS,
2622 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2623 - inode->i_mode, inode->i_uid, inode->i_gid,
2624 - (int)inode->i_size, atomic_read(&inode->i_count)));
2625 -
2626 - switch (obj->yst_mode & S_IFMT) {
2627 - default: /* fifo, device or socket */
2628 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2629 - init_special_inode(inode, obj->yst_mode,
2630 - old_decode_dev(obj->yst_rdev));
2631 -#else
2632 - init_special_inode(inode, obj->yst_mode,
2633 - (dev_t) (obj->yst_rdev));
2634 -#endif
2635 - break;
2636 - case S_IFREG: /* file */
2637 - inode->i_op = &yaffs_file_inode_operations;
2638 - inode->i_fop = &yaffs_file_operations;
2639 - inode->i_mapping->a_ops =
2640 - &yaffs_file_address_operations;
2641 - break;
2642 - case S_IFDIR: /* directory */
2643 - inode->i_op = &yaffs_dir_inode_operations;
2644 - inode->i_fop = &yaffs_dir_operations;
2645 - break;
2646 - case S_IFLNK: /* symlink */
2647 - inode->i_op = &yaffs_symlink_inode_operations;
2648 - break;
2649 - }
2650 -
2651 - yaffs_InodeToObjectLV(inode) = obj;
2652 -
2653 - obj->myInode = inode;
2654 -
2655 - } else {
2656 - T(YAFFS_TRACE_OS,
2657 - ("yaffs_FileInode invalid parameters\n"));
2658 - }
2659 -
2660 -}
2661 -
2662 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2663 - yaffs_Object *obj)
2664 -{
2665 - struct inode *inode;
2666 -
2667 - if (!sb) {
2668 - T(YAFFS_TRACE_OS,
2669 - ("yaffs_get_inode for NULL super_block!!\n"));
2670 - return NULL;
2671 -
2672 - }
2673 -
2674 - if (!obj) {
2675 - T(YAFFS_TRACE_OS,
2676 - ("yaffs_get_inode for NULL object!!\n"));
2677 - return NULL;
2678 -
2679 - }
2680 -
2681 - T(YAFFS_TRACE_OS,
2682 - ("yaffs_get_inode for object %d\n", obj->objectId));
2683 -
2684 - inode = Y_IGET(sb, obj->objectId);
2685 - if (IS_ERR(inode))
2686 - return NULL;
2687 -
2688 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2689 - /* iget also increments the inode's i_count */
2690 - /* NB You can't be holding grossLock or deadlock will happen! */
2691 -
2692 - return inode;
2693 -}
2694 -
2695 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2696 - loff_t *pos)
2697 -{
2698 - yaffs_Object *obj;
2699 - int nWritten, ipos;
2700 - struct inode *inode;
2701 - yaffs_Device *dev;
2702 -
2703 - obj = yaffs_DentryToObject(f->f_dentry);
2704 -
2705 - dev = obj->myDev;
2706 -
2707 - yaffs_GrossLock(dev);
2708 -
2709 - inode = f->f_dentry->d_inode;
2710 -
2711 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2712 - ipos = inode->i_size;
2713 - else
2714 - ipos = *pos;
2715 -
2716 - if (!obj)
2717 - T(YAFFS_TRACE_OS,
2718 - ("yaffs_file_write: hey obj is null!\n"));
2719 - else
2720 - T(YAFFS_TRACE_OS,
2721 - ("yaffs_file_write about to write writing %zu bytes"
2722 - "to object %d at %d\n",
2723 - n, obj->objectId, ipos));
2724 -
2725 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2726 -
2727 - T(YAFFS_TRACE_OS,
2728 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2729 - n, nWritten, ipos));
2730 -
2731 - if (nWritten > 0) {
2732 - ipos += nWritten;
2733 - *pos = ipos;
2734 - if (ipos > inode->i_size) {
2735 - inode->i_size = ipos;
2736 - inode->i_blocks = (ipos + 511) >> 9;
2737 -
2738 - T(YAFFS_TRACE_OS,
2739 - ("yaffs_file_write size updated to %d bytes, "
2740 - "%d blocks\n",
2741 - ipos, (int)(inode->i_blocks)));
2742 - }
2743 -
2744 - }
2745 - yaffs_GrossUnlock(dev);
2746 - return nWritten == 0 ? -ENOSPC : nWritten;
2747 -}
2748 -
2749 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2750 -/* For now we just assume few parallel writes and check against a small number. */
2751 -/* Todo: need to do this with a counter to handle parallel reads better */
2752 -
2753 -static ssize_t yaffs_hold_space(struct file *f)
2754 -{
2755 - yaffs_Object *obj;
2756 - yaffs_Device *dev;
2757 -
2758 - int nFreeChunks;
2759 -
2760 -
2761 - obj = yaffs_DentryToObject(f->f_dentry);
2762 -
2763 - dev = obj->myDev;
2764 -
2765 - yaffs_GrossLock(dev);
2766 -
2767 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2768 -
2769 - yaffs_GrossUnlock(dev);
2770 -
2771 - return (nFreeChunks > 20) ? 1 : 0;
2772 -}
2773 -
2774 -static void yaffs_release_space(struct file *f)
2775 -{
2776 - yaffs_Object *obj;
2777 - yaffs_Device *dev;
2778 -
2779 -
2780 - obj = yaffs_DentryToObject(f->f_dentry);
2781 -
2782 - dev = obj->myDev;
2783 -
2784 - yaffs_GrossLock(dev);
2785 -
2786 -
2787 - yaffs_GrossUnlock(dev);
2788 -}
2789 -
2790 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2791 -{
2792 - yaffs_Object *obj;
2793 - yaffs_Device *dev;
2794 - struct inode *inode = f->f_dentry->d_inode;
2795 - unsigned long offset, curoffs;
2796 - struct ylist_head *i;
2797 - yaffs_Object *l;
2798 -
2799 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2800 -
2801 - obj = yaffs_DentryToObject(f->f_dentry);
2802 - dev = obj->myDev;
2803 -
2804 - yaffs_GrossLock(dev);
2805 -
2806 - offset = f->f_pos;
2807 -
2808 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2809 -
2810 - if (offset == 0) {
2811 - T(YAFFS_TRACE_OS,
2812 - ("yaffs_readdir: entry . ino %d \n",
2813 - (int)inode->i_ino));
2814 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2815 - goto out;
2816 - offset++;
2817 - f->f_pos++;
2818 - }
2819 - if (offset == 1) {
2820 - T(YAFFS_TRACE_OS,
2821 - ("yaffs_readdir: entry .. ino %d \n",
2822 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2823 - if (filldir(dirent, "..", 2, offset,
2824 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2825 - goto out;
2826 - offset++;
2827 - f->f_pos++;
2828 - }
2829 -
2830 - curoffs = 1;
2831 -
2832 - /* If the directory has changed since the open or last call to
2833 - readdir, rewind to after the 2 canned entries. */
2834 -
2835 - if (f->f_version != inode->i_version) {
2836 - offset = 2;
2837 - f->f_pos = offset;
2838 - f->f_version = inode->i_version;
2839 - }
2840 -
2841 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2842 - curoffs++;
2843 - if (curoffs >= offset) {
2844 - l = ylist_entry(i, yaffs_Object, siblings);
2845 -
2846 - yaffs_GetObjectName(l, name,
2847 - YAFFS_MAX_NAME_LENGTH + 1);
2848 - T(YAFFS_TRACE_OS,
2849 - ("yaffs_readdir: %s inode %d\n", name,
2850 - yaffs_GetObjectInode(l)));
2851 -
2852 - if (filldir(dirent,
2853 - name,
2854 - strlen(name),
2855 - offset,
2856 - yaffs_GetObjectInode(l),
2857 - yaffs_GetObjectType(l)) < 0)
2858 - goto up_and_out;
2859 -
2860 - offset++;
2861 - f->f_pos++;
2862 - }
2863 - }
2864 -
2865 -up_and_out:
2866 -out:
2867 - yaffs_GrossUnlock(dev);
2868 -
2869 - return 0;
2870 -}
2871 -
2872 -/*
2873 - * File creation. Allocate an inode, and we're done..
2874 - */
2875 -
2876 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2877 -#define YCRED(x) x
2878 -#else
2879 -#define YCRED(x) (x->cred)
2880 -#endif
2881 -
2882 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2883 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2884 - dev_t rdev)
2885 -#else
2886 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2887 - int rdev)
2888 -#endif
2889 -{
2890 - struct inode *inode;
2891 -
2892 - yaffs_Object *obj = NULL;
2893 - yaffs_Device *dev;
2894 -
2895 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2896 -
2897 - int error = -ENOSPC;
2898 - uid_t uid = YCRED(current)->fsuid;
2899 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2900 -
2901 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2902 - mode |= S_ISGID;
2903 -
2904 - if (parent) {
2905 - T(YAFFS_TRACE_OS,
2906 - ("yaffs_mknod: parent object %d type %d\n",
2907 - parent->objectId, parent->variantType));
2908 - } else {
2909 - T(YAFFS_TRACE_OS,
2910 - ("yaffs_mknod: could not get parent object\n"));
2911 - return -EPERM;
2912 - }
2913 -
2914 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2915 - "mode %x dev %x\n",
2916 - dentry->d_name.name, mode, rdev));
2917 -
2918 - dev = parent->myDev;
2919 -
2920 - yaffs_GrossLock(dev);
2921 -
2922 - switch (mode & S_IFMT) {
2923 - default:
2924 - /* Special (socket, fifo, device...) */
2925 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2926 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2927 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2928 - gid, old_encode_dev(rdev));
2929 -#else
2930 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2931 - gid, rdev);
2932 -#endif
2933 - break;
2934 - case S_IFREG: /* file */
2935 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2936 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2937 - gid);
2938 - break;
2939 - case S_IFDIR: /* directory */
2940 - T(YAFFS_TRACE_OS,
2941 - ("yaffs_mknod: making directory\n"));
2942 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2943 - uid, gid);
2944 - break;
2945 - case S_IFLNK: /* symlink */
2946 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2947 - obj = NULL; /* Do we ever get here? */
2948 - break;
2949 - }
2950 -
2951 - /* Can not call yaffs_get_inode() with gross lock held */
2952 - yaffs_GrossUnlock(dev);
2953 -
2954 - if (obj) {
2955 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2956 - d_instantiate(dentry, inode);
2957 - T(YAFFS_TRACE_OS,
2958 - ("yaffs_mknod created object %d count = %d\n",
2959 - obj->objectId, atomic_read(&inode->i_count)));
2960 - error = 0;
2961 - } else {
2962 - T(YAFFS_TRACE_OS,
2963 - ("yaffs_mknod failed making object\n"));
2964 - error = -ENOMEM;
2965 - }
2966 -
2967 - return error;
2968 -}
2969 -
2970 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2971 -{
2972 - int retVal;
2973 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2974 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2975 - return retVal;
2976 -}
2977 -
2978 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2979 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2980 - struct nameidata *n)
2981 -#else
2982 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2983 -#endif
2984 -{
2985 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
2986 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
2987 -}
2988 -
2989 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
2990 -{
2991 - int retVal;
2992 -
2993 - yaffs_Device *dev;
2994 -
2995 - T(YAFFS_TRACE_OS,
2996 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
2997 - dentry->d_name.name));
2998 -
2999 - dev = yaffs_InodeToObject(dir)->myDev;
3000 -
3001 - yaffs_GrossLock(dev);
3002 -
3003 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
3004 -
3005 - if (retVal == YAFFS_OK) {
3006 - dentry->d_inode->i_nlink--;
3007 - dir->i_version++;
3008 - yaffs_GrossUnlock(dev);
3009 - mark_inode_dirty(dentry->d_inode);
3010 - return 0;
3011 - }
3012 - yaffs_GrossUnlock(dev);
3013 - return -ENOTEMPTY;
3014 -}
3015 -
3016 -/*
3017 - * Create a link...
3018 - */
3019 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
3020 - struct dentry *dentry)
3021 -{
3022 - struct inode *inode = old_dentry->d_inode;
3023 - yaffs_Object *obj = NULL;
3024 - yaffs_Object *link = NULL;
3025 - yaffs_Device *dev;
3026 -
3027 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
3028 -
3029 - obj = yaffs_InodeToObject(inode);
3030 - dev = obj->myDev;
3031 -
3032 - yaffs_GrossLock(dev);
3033 -
3034 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
3035 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
3036 - obj);
3037 -
3038 - if (link) {
3039 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
3040 - d_instantiate(dentry, old_dentry->d_inode);
3041 - atomic_inc(&old_dentry->d_inode->i_count);
3042 - T(YAFFS_TRACE_OS,
3043 - ("yaffs_link link count %d i_count %d\n",
3044 - old_dentry->d_inode->i_nlink,
3045 - atomic_read(&old_dentry->d_inode->i_count)));
3046 - }
3047 -
3048 - yaffs_GrossUnlock(dev);
3049 -
3050 - if (link)
3051 - return 0;
3052 -
3053 - return -EPERM;
3054 -}
3055 -
3056 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
3057 - const char *symname)
3058 -{
3059 - yaffs_Object *obj;
3060 - yaffs_Device *dev;
3061 - uid_t uid = YCRED(current)->fsuid;
3062 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
3063 -
3064 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
3065 -
3066 - dev = yaffs_InodeToObject(dir)->myDev;
3067 - yaffs_GrossLock(dev);
3068 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
3069 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
3070 - yaffs_GrossUnlock(dev);
3071 -
3072 - if (obj) {
3073 - struct inode *inode;
3074 -
3075 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
3076 - d_instantiate(dentry, inode);
3077 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
3078 - return 0;
3079 - } else {
3080 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
3081 - }
3082 -
3083 - return -ENOMEM;
3084 -}
3085 -
3086 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
3087 - int datasync)
3088 -{
3089 -
3090 - yaffs_Object *obj;
3091 - yaffs_Device *dev;
3092 -
3093 - obj = yaffs_DentryToObject(dentry);
3094 -
3095 - dev = obj->myDev;
3096 -
3097 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
3098 - yaffs_GrossLock(dev);
3099 - yaffs_FlushFile(obj, 1);
3100 - yaffs_GrossUnlock(dev);
3101 - return 0;
3102 -}
3103 -
3104 -/*
3105 - * The VFS layer already does all the dentry stuff for rename.
3106 - *
3107 - * NB: POSIX says you can rename an object over an old object of the same name
3108 - */
3109 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
3110 - struct inode *new_dir, struct dentry *new_dentry)
3111 -{
3112 - yaffs_Device *dev;
3113 - int retVal = YAFFS_FAIL;
3114 - yaffs_Object *target;
3115 -
3116 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
3117 - dev = yaffs_InodeToObject(old_dir)->myDev;
3118 -
3119 - yaffs_GrossLock(dev);
3120 -
3121 - /* Check if the target is an existing directory that is not empty. */
3122 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
3123 - new_dentry->d_name.name);
3124 -
3125 -
3126 -
3127 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
3128 - !ylist_empty(&target->variant.directoryVariant.children)) {
3129 -
3130 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
3131 -
3132 - retVal = YAFFS_FAIL;
3133 - } else {
3134 - /* Now does unlinking internally using shadowing mechanism */
3135 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
3136 -
3137 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
3138 - old_dentry->d_name.name,
3139 - yaffs_InodeToObject(new_dir),
3140 - new_dentry->d_name.name);
3141 - }
3142 - yaffs_GrossUnlock(dev);
3143 -
3144 - if (retVal == YAFFS_OK) {
3145 - if (target) {
3146 - new_dentry->d_inode->i_nlink--;
3147 - mark_inode_dirty(new_dentry->d_inode);
3148 - }
3149 -
3150 - return 0;
3151 - } else {
3152 - return -ENOTEMPTY;
3153 - }
3154 -}
3155 -
3156 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
3157 -{
3158 - struct inode *inode = dentry->d_inode;
3159 - int error;
3160 - yaffs_Device *dev;
3161 -
3162 - T(YAFFS_TRACE_OS,
3163 - ("yaffs_setattr of object %d\n",
3164 - yaffs_InodeToObject(inode)->objectId));
3165 -
3166 - error = inode_change_ok(inode, attr);
3167 - if (error == 0) {
3168 - dev = yaffs_InodeToObject(inode)->myDev;
3169 - yaffs_GrossLock(dev);
3170 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
3171 - YAFFS_OK) {
3172 - error = 0;
3173 - } else {
3174 - error = -EPERM;
3175 - }
3176 - yaffs_GrossUnlock(dev);
3177 - if (!error)
3178 - error = inode_setattr(inode, attr);
3179 - }
3180 - return error;
3181 -}
3182 -
3183 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3184 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
3185 -{
3186 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
3187 - struct super_block *sb = dentry->d_sb;
3188 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3189 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
3190 -{
3191 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3192 -#else
3193 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
3194 -{
3195 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3196 -#endif
3197 -
3198 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
3199 -
3200 - yaffs_GrossLock(dev);
3201 -
3202 - buf->f_type = YAFFS_MAGIC;
3203 - buf->f_bsize = sb->s_blocksize;
3204 - buf->f_namelen = 255;
3205 -
3206 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
3207 - /* Do this if chunk size is not a power of 2 */
3208 -
3209 - uint64_t bytesInDev;
3210 - uint64_t bytesFree;
3211 -
3212 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
3213 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
3214 -
3215 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
3216 - buf->f_blocks = bytesInDev;
3217 -
3218 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
3219 - ((uint64_t)(dev->nDataBytesPerChunk));
3220 -
3221 - do_div(bytesFree, sb->s_blocksize);
3222 -
3223 - buf->f_bfree = bytesFree;
3224 -
3225 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
3226 -
3227 - buf->f_blocks =
3228 - (dev->endBlock - dev->startBlock + 1) *
3229 - dev->nChunksPerBlock /
3230 - (sb->s_blocksize / dev->nDataBytesPerChunk);
3231 - buf->f_bfree =
3232 - yaffs_GetNumberOfFreeChunks(dev) /
3233 - (sb->s_blocksize / dev->nDataBytesPerChunk);
3234 - } else {
3235 - buf->f_blocks =
3236 - (dev->endBlock - dev->startBlock + 1) *
3237 - dev->nChunksPerBlock *
3238 - (dev->nDataBytesPerChunk / sb->s_blocksize);
3239 -
3240 - buf->f_bfree =
3241 - yaffs_GetNumberOfFreeChunks(dev) *
3242 - (dev->nDataBytesPerChunk / sb->s_blocksize);
3243 - }
3244 -
3245 - buf->f_files = 0;
3246 - buf->f_ffree = 0;
3247 - buf->f_bavail = buf->f_bfree;
3248 -
3249 - yaffs_GrossUnlock(dev);
3250 - return 0;
3251 -}
3252 -
3253 -
3254 -static int yaffs_do_sync_fs(struct super_block *sb)
3255 -{
3256 -
3257 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3258 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
3259 -
3260 - if (sb->s_dirt) {
3261 - yaffs_GrossLock(dev);
3262 -
3263 - if (dev) {
3264 - yaffs_FlushEntireDeviceCache(dev);
3265 - yaffs_CheckpointSave(dev);
3266 - }
3267 -
3268 - yaffs_GrossUnlock(dev);
3269 -
3270 - sb->s_dirt = 0;
3271 - }
3272 - return 0;
3273 -}
3274 -
3275 -
3276 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3277 -static void yaffs_write_super(struct super_block *sb)
3278 -#else
3279 -static int yaffs_write_super(struct super_block *sb)
3280 -#endif
3281 -{
3282 -
3283 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
3284 - if (yaffs_auto_checkpoint >= 2)
3285 - yaffs_do_sync_fs(sb);
3286 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
3287 - return 0;
3288 -#endif
3289 -}
3290 -
3291 -
3292 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3293 -static int yaffs_sync_fs(struct super_block *sb, int wait)
3294 -#else
3295 -static int yaffs_sync_fs(struct super_block *sb)
3296 -#endif
3297 -{
3298 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
3299 -
3300 - if (yaffs_auto_checkpoint >= 1)
3301 - yaffs_do_sync_fs(sb);
3302 -
3303 - return 0;
3304 -}
3305 -
3306 -#ifdef YAFFS_USE_OWN_IGET
3307 -
3308 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
3309 -{
3310 - struct inode *inode;
3311 - yaffs_Object *obj;
3312 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3313 -
3314 - T(YAFFS_TRACE_OS,
3315 - ("yaffs_iget for %lu\n", ino));
3316 -
3317 - inode = iget_locked(sb, ino);
3318 - if (!inode)
3319 - return ERR_PTR(-ENOMEM);
3320 - if (!(inode->i_state & I_NEW))
3321 - return inode;
3322 -
3323 - /* NB This is called as a side effect of other functions, but
3324 - * we had to release the lock to prevent deadlocks, so
3325 - * need to lock again.
3326 - */
3327 -
3328 - yaffs_GrossLock(dev);
3329 -
3330 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
3331 -
3332 - yaffs_FillInodeFromObject(inode, obj);
3333 -
3334 - yaffs_GrossUnlock(dev);
3335 -
3336 - unlock_new_inode(inode);
3337 - return inode;
3338 -}
3339 -
3340 -#else
3341 -
3342 -static void yaffs_read_inode(struct inode *inode)
3343 -{
3344 - /* NB This is called as a side effect of other functions, but
3345 - * we had to release the lock to prevent deadlocks, so
3346 - * need to lock again.
3347 - */
3348 -
3349 - yaffs_Object *obj;
3350 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
3351 -
3352 - T(YAFFS_TRACE_OS,
3353 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
3354 -
3355 - yaffs_GrossLock(dev);
3356 -
3357 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
3358 -
3359 - yaffs_FillInodeFromObject(inode, obj);
3360 -
3361 - yaffs_GrossUnlock(dev);
3362 -}
3363 -
3364 -#endif
3365 -
3366 -static YLIST_HEAD(yaffs_dev_list);
3367 -
3368 -#if 0 /* not used */
3369 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
3370 -{
3371 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3372 -
3373 - if (*flags & MS_RDONLY) {
3374 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3375 -
3376 - T(YAFFS_TRACE_OS,
3377 - ("yaffs_remount_fs: %s: RO\n", dev->name));
3378 -
3379 - yaffs_GrossLock(dev);
3380 -
3381 - yaffs_FlushEntireDeviceCache(dev);
3382 -
3383 - yaffs_CheckpointSave(dev);
3384 -
3385 - if (mtd->sync)
3386 - mtd->sync(mtd);
3387 -
3388 - yaffs_GrossUnlock(dev);
3389 - } else {
3390 - T(YAFFS_TRACE_OS,
3391 - ("yaffs_remount_fs: %s: RW\n", dev->name));
3392 - }
3393 -
3394 - return 0;
3395 -}
3396 -#endif
3397 -
3398 -static void yaffs_put_super(struct super_block *sb)
3399 -{
3400 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3401 -
3402 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3403 -
3404 - yaffs_GrossLock(dev);
3405 -
3406 - yaffs_FlushEntireDeviceCache(dev);
3407 -
3408 - yaffs_CheckpointSave(dev);
3409 -
3410 - if (dev->putSuperFunc)
3411 - dev->putSuperFunc(sb);
3412 -
3413 - yaffs_Deinitialise(dev);
3414 -
3415 - yaffs_GrossUnlock(dev);
3416 -
3417 - /* we assume this is protected by lock_kernel() in mount/umount */
3418 - ylist_del(&dev->devList);
3419 -
3420 - if (dev->spareBuffer) {
3421 - YFREE(dev->spareBuffer);
3422 - dev->spareBuffer = NULL;
3423 - }
3424 -
3425 - kfree(dev);
3426 -}
3427 -
3428 -
3429 -static void yaffs_MTDPutSuper(struct super_block *sb)
3430 -{
3431 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3432 -
3433 - if (mtd->sync)
3434 - mtd->sync(mtd);
3435 -
3436 - put_mtd_device(mtd);
3437 -}
3438 -
3439 -
3440 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3441 -{
3442 - struct super_block *sb = (struct super_block *)vsb;
3443 -
3444 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3445 - if (sb)
3446 - sb->s_dirt = 1;
3447 -}
3448 -
3449 -typedef struct {
3450 - int inband_tags;
3451 - int skip_checkpoint_read;
3452 - int skip_checkpoint_write;
3453 - int no_cache;
3454 -} yaffs_options;
3455 -
3456 -#define MAX_OPT_LEN 20
3457 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3458 -{
3459 - char cur_opt[MAX_OPT_LEN + 1];
3460 - int p;
3461 - int error = 0;
3462 -
3463 - /* Parse through the options which is a comma seperated list */
3464 -
3465 - while (options_str && *options_str && !error) {
3466 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3467 - p = 0;
3468 -
3469 - while (*options_str && *options_str != ',') {
3470 - if (p < MAX_OPT_LEN) {
3471 - cur_opt[p] = *options_str;
3472 - p++;
3473 - }
3474 - options_str++;
3475 - }
3476 -
3477 - if (!strcmp(cur_opt, "inband-tags"))
3478 - options->inband_tags = 1;
3479 - else if (!strcmp(cur_opt, "no-cache"))
3480 - options->no_cache = 1;
3481 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3482 - options->skip_checkpoint_read = 1;
3483 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3484 - options->skip_checkpoint_write = 1;
3485 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3486 - options->skip_checkpoint_read = 1;
3487 - options->skip_checkpoint_write = 1;
3488 - } else {
3489 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3490 - cur_opt);
3491 - error = 1;
3492 - }
3493 - }
3494 -
3495 - return error;
3496 -}
3497 -
3498 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3499 - struct super_block *sb,
3500 - void *data, int silent)
3501 -{
3502 - int nBlocks;
3503 - struct inode *inode = NULL;
3504 - struct dentry *root;
3505 - yaffs_Device *dev = 0;
3506 - char devname_buf[BDEVNAME_SIZE + 1];
3507 - struct mtd_info *mtd;
3508 - int err;
3509 - char *data_str = (char *)data;
3510 -
3511 - yaffs_options options;
3512 -
3513 - sb->s_magic = YAFFS_MAGIC;
3514 - sb->s_op = &yaffs_super_ops;
3515 - sb->s_flags |= MS_NOATIME;
3516 -
3517 - if (!sb)
3518 - printk(KERN_INFO "yaffs: sb is NULL\n");
3519 - else if (!sb->s_dev)
3520 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3521 - else if (!yaffs_devname(sb, devname_buf))
3522 - printk(KERN_INFO "yaffs: devname is NULL\n");
3523 - else
3524 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3525 - sb->s_dev,
3526 - yaffs_devname(sb, devname_buf));
3527 -
3528 - if (!data_str)
3529 - data_str = "";
3530 -
3531 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3532 -
3533 - memset(&options, 0, sizeof(options));
3534 -
3535 - if (yaffs_parse_options(&options, data_str)) {
3536 - /* Option parsing failed */
3537 - return NULL;
3538 - }
3539 -
3540 -
3541 - sb->s_blocksize = PAGE_CACHE_SIZE;
3542 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3543 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3544 - T(YAFFS_TRACE_OS,
3545 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3546 -
3547 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3548 - T(YAFFS_TRACE_OS,
3549 - ("yaffs: Write verification disabled. All guarantees "
3550 - "null and void\n"));
3551 -#endif
3552 -
3553 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3554 - "\"%s\"\n",
3555 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3556 - yaffs_devname(sb, devname_buf)));
3557 -
3558 - /* Check it's an mtd device..... */
3559 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3560 - return NULL; /* This isn't an mtd device */
3561 -
3562 - /* Get the device */
3563 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3564 - if (!mtd) {
3565 - T(YAFFS_TRACE_ALWAYS,
3566 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3567 - MINOR(sb->s_dev)));
3568 - return NULL;
3569 - }
3570 - /* Check it's NAND */
3571 - if (mtd->type != MTD_NANDFLASH) {
3572 - T(YAFFS_TRACE_ALWAYS,
3573 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3574 - return NULL;
3575 - }
3576 -
3577 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3578 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3579 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3580 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3581 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3582 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3583 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3584 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3585 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3586 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3587 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3588 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3589 -#else
3590 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3591 -#endif
3592 -
3593 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3594 -
3595 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3596 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3597 - yaffsVersion = 2;
3598 - }
3599 -
3600 - /* Added NCB 26/5/2006 for completeness */
3601 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3602 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3603 - yaffsVersion = 1;
3604 - }
3605 -
3606 -#endif
3607 -
3608 - if (yaffsVersion == 2) {
3609 - /* Check for version 2 style functions */
3610 - if (!mtd->erase ||
3611 - !mtd->block_isbad ||
3612 - !mtd->block_markbad ||
3613 - !mtd->read ||
3614 - !mtd->write ||
3615 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3616 - !mtd->read_oob || !mtd->write_oob) {
3617 -#else
3618 - !mtd->write_ecc ||
3619 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3620 -#endif
3621 - T(YAFFS_TRACE_ALWAYS,
3622 - ("yaffs: MTD device does not support required "
3623 - "functions\n"));;
3624 - return NULL;
3625 - }
3626 -
3627 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3628 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3629 - !options.inband_tags) {
3630 - T(YAFFS_TRACE_ALWAYS,
3631 - ("yaffs: MTD device does not have the "
3632 - "right page sizes\n"));
3633 - return NULL;
3634 - }
3635 - } else {
3636 - /* Check for V1 style functions */
3637 - if (!mtd->erase ||
3638 - !mtd->read ||
3639 - !mtd->write ||
3640 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3641 - !mtd->read_oob || !mtd->write_oob) {
3642 -#else
3643 - !mtd->write_ecc ||
3644 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3645 -#endif
3646 - T(YAFFS_TRACE_ALWAYS,
3647 - ("yaffs: MTD device does not support required "
3648 - "functions\n"));;
3649 - return NULL;
3650 - }
3651 -
3652 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3653 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3654 - T(YAFFS_TRACE_ALWAYS,
3655 - ("yaffs: MTD device does not support have the "
3656 - "right page sizes\n"));
3657 - return NULL;
3658 - }
3659 - }
3660 -
3661 - /* OK, so if we got here, we have an MTD that's NAND and looks
3662 - * like it has the right capabilities
3663 - * Set the yaffs_Device up for mtd
3664 - */
3665 -
3666 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3667 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3668 -#else
3669 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3670 -#endif
3671 - if (!dev) {
3672 - /* Deep shit could not allocate device structure */
3673 - T(YAFFS_TRACE_ALWAYS,
3674 - ("yaffs_read_super: Failed trying to allocate "
3675 - "yaffs_Device. \n"));
3676 - return NULL;
3677 - }
3678 -
3679 - memset(dev, 0, sizeof(yaffs_Device));
3680 - dev->genericDevice = mtd;
3681 - dev->name = mtd->name;
3682 -
3683 - /* Set up the memory size parameters.... */
3684 -
3685 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3686 -
3687 - dev->startBlock = 0;
3688 - dev->endBlock = nBlocks - 1;
3689 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3690 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3691 - dev->nReservedBlocks = 5;
3692 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3693 - dev->inbandTags = options.inband_tags;
3694 -
3695 - /* ... and the functions. */
3696 - if (yaffsVersion == 2) {
3697 - dev->writeChunkWithTagsToNAND =
3698 - nandmtd2_WriteChunkWithTagsToNAND;
3699 - dev->readChunkWithTagsFromNAND =
3700 - nandmtd2_ReadChunkWithTagsFromNAND;
3701 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3702 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3703 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3704 - dev->isYaffs2 = 1;
3705 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3706 - dev->totalBytesPerChunk = mtd->writesize;
3707 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3708 -#else
3709 - dev->totalBytesPerChunk = mtd->oobblock;
3710 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3711 -#endif
3712 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3713 -
3714 - dev->startBlock = 0;
3715 - dev->endBlock = nBlocks - 1;
3716 - } else {
3717 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3718 - /* use the MTD interface in yaffs_mtdif1.c */
3719 - dev->writeChunkWithTagsToNAND =
3720 - nandmtd1_WriteChunkWithTagsToNAND;
3721 - dev->readChunkWithTagsFromNAND =
3722 - nandmtd1_ReadChunkWithTagsFromNAND;
3723 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3724 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3725 -#else
3726 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3727 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3728 -#endif
3729 - dev->isYaffs2 = 0;
3730 - }
3731 - /* ... and common functions */
3732 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3733 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3734 -
3735 - dev->putSuperFunc = yaffs_MTDPutSuper;
3736 -
3737 - dev->superBlock = (void *)sb;
3738 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3739 -
3740 -
3741 -#ifndef CONFIG_YAFFS_DOES_ECC
3742 - dev->useNANDECC = 1;
3743 -#endif
3744 -
3745 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3746 - dev->wideTnodesDisabled = 1;
3747 -#endif
3748 -
3749 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3750 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3751 -
3752 - /* we assume this is protected by lock_kernel() in mount/umount */
3753 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3754 -
3755 - init_MUTEX(&dev->grossLock);
3756 -
3757 - yaffs_GrossLock(dev);
3758 -
3759 - err = yaffs_GutsInitialise(dev);
3760 -
3761 - T(YAFFS_TRACE_OS,
3762 - ("yaffs_read_super: guts initialised %s\n",
3763 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3764 -
3765 - /* Release lock before yaffs_get_inode() */
3766 - yaffs_GrossUnlock(dev);
3767 -
3768 - /* Create root inode */
3769 - if (err == YAFFS_OK)
3770 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3771 - yaffs_Root(dev));
3772 -
3773 - if (!inode)
3774 - return NULL;
3775 -
3776 - inode->i_op = &yaffs_dir_inode_operations;
3777 - inode->i_fop = &yaffs_dir_operations;
3778 -
3779 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3780 -
3781 - root = d_alloc_root(inode);
3782 -
3783 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3784 -
3785 - if (!root) {
3786 - iput(inode);
3787 - return NULL;
3788 - }
3789 - sb->s_root = root;
3790 - sb->s_dirt = !dev->isCheckpointed;
3791 - T(YAFFS_TRACE_ALWAYS,
3792 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3793 -
3794 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3795 - return sb;
3796 -}
3797 -
3798 -
3799 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3800 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3801 - int silent)
3802 -{
3803 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3804 -}
3805 -
3806 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3807 -static int yaffs_read_super(struct file_system_type *fs,
3808 - int flags, const char *dev_name,
3809 - void *data, struct vfsmount *mnt)
3810 -{
3811 -
3812 - return get_sb_bdev(fs, flags, dev_name, data,
3813 - yaffs_internal_read_super_mtd, mnt);
3814 -}
3815 -#else
3816 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3817 - int flags, const char *dev_name,
3818 - void *data)
3819 -{
3820 -
3821 - return get_sb_bdev(fs, flags, dev_name, data,
3822 - yaffs_internal_read_super_mtd);
3823 -}
3824 -#endif
3825 -
3826 -static struct file_system_type yaffs_fs_type = {
3827 - .owner = THIS_MODULE,
3828 - .name = "yaffs",
3829 - .get_sb = yaffs_read_super,
3830 - .kill_sb = kill_block_super,
3831 - .fs_flags = FS_REQUIRES_DEV,
3832 -};
3833 -#else
3834 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3835 - int silent)
3836 -{
3837 - return yaffs_internal_read_super(1, sb, data, silent);
3838 -}
3839 -
3840 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3841 - FS_REQUIRES_DEV);
3842 -#endif
3843 -
3844 -
3845 -#ifdef CONFIG_YAFFS_YAFFS2
3846 -
3847 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3848 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3849 - int silent)
3850 -{
3851 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3852 -}
3853 -
3854 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3855 -static int yaffs2_read_super(struct file_system_type *fs,
3856 - int flags, const char *dev_name, void *data,
3857 - struct vfsmount *mnt)
3858 -{
3859 - return get_sb_bdev(fs, flags, dev_name, data,
3860 - yaffs2_internal_read_super_mtd, mnt);
3861 -}
3862 -#else
3863 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3864 - int flags, const char *dev_name,
3865 - void *data)
3866 -{
3867 -
3868 - return get_sb_bdev(fs, flags, dev_name, data,
3869 - yaffs2_internal_read_super_mtd);
3870 -}
3871 -#endif
3872 -
3873 -static struct file_system_type yaffs2_fs_type = {
3874 - .owner = THIS_MODULE,
3875 - .name = "yaffs2",
3876 - .get_sb = yaffs2_read_super,
3877 - .kill_sb = kill_block_super,
3878 - .fs_flags = FS_REQUIRES_DEV,
3879 -};
3880 -#else
3881 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3882 - void *data, int silent)
3883 -{
3884 - return yaffs_internal_read_super(2, sb, data, silent);
3885 -}
3886 -
3887 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3888 - FS_REQUIRES_DEV);
3889 -#endif
3890 -
3891 -#endif /* CONFIG_YAFFS_YAFFS2 */
3892 -
3893 -static struct proc_dir_entry *my_proc_entry;
3894 -
3895 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3896 -{
3897 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3898 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3899 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3900 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3901 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3902 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3903 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3904 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3905 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3906 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3907 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3908 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3909 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3910 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3911 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3912 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3913 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3914 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3915 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3916 - buf += sprintf(buf, "passiveGCs......... %d\n",
3917 - dev->passiveGarbageCollections);
3918 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3919 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3920 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3921 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3922 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3923 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3924 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3925 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3926 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3927 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3928 - buf +=
3929 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3930 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3931 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3932 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3933 -
3934 - return buf;
3935 -}
3936 -
3937 -static int yaffs_proc_read(char *page,
3938 - char **start,
3939 - off_t offset, int count, int *eof, void *data)
3940 -{
3941 - struct ylist_head *item;
3942 - char *buf = page;
3943 - int step = offset;
3944 - int n = 0;
3945 -
3946 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3947 - * We use 'offset' (*ppos) to indicate where we are in devList.
3948 - * This also assumes the user has posted a read buffer large
3949 - * enough to hold the complete output; but that's life in /proc.
3950 - */
3951 -
3952 - *(int *)start = 1;
3953 -
3954 - /* Print header first */
3955 - if (step == 0) {
3956 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3957 - "\n%s\n%s\n", yaffs_fs_c_version,
3958 - yaffs_guts_c_version);
3959 - }
3960 -
3961 - /* hold lock_kernel while traversing yaffs_dev_list */
3962 - lock_kernel();
3963 -
3964 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3965 - ylist_for_each(item, &yaffs_dev_list) {
3966 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3967 - if (n < step) {
3968 - n++;
3969 - continue;
3970 - }
3971 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3972 - buf = yaffs_dump_dev(buf, dev);
3973 - break;
3974 - }
3975 - unlock_kernel();
3976 -
3977 - return buf - page < count ? buf - page : count;
3978 -}
3979 -
3980 -/**
3981 - * Set the verbosity of the warnings and error messages.
3982 - *
3983 - * Note that the names can only be a..z or _ with the current code.
3984 - */
3985 -
3986 -static struct {
3987 - char *mask_name;
3988 - unsigned mask_bitfield;
3989 -} mask_flags[] = {
3990 - {"allocate", YAFFS_TRACE_ALLOCATE},
3991 - {"always", YAFFS_TRACE_ALWAYS},
3992 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3993 - {"buffers", YAFFS_TRACE_BUFFERS},
3994 - {"bug", YAFFS_TRACE_BUG},
3995 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
3996 - {"deletion", YAFFS_TRACE_DELETION},
3997 - {"erase", YAFFS_TRACE_ERASE},
3998 - {"error", YAFFS_TRACE_ERROR},
3999 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
4000 - {"gc", YAFFS_TRACE_GC},
4001 - {"mtd", YAFFS_TRACE_MTD},
4002 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
4003 - {"os", YAFFS_TRACE_OS},
4004 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
4005 - {"scan", YAFFS_TRACE_SCAN},
4006 - {"tracing", YAFFS_TRACE_TRACING},
4007 -
4008 - {"verify", YAFFS_TRACE_VERIFY},
4009 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
4010 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
4011 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
4012 -
4013 - {"write", YAFFS_TRACE_WRITE},
4014 - {"all", 0xffffffff},
4015 - {"none", 0},
4016 - {NULL, 0},
4017 -};
4018 -
4019 -#define MAX_MASK_NAME_LENGTH 40
4020 -static int yaffs_proc_write(struct file *file, const char *buf,
4021 - unsigned long count, void *data)
4022 -{
4023 - unsigned rg = 0, mask_bitfield;
4024 - char *end;
4025 - char *mask_name;
4026 - const char *x;
4027 - char substring[MAX_MASK_NAME_LENGTH + 1];
4028 - int i;
4029 - int done = 0;
4030 - int add, len = 0;
4031 - int pos = 0;
4032 -
4033 - rg = yaffs_traceMask;
4034 -
4035 - while (!done && (pos < count)) {
4036 - done = 1;
4037 - while ((pos < count) && isspace(buf[pos]))
4038 - pos++;
4039 -
4040 - switch (buf[pos]) {
4041 - case '+':
4042 - case '-':
4043 - case '=':
4044 - add = buf[pos];
4045 - pos++;
4046 - break;
4047 -
4048 - default:
4049 - add = ' ';
4050 - break;
4051 - }
4052 - mask_name = NULL;
4053 -
4054 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
4055 -
4056 - if (end > buf + pos) {
4057 - mask_name = "numeral";
4058 - len = end - (buf + pos);
4059 - pos += len;
4060 - done = 0;
4061 - } else {
4062 - for (x = buf + pos, i = 0;
4063 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
4064 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
4065 - substring[i] = *x;
4066 - substring[i] = '\0';
4067 -
4068 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
4069 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
4070 - mask_name = mask_flags[i].mask_name;
4071 - mask_bitfield = mask_flags[i].mask_bitfield;
4072 - done = 0;
4073 - break;
4074 - }
4075 - }
4076 - }
4077 -
4078 - if (mask_name != NULL) {
4079 - done = 0;
4080 - switch (add) {
4081 - case '-':
4082 - rg &= ~mask_bitfield;
4083 - break;
4084 - case '+':
4085 - rg |= mask_bitfield;
4086 - break;
4087 - case '=':
4088 - rg = mask_bitfield;
4089 - break;
4090 - default:
4091 - rg |= mask_bitfield;
4092 - break;
4093 - }
4094 - }
4095 - }
4096 -
4097 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
4098 -
4099 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
4100 -
4101 - if (rg & YAFFS_TRACE_ALWAYS) {
4102 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
4103 - char flag;
4104 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
4105 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
4106 - }
4107 - }
4108 -
4109 - return count;
4110 -}
4111 -
4112 -/* Stuff to handle installation of file systems */
4113 -struct file_system_to_install {
4114 - struct file_system_type *fst;
4115 - int installed;
4116 -};
4117 -
4118 -static struct file_system_to_install fs_to_install[] = {
4119 - {&yaffs_fs_type, 0},
4120 - {&yaffs2_fs_type, 0},
4121 - {NULL, 0}
4122 -};
4123 -
4124 -static int __init init_yaffs_fs(void)
4125 -{
4126 - int error = 0;
4127 - struct file_system_to_install *fsinst;
4128 -
4129 - T(YAFFS_TRACE_ALWAYS,
4130 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
4131 -
4132 - /* Install the proc_fs entry */
4133 - my_proc_entry = create_proc_entry("yaffs",
4134 - S_IRUGO | S_IFREG,
4135 - YPROC_ROOT);
4136 -
4137 - if (my_proc_entry) {
4138 - my_proc_entry->write_proc = yaffs_proc_write;
4139 - my_proc_entry->read_proc = yaffs_proc_read;
4140 - my_proc_entry->data = NULL;
4141 - } else
4142 - return -ENOMEM;
4143 -
4144 - /* Now add the file system entries */
4145 -
4146 - fsinst = fs_to_install;
4147 -
4148 - while (fsinst->fst && !error) {
4149 - error = register_filesystem(fsinst->fst);
4150 - if (!error)
4151 - fsinst->installed = 1;
4152 - fsinst++;
4153 - }
4154 -
4155 - /* Any errors? uninstall */
4156 - if (error) {
4157 - fsinst = fs_to_install;
4158 -
4159 - while (fsinst->fst) {
4160 - if (fsinst->installed) {
4161 - unregister_filesystem(fsinst->fst);
4162 - fsinst->installed = 0;
4163 - }
4164 - fsinst++;
4165 - }
4166 - }
4167 -
4168 - return error;
4169 -}
4170 -
4171 -static void __exit exit_yaffs_fs(void)
4172 -{
4173 -
4174 - struct file_system_to_install *fsinst;
4175 -
4176 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
4177 - " removing. \n"));
4178 -
4179 - remove_proc_entry("yaffs", YPROC_ROOT);
4180 -
4181 - fsinst = fs_to_install;
4182 -
4183 - while (fsinst->fst) {
4184 - if (fsinst->installed) {
4185 - unregister_filesystem(fsinst->fst);
4186 - fsinst->installed = 0;
4187 - }
4188 - fsinst++;
4189 - }
4190 -}
4191 -
4192 -module_init(init_yaffs_fs)
4193 -module_exit(exit_yaffs_fs)
4194 -
4195 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
4196 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
4197 -MODULE_LICENSE("GPL");
4198 --- a/fs/yaffs2/yaffs_getblockinfo.h
4199 +++ b/fs/yaffs2/yaffs_getblockinfo.h
4200 @@ -1,7 +1,7 @@
4201 /*
4202 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
4203 *
4204 - * Copyright (C) 2002-2007 Aleph One Ltd.
4205 + * Copyright (C) 2002-2010 Aleph One Ltd.
4206 * for Toby Churchill Ltd and Brightstar Engineering
4207 *
4208 * Created by Charles Manning <charles@aleph1.co.uk>
4209 @@ -17,18 +17,19 @@
4210 #define __YAFFS_GETBLOCKINFO_H__
4211
4212 #include "yaffs_guts.h"
4213 +#include "yaffs_trace.h"
4214
4215 /* Function to manipulate block info */
4216 -static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
4217 +static Y_INLINE yaffs_block_info_t *yaffs_get_block_info(yaffs_dev_t * dev, int blk)
4218 {
4219 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4220 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
4221 T(YAFFS_TRACE_ERROR,
4222 (TSTR
4223 ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
4224 blk));
4225 YBUG();
4226 }
4227 - return &dev->blockInfo[blk - dev->internalStartBlock];
4228 + return &dev->block_info[blk - dev->internal_start_block];
4229 }
4230
4231 #endif
4232 --- a/fs/yaffs2/yaffs_guts.c
4233 +++ b/fs/yaffs2/yaffs_guts.c
4234 @@ -1,7 +1,7 @@
4235 /*
4236 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4237 *
4238 - * Copyright (C) 2002-2007 Aleph One Ltd.
4239 + * Copyright (C) 2002-2010 Aleph One Ltd.
4240 * for Toby Churchill Ltd and Brightstar Engineering
4241 *
4242 * Created by Charles Manning <charles@aleph1.co.uk>
4243 @@ -10,11 +10,8 @@
4244 * it under the terms of the GNU General Public License version 2 as
4245 * published by the Free Software Foundation.
4246 */
4247 -
4248 -const char *yaffs_guts_c_version =
4249 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
4250 -
4251 #include "yportenv.h"
4252 +#include "yaffs_trace.h"
4253
4254 #include "yaffsinterface.h"
4255 #include "yaffs_guts.h"
4256 @@ -22,118 +19,109 @@ const char *yaffs_guts_c_version =
4257 #include "yaffs_getblockinfo.h"
4258
4259 #include "yaffs_tagscompat.h"
4260 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
4261 -#include "yaffs_qsort.h"
4262 -#endif
4263 +
4264 #include "yaffs_nand.h"
4265
4266 -#include "yaffs_checkptrw.h"
4267 +#include "yaffs_yaffs1.h"
4268 +#include "yaffs_yaffs2.h"
4269 +#include "yaffs_bitmap.h"
4270 +#include "yaffs_verify.h"
4271
4272 #include "yaffs_nand.h"
4273 #include "yaffs_packedtags2.h"
4274
4275 +#include "yaffs_nameval.h"
4276 +#include "yaffs_allocator.h"
4277
4278 -#define YAFFS_PASSIVE_GC_CHUNKS 2
4279 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
4280 +#define YAFFS_GC_GOOD_ENOUGH 2
4281 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
4282
4283 #include "yaffs_ecc.h"
4284
4285
4286 +
4287 /* Robustification (if it ever comes about...) */
4288 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
4289 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4290 +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block);
4291 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
4292 int erasedOk);
4293 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4294 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
4295 const __u8 *data,
4296 - const yaffs_ExtendedTags *tags);
4297 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4298 - const yaffs_ExtendedTags *tags);
4299 + const yaffs_ext_tags *tags);
4300 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
4301 + const yaffs_ext_tags *tags);
4302
4303 /* Other local prototypes */
4304 -static int yaffs_UnlinkObject(yaffs_Object *obj);
4305 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
4306 -
4307 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
4308 +static void yaffs_update_parent(yaffs_obj_t *obj);
4309 +static int yaffs_unlink_obj(yaffs_obj_t *obj);
4310 +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj);
4311
4312 -static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
4313 +static int yaffs_write_new_chunk(yaffs_dev_t *dev,
4314 const __u8 *buffer,
4315 - yaffs_ExtendedTags *tags,
4316 + yaffs_ext_tags *tags,
4317 int useReserve);
4318 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
4319 - int chunkInNAND, int inScan);
4320
4321 -static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
4322 - yaffs_ObjectType type);
4323 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
4324 - yaffs_Object *obj);
4325 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
4326 - int force, int isShrink, int shadows);
4327 -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
4328 -static int yaffs_CheckStructures(void);
4329 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
4330 - int chunkOffset, int *limit);
4331 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
4332 -
4333 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
4334
4335 +static yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
4336 + yaffs_obj_type type);
4337
4338 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4339 - int chunkInNAND);
4340
4341 -static int yaffs_UnlinkWorker(yaffs_Object *obj);
4342 +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod);
4343
4344 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
4345 - int chunkInObject);
4346 +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj);
4347 +static int yaffs_check_structures(void);
4348 +static int yaffs_generic_obj_del(yaffs_obj_t *in);
4349 +
4350 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
4351 + int nand_chunk);
4352
4353 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
4354 - yaffs_BlockInfo **blockUsedPtr);
4355 +static int yaffs_unlink_worker(yaffs_obj_t *obj);
4356
4357 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
4358 +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
4359 + int chunkInObject);
4360
4361 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
4362 +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
4363 + yaffs_block_info_t **blockUsedPtr);
4364
4365 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
4366 -#ifdef YAFFS_PARANOID
4367 -static int yaffs_CheckFileSanity(yaffs_Object *in);
4368 -#else
4369 -#define yaffs_CheckFileSanity(in)
4370 -#endif
4371 +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in);
4372 +
4373 +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in);
4374 +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id);
4375
4376 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
4377 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
4378 +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
4379 + yaffs_ext_tags *tags);
4380
4381 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
4382 +static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
4383 + int nand_chunk,
4384 + const __u8 *data,
4385 + yaffs_ext_tags *tags);
4386
4387 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
4388 - yaffs_ExtendedTags *tags);
4389
4390 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4391 - unsigned pos);
4392 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4393 - yaffs_FileStructure *fStruct,
4394 - __u32 chunkId);
4395 +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
4396 +static void yaffs_load_oh_from_name(yaffs_dev_t *dev,YCHAR *ohName, const YCHAR *name);
4397
4398
4399 /* Function to calculate chunk and offset */
4400
4401 -static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
4402 +static void yaffs_addr_to_chunk(yaffs_dev_t *dev, loff_t addr, int *chunkOut,
4403 __u32 *offsetOut)
4404 {
4405 int chunk;
4406 __u32 offset;
4407
4408 - chunk = (__u32)(addr >> dev->chunkShift);
4409 + chunk = (__u32)(addr >> dev->chunk_shift);
4410
4411 - if (dev->chunkDiv == 1) {
4412 + if (dev->chunk_div == 1) {
4413 /* easy power of 2 case */
4414 - offset = (__u32)(addr & dev->chunkMask);
4415 + offset = (__u32)(addr & dev->chunk_mask);
4416 } else {
4417 /* Non power-of-2 case */
4418
4419 loff_t chunkBase;
4420
4421 - chunk /= dev->chunkDiv;
4422 + chunk /= dev->chunk_div;
4423
4424 - chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;
4425 + chunkBase = ((loff_t)chunk) * dev->data_bytes_per_chunk;
4426 offset = (__u32)(addr - chunkBase);
4427 }
4428
4429 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
4430
4431 static __u32 Shifts(__u32 x)
4432 {
4433 - int nShifts;
4434 + __u32 nShifts;
4435
4436 nShifts = 0;
4437
4438 @@ -193,49 +181,49 @@ static __u32 Shifts(__u32 x)
4439 * Temporary buffer manipulations.
4440 */
4441
4442 -static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)
4443 +static int yaffs_init_tmp_buffers(yaffs_dev_t *dev)
4444 {
4445 int i;
4446 __u8 *buf = (__u8 *)1;
4447
4448 - memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer));
4449 + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
4450
4451 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
4452 - dev->tempBuffer[i].line = 0; /* not in use */
4453 - dev->tempBuffer[i].buffer = buf =
4454 - YMALLOC_DMA(dev->totalBytesPerChunk);
4455 + dev->temp_buffer[i].line = 0; /* not in use */
4456 + dev->temp_buffer[i].buffer = buf =
4457 + YMALLOC_DMA(dev->param.total_bytes_per_chunk);
4458 }
4459
4460 return buf ? YAFFS_OK : YAFFS_FAIL;
4461 }
4462
4463 -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo)
4464 +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no)
4465 {
4466 int i, j;
4467
4468 - dev->tempInUse++;
4469 - if (dev->tempInUse > dev->maxTemp)
4470 - dev->maxTemp = dev->tempInUse;
4471 + dev->temp_in_use++;
4472 + if (dev->temp_in_use > dev->max_temp)
4473 + dev->max_temp = dev->temp_in_use;
4474
4475 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4476 - if (dev->tempBuffer[i].line == 0) {
4477 - dev->tempBuffer[i].line = lineNo;
4478 - if ((i + 1) > dev->maxTemp) {
4479 - dev->maxTemp = i + 1;
4480 + if (dev->temp_buffer[i].line == 0) {
4481 + dev->temp_buffer[i].line = line_no;
4482 + if ((i + 1) > dev->max_temp) {
4483 + dev->max_temp = i + 1;
4484 for (j = 0; j <= i; j++)
4485 - dev->tempBuffer[j].maxLine =
4486 - dev->tempBuffer[j].line;
4487 + dev->temp_buffer[j].max_line =
4488 + dev->temp_buffer[j].line;
4489 }
4490
4491 - return dev->tempBuffer[i].buffer;
4492 + return dev->temp_buffer[i].buffer;
4493 }
4494 }
4495
4496 T(YAFFS_TRACE_BUFFERS,
4497 (TSTR("Out of temp buffers at line %d, other held by lines:"),
4498 - lineNo));
4499 + line_no));
4500 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
4501 - T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
4502 + T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->temp_buffer[i].line));
4503
4504 T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
4505
4506 @@ -244,21 +232,21 @@ __u8 *yaffs_GetTempBuffer(yaffs_Device *
4507 * This is not good.
4508 */
4509
4510 - dev->unmanagedTempAllocations++;
4511 - return YMALLOC(dev->nDataBytesPerChunk);
4512 + dev->unmanaged_buffer_allocs++;
4513 + return YMALLOC(dev->data_bytes_per_chunk);
4514
4515 }
4516
4517 -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer,
4518 - int lineNo)
4519 +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer,
4520 + int line_no)
4521 {
4522 int i;
4523
4524 - dev->tempInUse--;
4525 + dev->temp_in_use--;
4526
4527 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4528 - if (dev->tempBuffer[i].buffer == buffer) {
4529 - dev->tempBuffer[i].line = 0;
4530 + if (dev->temp_buffer[i].buffer == buffer) {
4531 + dev->temp_buffer[i].line = 0;
4532 return;
4533 }
4534 }
4535 @@ -267,9 +255,9 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic
4536 /* assume it is an unmanaged one. */
4537 T(YAFFS_TRACE_BUFFERS,
4538 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
4539 - lineNo));
4540 + line_no));
4541 YFREE(buffer);
4542 - dev->unmanagedTempDeallocations++;
4543 + dev->unmanaged_buffer_deallocs++;
4544 }
4545
4546 }
4547 @@ -277,21 +265,21 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic
4548 /*
4549 * Determine if we have a managed buffer.
4550 */
4551 -int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)
4552 +int yaffs_is_managed_tmp_buffer(yaffs_dev_t *dev, const __u8 *buffer)
4553 {
4554 int i;
4555
4556 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4557 - if (dev->tempBuffer[i].buffer == buffer)
4558 + if (dev->temp_buffer[i].buffer == buffer)
4559 return 1;
4560 }
4561
4562 - for (i = 0; i < dev->nShortOpCaches; i++) {
4563 - if (dev->srCache[i].data == buffer)
4564 + for (i = 0; i < dev->param.n_caches; i++) {
4565 + if (dev->cache[i].data == buffer)
4566 return 1;
4567 }
4568
4569 - if (buffer == dev->checkpointBuffer)
4570 + if (buffer == dev->checkpt_buffer)
4571 return 1;
4572
4573 T(YAFFS_TRACE_ALWAYS,
4574 @@ -299,6397 +287,4205 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
4575 return 0;
4576 }
4577
4578 -
4579 -
4580 /*
4581 - * Chunk bitmap manipulations
4582 + * Verification code
4583 */
4584
4585 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
4586 -{
4587 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4588 - T(YAFFS_TRACE_ERROR,
4589 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4590 - blk));
4591 - YBUG();
4592 - }
4593 - return dev->chunkBits +
4594 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4595 -}
4596
4597 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4598 -{
4599 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4600 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4601 - T(YAFFS_TRACE_ERROR,
4602 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4603 - blk, chunk));
4604 - YBUG();
4605 - }
4606 -}
4607
4608 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4609 -{
4610 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4611
4612 - memset(blkBits, 0, dev->chunkBitmapStride);
4613 -}
4614 +/*
4615 + * Simple hash function. Needs to have a reasonable spread
4616 + */
4617
4618 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4619 +static Y_INLINE int yaffs_hash_fn(int n)
4620 {
4621 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4622 -
4623 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4624 -
4625 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4626 + n = abs(n);
4627 + return n % YAFFS_NOBJECT_BUCKETS;
4628 }
4629
4630 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4631 -{
4632 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4633 -
4634 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4635 -
4636 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4637 -}
4638 +/*
4639 + * Access functions to useful fake objects.
4640 + * Note that root might have a presence in NAND if permissions are set.
4641 + */
4642
4643 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4644 +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev)
4645 {
4646 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4647 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4648 -
4649 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4650 + return dev->root_dir;
4651 }
4652
4653 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4654 +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev)
4655 {
4656 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4657 - int i;
4658 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4659 - if (*blkBits)
4660 - return 1;
4661 - blkBits++;
4662 - }
4663 - return 0;
4664 + return dev->lost_n_found;
4665 }
4666
4667 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4668 -{
4669 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4670 - int i;
4671 - int n = 0;
4672 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4673 - __u8 x = *blkBits;
4674 - while (x) {
4675 - if (x & 1)
4676 - n++;
4677 - x >>= 1;
4678 - }
4679 -
4680 - blkBits++;
4681 - }
4682 - return n;
4683 -}
4684
4685 /*
4686 - * Verification code
4687 + * Erased NAND checking functions
4688 */
4689
4690 -static int yaffs_SkipVerification(yaffs_Device *dev)
4691 -{
4692 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4693 -}
4694 -
4695 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4696 -{
4697 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4698 -}
4699 -
4700 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4701 +int yaffs_check_ff(__u8 *buffer, int n_bytes)
4702 {
4703 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4704 + /* Horrible, slow implementation */
4705 + while (n_bytes--) {
4706 + if (*buffer != 0xFF)
4707 + return 0;
4708 + buffer++;
4709 + }
4710 + return 1;
4711 }
4712
4713 -static const char *blockStateName[] = {
4714 -"Unknown",
4715 -"Needs scanning",
4716 -"Scanning",
4717 -"Empty",
4718 -"Allocating",
4719 -"Full",
4720 -"Dirty",
4721 -"Checkpoint",
4722 -"Collecting",
4723 -"Dead"
4724 -};
4725 -
4726 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4727 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
4728 + int nand_chunk)
4729 {
4730 - int actuallyUsed;
4731 - int inUse;
4732 + int retval = YAFFS_OK;
4733 + __u8 *data = yaffs_get_temp_buffer(dev, __LINE__);
4734 + yaffs_ext_tags tags;
4735 + int result;
4736
4737 - if (yaffs_SkipVerification(dev))
4738 - return;
4739 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
4740
4741 - /* Report illegal runtime states */
4742 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4743 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4744 + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
4745 + retval = YAFFS_FAIL;
4746
4747 - switch (bi->blockState) {
4748 - case YAFFS_BLOCK_STATE_UNKNOWN:
4749 - case YAFFS_BLOCK_STATE_SCANNING:
4750 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4751 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4752 - n, blockStateName[bi->blockState]));
4753 + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || tags.chunk_used) {
4754 + T(YAFFS_TRACE_NANDACCESS,
4755 + (TSTR("Chunk %d not erased" TENDSTR), nand_chunk));
4756 + retval = YAFFS_FAIL;
4757 }
4758
4759 - /* Check pages in use and soft deletions are legal */
4760 -
4761 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4762 -
4763 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4764 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4765 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4766 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4767 - n, bi->pagesInUse, bi->softDeletions));
4768 -
4769 + yaffs_release_temp_buffer(dev, data, __LINE__);
4770
4771 - /* Check chunk bitmap legal */
4772 - inUse = yaffs_CountChunkBits(dev, n);
4773 - if (inUse != bi->pagesInUse)
4774 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4775 - n, bi->pagesInUse, inUse));
4776 + return retval;
4777
4778 - /* Check that the sequence number is valid.
4779 - * Ten million is legal, but is very unlikely
4780 - */
4781 - if (dev->isYaffs2 &&
4782 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4783 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4784 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4785 - n, bi->sequenceNumber));
4786 }
4787
4788 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4789 - int n)
4790 +
4791 +static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
4792 + int nand_chunk,
4793 + const __u8 *data,
4794 + yaffs_ext_tags *tags)
4795 {
4796 - yaffs_VerifyBlock(dev, bi, n);
4797 + int retval = YAFFS_OK;
4798 + yaffs_ext_tags tempTags;
4799 + __u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__);
4800 + int result;
4801 +
4802 + result = yaffs_rd_chunk_tags_nand(dev,nand_chunk,buffer,&tempTags);
4803 + if(memcmp(buffer,data,dev->data_bytes_per_chunk) ||
4804 + tempTags.obj_id != tags->obj_id ||
4805 + tempTags.chunk_id != tags->chunk_id ||
4806 + tempTags.n_bytes != tags->n_bytes)
4807 + retval = YAFFS_FAIL;
4808
4809 - /* After collection the block should be in the erased state */
4810 - /* This will need to change if we do partial gc */
4811 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
4812
4813 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4814 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4815 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4816 - n, bi->blockState));
4817 - }
4818 + return retval;
4819 }
4820
4821 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4822 +static int yaffs_write_new_chunk(struct yaffs_dev_s *dev,
4823 + const __u8 *data,
4824 + yaffs_ext_tags *tags,
4825 + int useReserve)
4826 {
4827 - int i;
4828 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4829 - int nIllegalBlockStates = 0;
4830 -
4831 - if (yaffs_SkipVerification(dev))
4832 - return;
4833 -
4834 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4835 -
4836 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4837 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4838 - yaffs_VerifyBlock(dev, bi, i);
4839 -
4840 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4841 - nBlocksPerState[bi->blockState]++;
4842 - else
4843 - nIllegalBlockStates++;
4844 - }
4845 + int attempts = 0;
4846 + int writeOk = 0;
4847 + int chunk;
4848
4849 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4850 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4851 + yaffs2_checkpt_invalidate(dev);
4852
4853 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4854 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4855 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4856 + do {
4857 + yaffs_block_info_t *bi = 0;
4858 + int erasedOk = 0;
4859
4860 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4861 - T(YAFFS_TRACE_VERIFY,
4862 - (TSTR("%s %d blocks"TENDSTR),
4863 - blockStateName[i], nBlocksPerState[i]));
4864 + chunk = yaffs_alloc_chunk(dev, useReserve, &bi);
4865 + if (chunk < 0) {
4866 + /* no space */
4867 + break;
4868 + }
4869
4870 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4871 - T(YAFFS_TRACE_VERIFY,
4872 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4873 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4874 + /* First check this chunk is erased, if it needs
4875 + * checking. The checking policy (unless forced
4876 + * always on) is as follows:
4877 + *
4878 + * Check the first page we try to write in a block.
4879 + * If the check passes then we don't need to check any
4880 + * more. If the check fails, we check again...
4881 + * If the block has been erased, we don't need to check.
4882 + *
4883 + * However, if the block has been prioritised for gc,
4884 + * then we think there might be something odd about
4885 + * this block and stop using it.
4886 + *
4887 + * Rationale: We should only ever see chunks that have
4888 + * not been erased if there was a partially written
4889 + * chunk due to power loss. This checking policy should
4890 + * catch that case with very few checks and thus save a
4891 + * lot of checks that are most likely not needed.
4892 + *
4893 + * Mods to the above
4894 + * If an erase check fails or the write fails we skip the
4895 + * rest of the block.
4896 + */
4897
4898 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4899 - T(YAFFS_TRACE_VERIFY,
4900 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4901 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4902 + /* let's give it a try */
4903 + attempts++;
4904
4905 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4906 - T(YAFFS_TRACE_VERIFY,
4907 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4908 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4909 + if(dev->param.always_check_erased)
4910 + bi->skip_erased_check = 0;
4911
4912 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4913 + if (!bi->skip_erased_check) {
4914 + erasedOk = yaffs_check_chunk_erased(dev, chunk);
4915 + if (erasedOk != YAFFS_OK) {
4916 + T(YAFFS_TRACE_ERROR,
4917 + (TSTR("**>> yaffs chunk %d was not erased"
4918 + TENDSTR), chunk));
4919
4920 -}
4921 + /* If not erased, delete this one,
4922 + * skip rest of block and
4923 + * try another chunk */
4924 + yaffs_chunk_del(dev,chunk,1,__LINE__);
4925 + yaffs_skip_rest_of_block(dev);
4926 + continue;
4927 + }
4928 + }
4929
4930 -/*
4931 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4932 - * case those tests will not be performed.
4933 - */
4934 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4935 -{
4936 - if (obj && yaffs_SkipVerification(obj->myDev))
4937 - return;
4938 + writeOk = yaffs_wr_chunk_tags_nand(dev, chunk,
4939 + data, tags);
4940
4941 - if (!(tags && obj && oh)) {
4942 - T(YAFFS_TRACE_VERIFY,
4943 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4944 - (__u32)tags, (__u32)obj, (__u32)oh));
4945 - return;
4946 - }
4947 + if(!bi->skip_erased_check)
4948 + writeOk = yaffs_verify_chunk_written(dev, chunk, data, tags);
4949
4950 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4951 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4952 - T(YAFFS_TRACE_VERIFY,
4953 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4954 - tags->objectId, oh->type));
4955 + if (writeOk != YAFFS_OK) {
4956 + /* Clean up aborted write, skip to next block and
4957 + * try another chunk */
4958 + yaffs_handle_chunk_wr_error(dev, chunk, erasedOk);
4959 + continue;
4960 + }
4961
4962 - if (tags->objectId != obj->objectId)
4963 - T(YAFFS_TRACE_VERIFY,
4964 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4965 - tags->objectId, obj->objectId));
4966 + bi->skip_erased_check = 1;
4967
4968 + /* Copy the data into the robustification buffer */
4969 + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
4970
4971 - /*
4972 - * Check that the object's parent ids match if parentCheck requested.
4973 - *
4974 - * Tests do not apply to the root object.
4975 - */
4976 + } while (writeOk != YAFFS_OK &&
4977 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4978
4979 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4980 - T(YAFFS_TRACE_VERIFY,
4981 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4982 - tags->objectId, oh->parentObjectId));
4983 + if (!writeOk)
4984 + chunk = -1;
4985
4986 - if (parentCheck && obj->parent &&
4987 - oh->parentObjectId != obj->parent->objectId &&
4988 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
4989 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
4990 - T(YAFFS_TRACE_VERIFY,
4991 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
4992 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
4993 + if (attempts > 1) {
4994 + T(YAFFS_TRACE_ERROR,
4995 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
4996 + attempts));
4997
4998 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
4999 - T(YAFFS_TRACE_VERIFY,
5000 - (TSTR("Obj %d header name is NULL"TENDSTR),
5001 - obj->objectId));
5002 + dev->n_retired_writes += (attempts - 1);
5003 + }
5004
5005 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
5006 - T(YAFFS_TRACE_VERIFY,
5007 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
5008 - obj->objectId));
5009 + return chunk;
5010 }
5011
5012
5013 +
5014 +/*
5015 + * Block retiring for handling a broken block.
5016 + */
5017
5018 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
5019 - __u32 level, int chunkOffset)
5020 +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block)
5021 {
5022 - int i;
5023 - yaffs_Device *dev = obj->myDev;
5024 - int ok = 1;
5025 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
5026
5027 - if (tn) {
5028 - if (level > 0) {
5029 + yaffs2_checkpt_invalidate(dev);
5030 +
5031 + yaffs2_clear_oldest_dirty_seq(dev,bi);
5032
5033 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
5034 - if (tn->internal[i]) {
5035 - ok = yaffs_VerifyTnodeWorker(obj,
5036 - tn->internal[i],
5037 - level - 1,
5038 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
5039 - }
5040 - }
5041 - } else if (level == 0) {
5042 - yaffs_ExtendedTags tags;
5043 - __u32 objectId = obj->objectId;
5044 + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
5045 + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
5046 + T(YAFFS_TRACE_ALWAYS, (TSTR(
5047 + "yaffs: Failed to mark bad and erase block %d"
5048 + TENDSTR), flash_block));
5049 + } else {
5050 + yaffs_ext_tags tags;
5051 + int chunk_id = flash_block * dev->param.chunks_per_block;
5052
5053 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
5054 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
5055
5056 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
5057 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5058 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
5059 + yaffs_init_tags(&tags);
5060 + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
5061 + if (dev->param.write_chunk_tags_fn(dev, chunk_id -
5062 + dev->chunk_offset, buffer, &tags) != YAFFS_OK)
5063 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5064 + TCONT("write bad block marker to block %d")
5065 + TENDSTR), flash_block));
5066
5067 - if (theChunk > 0) {
5068 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
5069 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
5070 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
5071 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
5072 - objectId, chunkOffset, theChunk,
5073 - tags.objectId, tags.chunkId));
5074 - }
5075 - }
5076 - chunkOffset++;
5077 - }
5078 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
5079 }
5080 }
5081
5082 - return ok;
5083 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
5084 + bi->gc_prioritise = 0;
5085 + bi->needs_retiring = 0;
5086
5087 + dev->n_retired_blocks++;
5088 }
5089
5090 +/*
5091 + * Functions for robustisizing TODO
5092 + *
5093 + */
5094
5095 -static void yaffs_VerifyFile(yaffs_Object *obj)
5096 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
5097 + const __u8 *data,
5098 + const yaffs_ext_tags *tags)
5099 {
5100 - int requiredTallness;
5101 - int actualTallness;
5102 - __u32 lastChunk;
5103 - __u32 x;
5104 - __u32 i;
5105 - yaffs_Device *dev;
5106 - yaffs_ExtendedTags tags;
5107 - yaffs_Tnode *tn;
5108 - __u32 objectId;
5109 + dev=dev;
5110 + nand_chunk=nand_chunk;
5111 + data=data;
5112 + tags=tags;
5113 +}
5114
5115 - if (!obj)
5116 - return;
5117 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
5118 + const yaffs_ext_tags *tags)
5119 +{
5120 + dev=dev;
5121 + nand_chunk=nand_chunk;
5122 + tags=tags;
5123 +}
5124
5125 - if (yaffs_SkipVerification(obj->myDev))
5126 - return;
5127 +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi)
5128 +{
5129 + if (!bi->gc_prioritise) {
5130 + bi->gc_prioritise = 1;
5131 + dev->has_pending_prioritised_gc = 1;
5132 + bi->chunk_error_strikes++;
5133
5134 - dev = obj->myDev;
5135 - objectId = obj->objectId;
5136 + if (bi->chunk_error_strikes > 3) {
5137 + bi->needs_retiring = 1; /* Too many stikes, so retire this */
5138 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5139
5140 - /* Check file size is consistent with tnode depth */
5141 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
5142 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
5143 - requiredTallness = 0;
5144 - while (x > 0) {
5145 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5146 - requiredTallness++;
5147 + }
5148 }
5149 +}
5150
5151 - actualTallness = obj->variant.fileVariant.topLevel;
5152 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
5153 + int erasedOk)
5154 +{
5155 + int flash_block = nand_chunk / dev->param.chunks_per_block;
5156 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
5157
5158 - if (requiredTallness > actualTallness)
5159 - T(YAFFS_TRACE_VERIFY,
5160 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
5161 - obj->objectId, actualTallness, requiredTallness));
5162 + yaffs_handle_chunk_error(dev, bi);
5163
5164 + if (erasedOk) {
5165 + /* Was an actual write failure, so mark the block for retirement */
5166 + bi->needs_retiring = 1;
5167 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5168 + (TSTR("**>> Block %d needs retiring" TENDSTR), flash_block));
5169 + }
5170
5171 - /* Check that the chunks in the tnode tree are all correct.
5172 - * We do this by scanning through the tnode tree and
5173 - * checking the tags for every chunk match.
5174 - */
5175 + /* Delete the chunk */
5176 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
5177 + yaffs_skip_rest_of_block(dev);
5178 +}
5179
5180 - if (yaffs_SkipNANDVerification(dev))
5181 - return;
5182
5183 - for (i = 1; i <= lastChunk; i++) {
5184 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
5185 +/*---------------- Name handling functions ------------*/
5186
5187 - if (tn) {
5188 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5189 - if (theChunk > 0) {
5190 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
5191 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
5192 - if (tags.objectId != objectId || tags.chunkId != i) {
5193 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
5194 - objectId, i, theChunk,
5195 - tags.objectId, tags.chunkId));
5196 - }
5197 - }
5198 +static __u16 yaffs_calc_name_sum(const YCHAR *name)
5199 +{
5200 + __u16 sum = 0;
5201 + __u16 i = 1;
5202 +
5203 + const YUCHAR *bname = (const YUCHAR *) name;
5204 + if (bname) {
5205 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5206 +
5207 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5208 + sum += yaffs_toupper(*bname) * i;
5209 +#else
5210 + sum += (*bname) * i;
5211 +#endif
5212 + i++;
5213 + bname++;
5214 }
5215 }
5216 + return sum;
5217 }
5218
5219 -
5220 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
5221 +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name)
5222 {
5223 - if (obj && yaffs_SkipVerification(obj->myDev))
5224 - return;
5225 -
5226 - /* Verify sane equivalent object */
5227 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5228 + memset(obj->short_name, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5229 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
5230 + yaffs_strcpy(obj->short_name, name);
5231 + else
5232 + obj->short_name[0] = _Y('\0');
5233 +#endif
5234 + obj->sum = yaffs_calc_name_sum(name);
5235 }
5236
5237 -static void yaffs_VerifySymlink(yaffs_Object *obj)
5238 +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh)
5239 {
5240 - if (obj && yaffs_SkipVerification(obj->myDev))
5241 - return;
5242 -
5243 - /* Verify symlink string */
5244 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
5245 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
5246 + memset(tmpName,0,sizeof(tmpName));
5247 + yaffs_load_name_from_oh(obj->my_dev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
5248 + yaffs_set_obj_name(obj,tmpName);
5249 +#else
5250 + yaffs_set_obj_name(obj,oh->name);
5251 +#endif
5252 }
5253
5254 -static void yaffs_VerifySpecial(yaffs_Object *obj)
5255 -{
5256 - if (obj && yaffs_SkipVerification(obj->myDev))
5257 - return;
5258 -}
5259 -
5260 -static void yaffs_VerifyObject(yaffs_Object *obj)
5261 -{
5262 - yaffs_Device *dev;
5263 -
5264 - __u32 chunkMin;
5265 - __u32 chunkMax;
5266 -
5267 - __u32 chunkIdOk;
5268 - __u32 chunkInRange;
5269 - __u32 chunkShouldNotBeDeleted;
5270 - __u32 chunkValid;
5271 -
5272 - if (!obj)
5273 - return;
5274 -
5275 - if (obj->beingCreated)
5276 - return;
5277 +/*-------------------- TNODES -------------------
5278
5279 - dev = obj->myDev;
5280 + * List of spare tnodes
5281 + * The list is hooked together using the first pointer
5282 + * in the tnode.
5283 + */
5284
5285 - if (yaffs_SkipVerification(dev))
5286 - return;
5287
5288 - /* Check sane object header chunk */
5289 +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev)
5290 +{
5291 + yaffs_tnode_t *tn = yaffs_alloc_raw_tnode(dev);
5292 + if (tn){
5293 + memset(tn, 0, dev->tnode_size);
5294 + dev->n_tnodes++;
5295 + }
5296
5297 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
5298 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
5299 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
5300
5301 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
5302 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
5303 - chunkValid = chunkInRange &&
5304 - yaffs_CheckChunkBit(dev,
5305 - obj->hdrChunk / dev->nChunksPerBlock,
5306 - obj->hdrChunk % dev->nChunksPerBlock);
5307 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
5308 + return tn;
5309 +}
5310
5311 - if (!obj->fake &&
5312 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
5313 - T(YAFFS_TRACE_VERIFY,
5314 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
5315 - obj->objectId, obj->hdrChunk,
5316 - chunkIdOk ? "" : ",out of range",
5317 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
5318 - }
5319 +/* FreeTnode frees up a tnode and puts it back on the free list */
5320 +static void yaffs_free_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
5321 +{
5322 + yaffs_free_raw_tnode(dev,tn);
5323 + dev->n_tnodes--;
5324 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
5325 +}
5326
5327 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
5328 - yaffs_ExtendedTags tags;
5329 - yaffs_ObjectHeader *oh;
5330 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5331 +static void yaffs_deinit_tnodes_and_objs(yaffs_dev_t *dev)
5332 +{
5333 + yaffs_deinit_raw_tnodes_and_objs(dev);
5334 + dev->n_obj = 0;
5335 + dev->n_tnodes = 0;
5336 +}
5337
5338 - oh = (yaffs_ObjectHeader *)buffer;
5339
5340 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
5341 - &tags);
5342 +void yaffs_load_tnode_0(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos,
5343 + unsigned val)
5344 +{
5345 + __u32 *map = (__u32 *)tn;
5346 + __u32 bitInMap;
5347 + __u32 bitInWord;
5348 + __u32 wordInMap;
5349 + __u32 mask;
5350
5351 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
5352 + pos &= YAFFS_TNODES_LEVEL0_MASK;
5353 + val >>= dev->chunk_grp_bits;
5354
5355 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5356 - }
5357 + bitInMap = pos * dev->tnode_width;
5358 + wordInMap = bitInMap / 32;
5359 + bitInWord = bitInMap & (32 - 1);
5360
5361 - /* Verify it has a parent */
5362 - if (obj && !obj->fake &&
5363 - (!obj->parent || obj->parent->myDev != dev)) {
5364 - T(YAFFS_TRACE_VERIFY,
5365 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
5366 - obj->objectId, obj->parent));
5367 - }
5368 + mask = dev->tnode_mask << bitInWord;
5369
5370 - /* Verify parent is a directory */
5371 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
5372 - T(YAFFS_TRACE_VERIFY,
5373 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
5374 - obj->objectId, obj->parent->variantType));
5375 - }
5376 + map[wordInMap] &= ~mask;
5377 + map[wordInMap] |= (mask & (val << bitInWord));
5378
5379 - switch (obj->variantType) {
5380 - case YAFFS_OBJECT_TYPE_FILE:
5381 - yaffs_VerifyFile(obj);
5382 - break;
5383 - case YAFFS_OBJECT_TYPE_SYMLINK:
5384 - yaffs_VerifySymlink(obj);
5385 - break;
5386 - case YAFFS_OBJECT_TYPE_DIRECTORY:
5387 - yaffs_VerifyDirectory(obj);
5388 - break;
5389 - case YAFFS_OBJECT_TYPE_HARDLINK:
5390 - yaffs_VerifyHardLink(obj);
5391 - break;
5392 - case YAFFS_OBJECT_TYPE_SPECIAL:
5393 - yaffs_VerifySpecial(obj);
5394 - break;
5395 - case YAFFS_OBJECT_TYPE_UNKNOWN:
5396 - default:
5397 - T(YAFFS_TRACE_VERIFY,
5398 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
5399 - obj->objectId, obj->variantType));
5400 - break;
5401 + if (dev->tnode_width > (32 - bitInWord)) {
5402 + bitInWord = (32 - bitInWord);
5403 + wordInMap++;;
5404 + mask = dev->tnode_mask >> (/*dev->tnode_width -*/ bitInWord);
5405 + map[wordInMap] &= ~mask;
5406 + map[wordInMap] |= (mask & (val >> bitInWord));
5407 }
5408 }
5409
5410 -static void yaffs_VerifyObjects(yaffs_Device *dev)
5411 +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn,
5412 + unsigned pos)
5413 {
5414 - yaffs_Object *obj;
5415 - int i;
5416 - struct ylist_head *lh;
5417 + __u32 *map = (__u32 *)tn;
5418 + __u32 bitInMap;
5419 + __u32 bitInWord;
5420 + __u32 wordInMap;
5421 + __u32 val;
5422
5423 - if (yaffs_SkipVerification(dev))
5424 - return;
5425 + pos &= YAFFS_TNODES_LEVEL0_MASK;
5426
5427 - /* Iterate through the objects in each hash entry */
5428 + bitInMap = pos * dev->tnode_width;
5429 + wordInMap = bitInMap / 32;
5430 + bitInWord = bitInMap & (32 - 1);
5431
5432 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
5433 - ylist_for_each(lh, &dev->objectBucket[i].list) {
5434 - if (lh) {
5435 - obj = ylist_entry(lh, yaffs_Object, hashLink);
5436 - yaffs_VerifyObject(obj);
5437 - }
5438 - }
5439 - }
5440 -}
5441 + val = map[wordInMap] >> bitInWord;
5442
5443 + if (dev->tnode_width > (32 - bitInWord)) {
5444 + bitInWord = (32 - bitInWord);
5445 + wordInMap++;;
5446 + val |= (map[wordInMap] << bitInWord);
5447 + }
5448
5449 -/*
5450 - * Simple hash function. Needs to have a reasonable spread
5451 - */
5452 + val &= dev->tnode_mask;
5453 + val <<= dev->chunk_grp_bits;
5454
5455 -static Y_INLINE int yaffs_HashFunction(int n)
5456 -{
5457 - n = abs(n);
5458 - return n % YAFFS_NOBJECT_BUCKETS;
5459 + return val;
5460 }
5461
5462 -/*
5463 - * Access functions to useful fake objects.
5464 - * Note that root might have a presence in NAND if permissions are set.
5465 +/* ------------------- End of individual tnode manipulation -----------------*/
5466 +
5467 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5468 + * The look up tree is represented by the top tnode and the number of top_level
5469 + * in the tree. 0 means only the level 0 tnode is in the tree.
5470 */
5471
5472 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
5473 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5474 +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
5475 + yaffs_file_s *file_struct,
5476 + __u32 chunk_id)
5477 {
5478 - return dev->rootDir;
5479 -}
5480 + yaffs_tnode_t *tn = file_struct->top;
5481 + __u32 i;
5482 + int requiredTallness;
5483 + int level = file_struct->top_level;
5484
5485 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
5486 -{
5487 - return dev->lostNFoundDir;
5488 -}
5489 + dev=dev;
5490
5491 + /* Check sane level and chunk Id */
5492 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5493 + return NULL;
5494
5495 -/*
5496 - * Erased NAND checking functions
5497 - */
5498 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
5499 + return NULL;
5500
5501 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
5502 -{
5503 - /* Horrible, slow implementation */
5504 - while (nBytes--) {
5505 - if (*buffer != 0xFF)
5506 - return 0;
5507 - buffer++;
5508 + /* First check we're tall enough (ie enough top_level) */
5509 +
5510 + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
5511 + requiredTallness = 0;
5512 + while (i) {
5513 + i >>= YAFFS_TNODES_INTERNAL_BITS;
5514 + requiredTallness++;
5515 }
5516 - return 1;
5517 -}
5518
5519 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
5520 - int chunkInNAND)
5521 -{
5522 - int retval = YAFFS_OK;
5523 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
5524 - yaffs_ExtendedTags tags;
5525 - int result;
5526 + if (requiredTallness > file_struct->top_level)
5527 + return NULL; /* Not tall enough, so we can't find it */
5528 +
5529 + /* Traverse down to level 0 */
5530 + while (level > 0 && tn) {
5531 + tn = tn->internal[(chunk_id >>
5532 + (YAFFS_TNODES_LEVEL0_BITS +
5533 + (level - 1) *
5534 + YAFFS_TNODES_INTERNAL_BITS)) &
5535 + YAFFS_TNODES_INTERNAL_MASK];
5536 + level--;
5537 + }
5538
5539 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
5540 + return tn;
5541 +}
5542
5543 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
5544 - retval = YAFFS_FAIL;
5545 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5546 + * This happens in two steps:
5547 + * 1. If the tree isn't tall enough, then make it taller.
5548 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5549 + *
5550 + * Used when modifying the tree.
5551 + *
5552 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5553 + * be plugged into the ttree.
5554 + */
5555
5556 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
5557 - T(YAFFS_TRACE_NANDACCESS,
5558 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
5559 - retval = YAFFS_FAIL;
5560 - }
5561 +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
5562 + yaffs_file_s *file_struct,
5563 + __u32 chunk_id,
5564 + yaffs_tnode_t *passed_tn)
5565 +{
5566 + int requiredTallness;
5567 + int i;
5568 + int l;
5569 + yaffs_tnode_t *tn;
5570
5571 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
5572 + __u32 x;
5573
5574 - return retval;
5575
5576 -}
5577 + /* Check sane level and page Id */
5578 + if (file_struct->top_level < 0 || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
5579 + return NULL;
5580
5581 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
5582 - const __u8 *data,
5583 - yaffs_ExtendedTags *tags,
5584 - int useReserve)
5585 -{
5586 - int attempts = 0;
5587 - int writeOk = 0;
5588 - int chunk;
5589 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
5590 + return NULL;
5591
5592 - yaffs_InvalidateCheckpoint(dev);
5593 + /* First check we're tall enough (ie enough top_level) */
5594
5595 - do {
5596 - yaffs_BlockInfo *bi = 0;
5597 - int erasedOk = 0;
5598 + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
5599 + requiredTallness = 0;
5600 + while (x) {
5601 + x >>= YAFFS_TNODES_INTERNAL_BITS;
5602 + requiredTallness++;
5603 + }
5604
5605 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5606 - if (chunk < 0) {
5607 - /* no space */
5608 - break;
5609 - }
5610
5611 - /* First check this chunk is erased, if it needs
5612 - * checking. The checking policy (unless forced
5613 - * always on) is as follows:
5614 - *
5615 - * Check the first page we try to write in a block.
5616 - * If the check passes then we don't need to check any
5617 - * more. If the check fails, we check again...
5618 - * If the block has been erased, we don't need to check.
5619 - *
5620 - * However, if the block has been prioritised for gc,
5621 - * then we think there might be something odd about
5622 - * this block and stop using it.
5623 - *
5624 - * Rationale: We should only ever see chunks that have
5625 - * not been erased if there was a partially written
5626 - * chunk due to power loss. This checking policy should
5627 - * catch that case with very few checks and thus save a
5628 - * lot of checks that are most likely not needed.
5629 - */
5630 - if (bi->gcPrioritise) {
5631 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5632 - /* try another chunk */
5633 - continue;
5634 - }
5635 + if (requiredTallness > file_struct->top_level) {
5636 + /* Not tall enough, gotta make the tree taller */
5637 + for (i = file_struct->top_level; i < requiredTallness; i++) {
5638
5639 - /* let's give it a try */
5640 - attempts++;
5641 + tn = yaffs_get_tnode(dev);
5642
5643 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5644 - bi->skipErasedCheck = 0;
5645 -#endif
5646 - if (!bi->skipErasedCheck) {
5647 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5648 - if (erasedOk != YAFFS_OK) {
5649 + if (tn) {
5650 + tn->internal[0] = file_struct->top;
5651 + file_struct->top = tn;
5652 + file_struct->top_level++;
5653 + } else {
5654 T(YAFFS_TRACE_ERROR,
5655 - (TSTR("**>> yaffs chunk %d was not erased"
5656 - TENDSTR), chunk));
5657 -
5658 - /* try another chunk */
5659 - continue;
5660 + (TSTR("yaffs: no more tnodes" TENDSTR)));
5661 + return NULL;
5662 }
5663 - bi->skipErasedCheck = 1;
5664 }
5665 + }
5666
5667 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5668 - data, tags);
5669 - if (writeOk != YAFFS_OK) {
5670 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5671 - /* try another chunk */
5672 - continue;
5673 - }
5674 + /* Traverse down to level 0, adding anything we need */
5675
5676 - /* Copy the data into the robustification buffer */
5677 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5678 + l = file_struct->top_level;
5679 + tn = file_struct->top;
5680
5681 - } while (writeOk != YAFFS_OK &&
5682 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5683 + if (l > 0) {
5684 + while (l > 0 && tn) {
5685 + x = (chunk_id >>
5686 + (YAFFS_TNODES_LEVEL0_BITS +
5687 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5688 + YAFFS_TNODES_INTERNAL_MASK;
5689
5690 - if (!writeOk)
5691 - chunk = -1;
5692
5693 - if (attempts > 1) {
5694 - T(YAFFS_TRACE_ERROR,
5695 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5696 - attempts));
5697 + if ((l > 1) && !tn->internal[x]) {
5698 + /* Add missing non-level-zero tnode */
5699 + tn->internal[x] = yaffs_get_tnode(dev);
5700 + if(!tn->internal[x])
5701 + return NULL;
5702 + } else if (l == 1) {
5703 + /* Looking from level 1 at level 0 */
5704 + if (passed_tn) {
5705 + /* If we already have one, then release it.*/
5706 + if (tn->internal[x])
5707 + yaffs_free_tnode(dev, tn->internal[x]);
5708 + tn->internal[x] = passed_tn;
5709 +
5710 + } else if (!tn->internal[x]) {
5711 + /* Don't have one, none passed in */
5712 + tn->internal[x] = yaffs_get_tnode(dev);
5713 + if(!tn->internal[x])
5714 + return NULL;
5715 + }
5716 + }
5717
5718 - dev->nRetriedWrites += (attempts - 1);
5719 + tn = tn->internal[x];
5720 + l--;
5721 + }
5722 + } else {
5723 + /* top is level 0 */
5724 + if (passed_tn) {
5725 + memcpy(tn, passed_tn, (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8);
5726 + yaffs_free_tnode(dev, passed_tn);
5727 + }
5728 }
5729
5730 - return chunk;
5731 + return tn;
5732 }
5733
5734 -/*
5735 - * Block retiring for handling a broken block.
5736 - */
5737 -
5738 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5739 +static int yaffs_find_chunk_in_group(yaffs_dev_t *dev, int theChunk,
5740 + yaffs_ext_tags *tags, int obj_id,
5741 + int inode_chunk)
5742 {
5743 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5744 + int j;
5745
5746 - yaffs_InvalidateCheckpoint(dev);
5747 + for (j = 0; theChunk && j < dev->chunk_grp_size; j++) {
5748 + if (yaffs_check_chunk_bit(dev, theChunk / dev->param.chunks_per_block,
5749 + theChunk % dev->param.chunks_per_block)) {
5750 +
5751 + if(dev->chunk_grp_size == 1)
5752 + return theChunk;
5753 + else {
5754 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL,
5755 + tags);
5756 + if (yaffs_tags_match(tags, obj_id, inode_chunk)) {
5757 + /* found it; */
5758 + return theChunk;
5759 + }
5760 + }
5761 + }
5762 + theChunk++;
5763 + }
5764 + return -1;
5765 +}
5766
5767 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5768 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5769 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5770 - "yaffs: Failed to mark bad and erase block %d"
5771 - TENDSTR), blockInNAND));
5772 - } else {
5773 - yaffs_ExtendedTags tags;
5774 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5775 +#if 0
5776 +/* Experimental code not being used yet. Might speed up file deletion */
5777 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
5778 + * chunks and tnodes in the file.
5779 + * Returns 1 if the tree was deleted.
5780 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5781 + */
5782
5783 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5784 +static int yaffs_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, __u32 level,
5785 + int chunk_offset, int *limit)
5786 +{
5787 + int i;
5788 + int inode_chunk;
5789 + int theChunk;
5790 + yaffs_ext_tags tags;
5791 + int foundChunk;
5792 + yaffs_dev_t *dev = in->my_dev;
5793
5794 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5795 - yaffs_InitialiseTags(&tags);
5796 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5797 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5798 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5799 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5800 - TCONT("write bad block marker to block %d")
5801 - TENDSTR), blockInNAND));
5802 + int allDone = 1;
5803
5804 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5805 - }
5806 - }
5807 + if (tn) {
5808 + if (level > 0) {
5809 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5810 + i--) {
5811 + if (tn->internal[i]) {
5812 + if (limit && (*limit) < 0) {
5813 + allDone = 0;
5814 + } else {
5815 + allDone =
5816 + yaffs_del_worker(in,
5817 + tn->
5818 + internal
5819 + [i],
5820 + level -
5821 + 1,
5822 + (chunk_offset
5823 + <<
5824 + YAFFS_TNODES_INTERNAL_BITS)
5825 + + i,
5826 + limit);
5827 + }
5828 + if (allDone) {
5829 + yaffs_free_tnode(dev,
5830 + tn->
5831 + internal[i]);
5832 + tn->internal[i] = NULL;
5833 + }
5834 + }
5835 + }
5836 + return (allDone) ? 1 : 0;
5837 + } else if (level == 0) {
5838 + int hitLimit = 0;
5839
5840 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5841 - bi->gcPrioritise = 0;
5842 - bi->needsRetiring = 0;
5843 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5844 + i--) {
5845 + theChunk = yaffs_get_group_base(dev, tn, i);
5846 + if (theChunk) {
5847
5848 - dev->nRetiredBlocks++;
5849 -}
5850 + inode_chunk = (chunk_offset <<
5851 + YAFFS_TNODES_LEVEL0_BITS) + i;
5852
5853 -/*
5854 - * Functions for robustisizing TODO
5855 - *
5856 - */
5857 + foundChunk =
5858 + yaffs_find_chunk_in_group(dev,
5859 + theChunk,
5860 + &tags,
5861 + in->obj_id,
5862 + inode_chunk);
5863
5864 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5865 - const __u8 *data,
5866 - const yaffs_ExtendedTags *tags)
5867 -{
5868 -}
5869 + if (foundChunk > 0) {
5870 + yaffs_chunk_del(dev,
5871 + foundChunk, 1,
5872 + __LINE__);
5873 + in->n_data_chunks--;
5874 + if (limit) {
5875 + *limit = *limit - 1;
5876 + if (*limit <= 0)
5877 + hitLimit = 1;
5878 + }
5879
5880 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5881 - const yaffs_ExtendedTags *tags)
5882 -{
5883 -}
5884 + }
5885
5886 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5887 -{
5888 - if (!bi->gcPrioritise) {
5889 - bi->gcPrioritise = 1;
5890 - dev->hasPendingPrioritisedGCs = 1;
5891 - bi->chunkErrorStrikes++;
5892 + yaffs_load_tnode_0(dev, tn, i, 0);
5893 + }
5894
5895 - if (bi->chunkErrorStrikes > 3) {
5896 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5897 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5898 + }
5899 + return (i < 0) ? 1 : 0;
5900
5901 }
5902 +
5903 }
5904 +
5905 + return 1;
5906 +
5907 }
5908
5909 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5910 - int erasedOk)
5911 +#endif
5912 +
5913 +static void yaffs_soft_del_chunk(yaffs_dev_t *dev, int chunk)
5914 {
5915 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5916 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5917 + yaffs_block_info_t *theBlock;
5918 + unsigned block_no;
5919
5920 - yaffs_HandleChunkError(dev, bi);
5921 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5922
5923 - if (erasedOk) {
5924 - /* Was an actual write failure, so mark the block for retirement */
5925 - bi->needsRetiring = 1;
5926 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5927 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5928 + block_no = chunk / dev->param.chunks_per_block;
5929 + theBlock = yaffs_get_block_info(dev, block_no);
5930 + if (theBlock) {
5931 + theBlock->soft_del_pages++;
5932 + dev->n_free_chunks++;
5933 + yaffs2_update_oldest_dirty_seq(dev, block_no, theBlock);
5934 }
5935 -
5936 - /* Delete the chunk */
5937 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5938 }
5939
5940 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5941 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5942 + * of the tnode.
5943 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5944 + */
5945
5946 -/*---------------- Name handling functions ------------*/
5947 -
5948 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5949 +static int yaffs_soft_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
5950 + __u32 level, int chunk_offset)
5951 {
5952 - __u16 sum = 0;
5953 - __u16 i = 1;
5954 + int i;
5955 + int theChunk;
5956 + int allDone = 1;
5957 + yaffs_dev_t *dev = in->my_dev;
5958
5959 - const YUCHAR *bname = (const YUCHAR *) name;
5960 - if (bname) {
5961 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5962 + if (tn) {
5963 + if (level > 0) {
5964 +
5965 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5966 + i--) {
5967 + if (tn->internal[i]) {
5968 + allDone =
5969 + yaffs_soft_del_worker(in,
5970 + tn->
5971 + internal[i],
5972 + level - 1,
5973 + (chunk_offset
5974 + <<
5975 + YAFFS_TNODES_INTERNAL_BITS)
5976 + + i);
5977 + if (allDone) {
5978 + yaffs_free_tnode(dev,
5979 + tn->
5980 + internal[i]);
5981 + tn->internal[i] = NULL;
5982 + } else {
5983 + /* Hoosterman... how could this happen? */
5984 + }
5985 + }
5986 + }
5987 + return (allDone) ? 1 : 0;
5988 + } else if (level == 0) {
5989 +
5990 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
5991 + theChunk = yaffs_get_group_base(dev, tn, i);
5992 + if (theChunk) {
5993 + /* Note this does not find the real chunk, only the chunk group.
5994 + * We make an assumption that a chunk group is not larger than
5995 + * a block.
5996 + */
5997 + yaffs_soft_del_chunk(dev, theChunk);
5998 + yaffs_load_tnode_0(dev, tn, i, 0);
5999 + }
6000 +
6001 + }
6002 + return 1;
6003
6004 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6005 - sum += yaffs_toupper(*bname) * i;
6006 -#else
6007 - sum += (*bname) * i;
6008 -#endif
6009 - i++;
6010 - bname++;
6011 }
6012 +
6013 }
6014 - return sum;
6015 +
6016 + return 1;
6017 +
6018 }
6019
6020 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
6021 +static void yaffs_soft_del_file(yaffs_obj_t *obj)
6022 {
6023 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
6024 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
6025 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
6026 - yaffs_strcpy(obj->shortName, name);
6027 - else
6028 - obj->shortName[0] = _Y('\0');
6029 -#endif
6030 - obj->sum = yaffs_CalcNameSum(name);
6031 + if (obj->deleted &&
6032 + obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) {
6033 + if (obj->n_data_chunks <= 0) {
6034 + /* Empty file with no duplicate object headers, just delete it immediately */
6035 + yaffs_free_tnode(obj->my_dev,
6036 + obj->variant.file_variant.top);
6037 + obj->variant.file_variant.top = NULL;
6038 + T(YAFFS_TRACE_TRACING,
6039 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
6040 + obj->obj_id));
6041 + yaffs_generic_obj_del(obj);
6042 + } else {
6043 + yaffs_soft_del_worker(obj,
6044 + obj->variant.file_variant.top,
6045 + obj->variant.file_variant.
6046 + top_level, 0);
6047 + obj->soft_del = 1;
6048 + }
6049 + }
6050 }
6051
6052 -/*-------------------- TNODES -------------------
6053 -
6054 - * List of spare tnodes
6055 - * The list is hooked together using the first pointer
6056 - * in the tnode.
6057 - */
6058 -
6059 -/* yaffs_CreateTnodes creates a bunch more tnodes and
6060 - * adds them to the tnode free list.
6061 - * Don't use this function directly
6062 +/* Pruning removes any part of the file structure tree that is beyond the
6063 + * bounds of the file (ie that does not point to chunks).
6064 + *
6065 + * A file should only get pruned when its size is reduced.
6066 + *
6067 + * Before pruning, the chunks must be pulled from the tree and the
6068 + * level 0 tnode entries must be zeroed out.
6069 + * Could also use this for file deletion, but that's probably better handled
6070 + * by a special case.
6071 + *
6072 + * This function is recursive. For levels > 0 the function is called again on
6073 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
6074 + * If there is no data in a subtree then it is pruned.
6075 */
6076
6077 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
6078 +static yaffs_tnode_t *yaffs_prune_worker(yaffs_dev_t *dev, yaffs_tnode_t *tn,
6079 + __u32 level, int del0)
6080 {
6081 int i;
6082 - int tnodeSize;
6083 - yaffs_Tnode *newTnodes;
6084 - __u8 *mem;
6085 - yaffs_Tnode *curr;
6086 - yaffs_Tnode *next;
6087 - yaffs_TnodeList *tnl;
6088 + int hasData;
6089
6090 - if (nTnodes < 1)
6091 - return YAFFS_OK;
6092 + if (tn) {
6093 + hasData = 0;
6094
6095 - /* Calculate the tnode size in bytes for variable width tnode support.
6096 - * Must be a multiple of 32-bits */
6097 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6098 + if(level > 0){
6099 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
6100 + if (tn->internal[i]) {
6101 + tn->internal[i] =
6102 + yaffs_prune_worker(dev, tn->internal[i],
6103 + level - 1,
6104 + (i == 0) ? del0 : 1);
6105 + }
6106
6107 - if (tnodeSize < sizeof(yaffs_Tnode))
6108 - tnodeSize = sizeof(yaffs_Tnode);
6109 + if (tn->internal[i])
6110 + hasData++;
6111 + }
6112 + } else {
6113 + int tnode_size_u32 = dev->tnode_size/sizeof(__u32);
6114 + __u32 *map = (__u32 *)tn;
6115
6116 - /* make these things */
6117 + for(i = 0; !hasData && i < tnode_size_u32; i++){
6118 + if(map[i])
6119 + hasData++;
6120 + }
6121 + }
6122
6123 - newTnodes = YMALLOC(nTnodes * tnodeSize);
6124 - mem = (__u8 *)newTnodes;
6125 + if (hasData == 0 && del0) {
6126 + /* Free and return NULL */
6127
6128 - if (!newTnodes) {
6129 - T(YAFFS_TRACE_ERROR,
6130 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
6131 - return YAFFS_FAIL;
6132 - }
6133 + yaffs_free_tnode(dev, tn);
6134 + tn = NULL;
6135 + }
6136
6137 - /* Hook them into the free list */
6138 -#if 0
6139 - for (i = 0; i < nTnodes - 1; i++) {
6140 - newTnodes[i].internal[0] = &newTnodes[i + 1];
6141 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6142 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6143 -#endif
6144 }
6145
6146 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
6147 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6148 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6149 -#endif
6150 - dev->freeTnodes = newTnodes;
6151 -#else
6152 - /* New hookup for wide tnodes */
6153 - for (i = 0; i < nTnodes - 1; i++) {
6154 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
6155 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
6156 - curr->internal[0] = next;
6157 - }
6158 + return tn;
6159
6160 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
6161 - curr->internal[0] = dev->freeTnodes;
6162 - dev->freeTnodes = (yaffs_Tnode *)mem;
6163 +}
6164
6165 -#endif
6166 +static int yaffs_prune_tree(yaffs_dev_t *dev,
6167 + yaffs_file_s *file_struct)
6168 +{
6169 + int i;
6170 + int hasData;
6171 + int done = 0;
6172 + yaffs_tnode_t *tn;
6173
6174 + if (file_struct->top_level > 0) {
6175 + file_struct->top =
6176 + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
6177 +
6178 + /* Now we have a tree with all the non-zero branches NULL but the height
6179 + * is the same as it was.
6180 + * Let's see if we can trim internal tnodes to shorten the tree.
6181 + * We can do this if only the 0th element in the tnode is in use
6182 + * (ie all the non-zero are NULL)
6183 + */
6184
6185 - dev->nFreeTnodes += nTnodes;
6186 - dev->nTnodesCreated += nTnodes;
6187 + while (file_struct->top_level && !done) {
6188 + tn = file_struct->top;
6189
6190 - /* Now add this bunch of tnodes to a list for freeing up.
6191 - * NB If we can't add this to the management list it isn't fatal
6192 - * but it just means we can't free this bunch of tnodes later.
6193 - */
6194 + hasData = 0;
6195 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
6196 + if (tn->internal[i])
6197 + hasData++;
6198 + }
6199
6200 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
6201 - if (!tnl) {
6202 - T(YAFFS_TRACE_ERROR,
6203 - (TSTR
6204 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
6205 - return YAFFS_FAIL;
6206 - } else {
6207 - tnl->tnodes = newTnodes;
6208 - tnl->next = dev->allocatedTnodeList;
6209 - dev->allocatedTnodeList = tnl;
6210 + if (!hasData) {
6211 + file_struct->top = tn->internal[0];
6212 + file_struct->top_level--;
6213 + yaffs_free_tnode(dev, tn);
6214 + } else {
6215 + done = 1;
6216 + }
6217 + }
6218 }
6219
6220 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
6221 -
6222 return YAFFS_OK;
6223 }
6224
6225 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
6226 +/*-------------------- End of File Structure functions.-------------------*/
6227 +
6228
6229 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
6230 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
6231 +static yaffs_obj_t *yaffs_alloc_empty_obj(yaffs_dev_t *dev)
6232 {
6233 - yaffs_Tnode *tn = NULL;
6234 + yaffs_obj_t *obj = yaffs_alloc_raw_obj(dev);
6235
6236 - /* If there are none left make more */
6237 - if (!dev->freeTnodes)
6238 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
6239 -
6240 - if (dev->freeTnodes) {
6241 - tn = dev->freeTnodes;
6242 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6243 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
6244 - /* Hoosterman, this thing looks like it isn't in the list */
6245 - T(YAFFS_TRACE_ALWAYS,
6246 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
6247 - }
6248 -#endif
6249 - dev->freeTnodes = dev->freeTnodes->internal[0];
6250 - dev->nFreeTnodes--;
6251 - }
6252 + if (obj) {
6253 + dev->n_obj++;
6254
6255 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6256 + /* Now sweeten it up... */
6257
6258 - return tn;
6259 -}
6260 + memset(obj, 0, sizeof(yaffs_obj_t));
6261 + obj->being_created = 1;
6262
6263 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
6264 -{
6265 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
6266 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6267 + obj->my_dev = dev;
6268 + obj->hdr_chunk = 0;
6269 + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
6270 + YINIT_LIST_HEAD(&(obj->hard_links));
6271 + YINIT_LIST_HEAD(&(obj->hash_link));
6272 + YINIT_LIST_HEAD(&obj->siblings);
6273
6274 - if (tnodeSize < sizeof(yaffs_Tnode))
6275 - tnodeSize = sizeof(yaffs_Tnode);
6276
6277 - if (tn)
6278 - memset(tn, 0, tnodeSize);
6279 + /* Now make the directory sane */
6280 + if (dev->root_dir) {
6281 + obj->parent = dev->root_dir;
6282 + ylist_add(&(obj->siblings), &dev->root_dir->variant.dir_variant.children);
6283 + }
6284
6285 - return tn;
6286 + /* Add it to the lost and found directory.
6287 + * NB Can't put root or lostNFound in lostNFound so
6288 + * check if lostNFound exists first
6289 + */
6290 + if (dev->lost_n_found)
6291 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
6292 +
6293 + obj->being_created = 0;
6294 + }
6295 +
6296 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
6297 +
6298 + return obj;
6299 }
6300
6301 -/* FreeTnode frees up a tnode and puts it back on the free list */
6302 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
6303 +static yaffs_obj_t *yaffs_create_fake_dir(yaffs_dev_t *dev, int number,
6304 + __u32 mode)
6305 {
6306 - if (tn) {
6307 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6308 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
6309 - /* Hoosterman, this thing looks like it is already in the list */
6310 - T(YAFFS_TRACE_ALWAYS,
6311 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
6312 - }
6313 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6314 -#endif
6315 - tn->internal[0] = dev->freeTnodes;
6316 - dev->freeTnodes = tn;
6317 - dev->nFreeTnodes++;
6318 +
6319 + yaffs_obj_t *obj =
6320 + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6321 + if (obj) {
6322 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
6323 + obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */
6324 + obj->unlink_allowed = 0; /* ... or unlink it */
6325 + obj->deleted = 0;
6326 + obj->unlinked = 0;
6327 + obj->yst_mode = mode;
6328 + obj->my_dev = dev;
6329 + obj->hdr_chunk = 0; /* Not a valid chunk. */
6330 + }
6331 +
6332 + return obj;
6333 +
6334 +}
6335 +
6336 +static void yaffs_unhash_obj(yaffs_obj_t *obj)
6337 +{
6338 + int bucket;
6339 + yaffs_dev_t *dev = obj->my_dev;
6340 +
6341 + /* If it is still linked into the bucket list, free from the list */
6342 + if (!ylist_empty(&obj->hash_link)) {
6343 + ylist_del_init(&obj->hash_link);
6344 + bucket = yaffs_hash_fn(obj->obj_id);
6345 + dev->obj_bucket[bucket].count--;
6346 }
6347 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6348 }
6349
6350 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
6351 +/* FreeObject frees up a Object and puts it back on the free list */
6352 +static void yaffs_free_obj(yaffs_obj_t *obj)
6353 {
6354 - /* Free the list of allocated tnodes */
6355 - yaffs_TnodeList *tmp;
6356 + yaffs_dev_t *dev = obj->my_dev;
6357 +
6358 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->my_inode));
6359
6360 - while (dev->allocatedTnodeList) {
6361 - tmp = dev->allocatedTnodeList->next;
6362 + if (!obj)
6363 + YBUG();
6364 + if (obj->parent)
6365 + YBUG();
6366 + if (!ylist_empty(&obj->siblings))
6367 + YBUG();
6368
6369 - YFREE(dev->allocatedTnodeList->tnodes);
6370 - YFREE(dev->allocatedTnodeList);
6371 - dev->allocatedTnodeList = tmp;
6372
6373 + if (obj->my_inode) {
6374 + /* We're still hooked up to a cached inode.
6375 + * Don't delete now, but mark for later deletion
6376 + */
6377 + obj->defered_free = 1;
6378 + return;
6379 }
6380
6381 - dev->freeTnodes = NULL;
6382 - dev->nFreeTnodes = 0;
6383 -}
6384 + yaffs_unhash_obj(obj);
6385
6386 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
6387 -{
6388 - dev->allocatedTnodeList = NULL;
6389 - dev->freeTnodes = NULL;
6390 - dev->nFreeTnodes = 0;
6391 - dev->nTnodesCreated = 0;
6392 + yaffs_free_raw_obj(dev,obj);
6393 + dev->n_obj--;
6394 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
6395 }
6396
6397
6398 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
6399 - unsigned val)
6400 +void yaffs_handle_defered_free(yaffs_obj_t *obj)
6401 {
6402 - __u32 *map = (__u32 *)tn;
6403 - __u32 bitInMap;
6404 - __u32 bitInWord;
6405 - __u32 wordInMap;
6406 - __u32 mask;
6407 -
6408 - pos &= YAFFS_TNODES_LEVEL0_MASK;
6409 - val >>= dev->chunkGroupBits;
6410 + if (obj->defered_free)
6411 + yaffs_free_obj(obj);
6412 +}
6413
6414 - bitInMap = pos * dev->tnodeWidth;
6415 - wordInMap = bitInMap / 32;
6416 - bitInWord = bitInMap & (32 - 1);
6417 +static void yaffs_init_tnodes_and_objs(yaffs_dev_t *dev)
6418 +{
6419 + int i;
6420
6421 - mask = dev->tnodeMask << bitInWord;
6422 + dev->n_obj = 0;
6423 + dev->n_tnodes = 0;
6424
6425 - map[wordInMap] &= ~mask;
6426 - map[wordInMap] |= (mask & (val << bitInWord));
6427 + yaffs_init_raw_tnodes_and_objs(dev);
6428
6429 - if (dev->tnodeWidth > (32 - bitInWord)) {
6430 - bitInWord = (32 - bitInWord);
6431 - wordInMap++;;
6432 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
6433 - map[wordInMap] &= ~mask;
6434 - map[wordInMap] |= (mask & (val >> bitInWord));
6435 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6436 + YINIT_LIST_HEAD(&dev->obj_bucket[i].list);
6437 + dev->obj_bucket[i].count = 0;
6438 }
6439 }
6440
6441 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
6442 - unsigned pos)
6443 +static int yaffs_find_nice_bucket(yaffs_dev_t *dev)
6444 {
6445 - __u32 *map = (__u32 *)tn;
6446 - __u32 bitInMap;
6447 - __u32 bitInWord;
6448 - __u32 wordInMap;
6449 - __u32 val;
6450 + int i;
6451 + int l = 999;
6452 + int lowest = 999999;
6453
6454 - pos &= YAFFS_TNODES_LEVEL0_MASK;
6455
6456 - bitInMap = pos * dev->tnodeWidth;
6457 - wordInMap = bitInMap / 32;
6458 - bitInWord = bitInMap & (32 - 1);
6459 + /* Search for the shortest list or one that
6460 + * isn't too long.
6461 + */
6462
6463 - val = map[wordInMap] >> bitInWord;
6464 + for (i = 0; i < 10 && lowest > 4; i++) {
6465 + dev->bucket_finder++;
6466 + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
6467 + if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
6468 + lowest = dev->obj_bucket[dev->bucket_finder].count;
6469 + l = dev->bucket_finder;
6470 + }
6471
6472 - if (dev->tnodeWidth > (32 - bitInWord)) {
6473 - bitInWord = (32 - bitInWord);
6474 - wordInMap++;;
6475 - val |= (map[wordInMap] << bitInWord);
6476 }
6477
6478 - val &= dev->tnodeMask;
6479 - val <<= dev->chunkGroupBits;
6480 -
6481 - return val;
6482 + return l;
6483 }
6484
6485 -/* ------------------- End of individual tnode manipulation -----------------*/
6486 -
6487 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
6488 - * The look up tree is represented by the top tnode and the number of topLevel
6489 - * in the tree. 0 means only the level 0 tnode is in the tree.
6490 - */
6491 -
6492 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
6493 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
6494 - yaffs_FileStructure *fStruct,
6495 - __u32 chunkId)
6496 +static int yaffs_new_obj_id(yaffs_dev_t *dev)
6497 {
6498 - yaffs_Tnode *tn = fStruct->top;
6499 - __u32 i;
6500 - int requiredTallness;
6501 - int level = fStruct->topLevel;
6502 -
6503 - /* Check sane level and chunk Id */
6504 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
6505 - return NULL;
6506 + int bucket = yaffs_find_nice_bucket(dev);
6507
6508 - if (chunkId > YAFFS_MAX_CHUNK_ID)
6509 - return NULL;
6510 + /* Now find an object value that has not already been taken
6511 + * by scanning the list.
6512 + */
6513
6514 - /* First check we're tall enough (ie enough topLevel) */
6515 + int found = 0;
6516 + struct ylist_head *i;
6517
6518 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
6519 - requiredTallness = 0;
6520 - while (i) {
6521 - i >>= YAFFS_TNODES_INTERNAL_BITS;
6522 - requiredTallness++;
6523 - }
6524 + __u32 n = (__u32) bucket;
6525
6526 - if (requiredTallness > fStruct->topLevel)
6527 - return NULL; /* Not tall enough, so we can't find it */
6528 + /* yaffs_check_obj_hash_sane(); */
6529
6530 - /* Traverse down to level 0 */
6531 - while (level > 0 && tn) {
6532 - tn = tn->internal[(chunkId >>
6533 - (YAFFS_TNODES_LEVEL0_BITS +
6534 - (level - 1) *
6535 - YAFFS_TNODES_INTERNAL_BITS)) &
6536 - YAFFS_TNODES_INTERNAL_MASK];
6537 - level--;
6538 + while (!found) {
6539 + found = 1;
6540 + n += YAFFS_NOBJECT_BUCKETS;
6541 + if (1 || dev->obj_bucket[bucket].count > 0) {
6542 + ylist_for_each(i, &dev->obj_bucket[bucket].list) {
6543 + /* If there is already one in the list */
6544 + if (i && ylist_entry(i, yaffs_obj_t,
6545 + hash_link)->obj_id == n) {
6546 + found = 0;
6547 + }
6548 + }
6549 + }
6550 }
6551
6552 - return tn;
6553 + return n;
6554 }
6555
6556 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
6557 - * This happens in two steps:
6558 - * 1. If the tree isn't tall enough, then make it taller.
6559 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
6560 - *
6561 - * Used when modifying the tree.
6562 - *
6563 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
6564 - * be plugged into the ttree.
6565 - */
6566 -
6567 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
6568 - yaffs_FileStructure *fStruct,
6569 - __u32 chunkId,
6570 - yaffs_Tnode *passedTn)
6571 +static void yaffs_hash_obj(yaffs_obj_t *in)
6572 {
6573 - int requiredTallness;
6574 - int i;
6575 - int l;
6576 - yaffs_Tnode *tn;
6577 -
6578 - __u32 x;
6579 + int bucket = yaffs_hash_fn(in->obj_id);
6580 + yaffs_dev_t *dev = in->my_dev;
6581
6582 + ylist_add(&in->hash_link, &dev->obj_bucket[bucket].list);
6583 + dev->obj_bucket[bucket].count++;
6584 +}
6585
6586 - /* Check sane level and page Id */
6587 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
6588 - return NULL;
6589 +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number)
6590 +{
6591 + int bucket = yaffs_hash_fn(number);
6592 + struct ylist_head *i;
6593 + yaffs_obj_t *in;
6594
6595 - if (chunkId > YAFFS_MAX_CHUNK_ID)
6596 - return NULL;
6597 + ylist_for_each(i, &dev->obj_bucket[bucket].list) {
6598 + /* Look if it is in the list */
6599 + if (i) {
6600 + in = ylist_entry(i, yaffs_obj_t, hash_link);
6601 + if (in->obj_id == number) {
6602
6603 - /* First check we're tall enough (ie enough topLevel) */
6604 + /* Don't tell the VFS about this one if it is defered free */
6605 + if (in->defered_free)
6606 + return NULL;
6607
6608 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
6609 - requiredTallness = 0;
6610 - while (x) {
6611 - x >>= YAFFS_TNODES_INTERNAL_BITS;
6612 - requiredTallness++;
6613 + return in;
6614 + }
6615 + }
6616 }
6617
6618 + return NULL;
6619 +}
6620
6621 - if (requiredTallness > fStruct->topLevel) {
6622 - /* Not tall enough, gotta make the tree taller */
6623 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
6624 +yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
6625 + yaffs_obj_type type)
6626 +{
6627 + yaffs_obj_t *theObject=NULL;
6628 + yaffs_tnode_t *tn = NULL;
6629
6630 - tn = yaffs_GetTnode(dev);
6631 + if (number < 0)
6632 + number = yaffs_new_obj_id(dev);
6633
6634 - if (tn) {
6635 - tn->internal[0] = fStruct->top;
6636 - fStruct->top = tn;
6637 - } else {
6638 - T(YAFFS_TRACE_ERROR,
6639 - (TSTR("yaffs: no more tnodes" TENDSTR)));
6640 - }
6641 - }
6642 + if (type == YAFFS_OBJECT_TYPE_FILE) {
6643 + tn = yaffs_get_tnode(dev);
6644 + if (!tn)
6645 + return NULL;
6646 + }
6647
6648 - fStruct->topLevel = requiredTallness;
6649 + theObject = yaffs_alloc_empty_obj(dev);
6650 + if (!theObject){
6651 + if(tn)
6652 + yaffs_free_tnode(dev,tn);
6653 + return NULL;
6654 }
6655
6656 - /* Traverse down to level 0, adding anything we need */
6657
6658 - l = fStruct->topLevel;
6659 - tn = fStruct->top;
6660 + if (theObject) {
6661 + theObject->fake = 0;
6662 + theObject->rename_allowed = 1;
6663 + theObject->unlink_allowed = 1;
6664 + theObject->obj_id = number;
6665 + yaffs_hash_obj(theObject);
6666 + theObject->variant_type = type;
6667 +#ifdef CONFIG_YAFFS_WINCE
6668 + yfsd_win_file_time_now(theObject->win_atime);
6669 + theObject->win_ctime[0] = theObject->win_mtime[0] =
6670 + theObject->win_atime[0];
6671 + theObject->win_ctime[1] = theObject->win_mtime[1] =
6672 + theObject->win_atime[1];
6673 +
6674 +#else
6675
6676 - if (l > 0) {
6677 - while (l > 0 && tn) {
6678 - x = (chunkId >>
6679 - (YAFFS_TNODES_LEVEL0_BITS +
6680 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
6681 - YAFFS_TNODES_INTERNAL_MASK;
6682 + theObject->yst_atime = theObject->yst_mtime =
6683 + theObject->yst_ctime = Y_CURRENT_TIME;
6684 +#endif
6685 + switch (type) {
6686 + case YAFFS_OBJECT_TYPE_FILE:
6687 + theObject->variant.file_variant.file_size = 0;
6688 + theObject->variant.file_variant.scanned_size = 0;
6689 + theObject->variant.file_variant.shrink_size = 0xFFFFFFFF; /* max __u32 */
6690 + theObject->variant.file_variant.top_level = 0;
6691 + theObject->variant.file_variant.top = tn;
6692 + break;
6693 + case YAFFS_OBJECT_TYPE_DIRECTORY:
6694 + YINIT_LIST_HEAD(&theObject->variant.dir_variant.
6695 + children);
6696 + YINIT_LIST_HEAD(&theObject->variant.dir_variant.
6697 + dirty);
6698 + break;
6699 + case YAFFS_OBJECT_TYPE_SYMLINK:
6700 + case YAFFS_OBJECT_TYPE_HARDLINK:
6701 + case YAFFS_OBJECT_TYPE_SPECIAL:
6702 + /* No action required */
6703 + break;
6704 + case YAFFS_OBJECT_TYPE_UNKNOWN:
6705 + /* todo this should not happen */
6706 + break;
6707 + }
6708 + }
6709
6710 + return theObject;
6711 +}
6712
6713 - if ((l > 1) && !tn->internal[x]) {
6714 - /* Add missing non-level-zero tnode */
6715 - tn->internal[x] = yaffs_GetTnode(dev);
6716 +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
6717 + int number,
6718 + yaffs_obj_type type)
6719 +{
6720 + yaffs_obj_t *theObject = NULL;
6721
6722 - } else if (l == 1) {
6723 - /* Looking from level 1 at level 0 */
6724 - if (passedTn) {
6725 - /* If we already have one, then release it.*/
6726 - if (tn->internal[x])
6727 - yaffs_FreeTnode(dev, tn->internal[x]);
6728 - tn->internal[x] = passedTn;
6729 + if (number > 0)
6730 + theObject = yaffs_find_by_number(dev, number);
6731
6732 - } else if (!tn->internal[x]) {
6733 - /* Don't have one, none passed in */
6734 - tn->internal[x] = yaffs_GetTnode(dev);
6735 - }
6736 - }
6737 + if (!theObject)
6738 + theObject = yaffs_new_obj(dev, number, type);
6739
6740 - tn = tn->internal[x];
6741 - l--;
6742 - }
6743 - } else {
6744 - /* top is level 0 */
6745 - if (passedTn) {
6746 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
6747 - yaffs_FreeTnode(dev, passedTn);
6748 - }
6749 - }
6750 + return theObject;
6751
6752 - return tn;
6753 }
6754
6755 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
6756 - yaffs_ExtendedTags *tags, int objectId,
6757 - int chunkInInode)
6758 +
6759 +YCHAR *yaffs_clone_str(const YCHAR *str)
6760 {
6761 - int j;
6762 + YCHAR *newStr = NULL;
6763 + int len;
6764
6765 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
6766 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
6767 - theChunk % dev->nChunksPerBlock)) {
6768 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
6769 - tags);
6770 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
6771 - /* found it; */
6772 - return theChunk;
6773 - }
6774 - }
6775 - theChunk++;
6776 + if (!str)
6777 + str = _Y("");
6778 +
6779 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
6780 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
6781 + if (newStr){
6782 + yaffs_strncpy(newStr, str,len);
6783 + newStr[len] = 0;
6784 }
6785 - return -1;
6786 -}
6787 + return newStr;
6788
6789 +}
6790
6791 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
6792 - * chunks and tnodes in the file
6793 - * Returns 1 if the tree was deleted.
6794 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
6795 +/*
6796 + * Mknod (create) a new object.
6797 + * equiv_obj only has meaning for a hard link;
6798 + * aliasString only has meaning for a symlink.
6799 + * rdev only has meaning for devices (a subset of special objects)
6800 */
6801
6802 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
6803 - int chunkOffset, int *limit)
6804 +static yaffs_obj_t *yaffs_create_obj(yaffs_obj_type type,
6805 + yaffs_obj_t *parent,
6806 + const YCHAR *name,
6807 + __u32 mode,
6808 + __u32 uid,
6809 + __u32 gid,
6810 + yaffs_obj_t *equiv_obj,
6811 + const YCHAR *aliasString, __u32 rdev)
6812 {
6813 - int i;
6814 - int chunkInInode;
6815 - int theChunk;
6816 - yaffs_ExtendedTags tags;
6817 - int foundChunk;
6818 - yaffs_Device *dev = in->myDev;
6819 -
6820 - int allDone = 1;
6821 -
6822 - if (tn) {
6823 - if (level > 0) {
6824 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
6825 - i--) {
6826 - if (tn->internal[i]) {
6827 - if (limit && (*limit) < 0) {
6828 - allDone = 0;
6829 - } else {
6830 - allDone =
6831 - yaffs_DeleteWorker(in,
6832 - tn->
6833 - internal
6834 - [i],
6835 - level -
6836 - 1,
6837 - (chunkOffset
6838 - <<
6839 - YAFFS_TNODES_INTERNAL_BITS)
6840 - + i,
6841 - limit);
6842 - }
6843 - if (allDone) {
6844 - yaffs_FreeTnode(dev,
6845 - tn->
6846 - internal[i]);
6847 - tn->internal[i] = NULL;
6848 - }
6849 - }
6850 - }
6851 - return (allDone) ? 1 : 0;
6852 - } else if (level == 0) {
6853 - int hitLimit = 0;
6854 -
6855 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
6856 - i--) {
6857 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
6858 - if (theChunk) {
6859 -
6860 - chunkInInode = (chunkOffset <<
6861 - YAFFS_TNODES_LEVEL0_BITS) + i;
6862 -
6863 - foundChunk =
6864 - yaffs_FindChunkInGroup(dev,
6865 - theChunk,
6866 - &tags,
6867 - in->objectId,
6868 - chunkInInode);
6869 -
6870 - if (foundChunk > 0) {
6871 - yaffs_DeleteChunk(dev,
6872 - foundChunk, 1,
6873 - __LINE__);
6874 - in->nDataChunks--;
6875 - if (limit) {
6876 - *limit = *limit - 1;
6877 - if (*limit <= 0)
6878 - hitLimit = 1;
6879 - }
6880 -
6881 - }
6882 -
6883 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
6884 - }
6885 -
6886 - }
6887 - return (i < 0) ? 1 : 0;
6888 -
6889 - }
6890 -
6891 - }
6892 -
6893 - return 1;
6894 -
6895 -}
6896 -
6897 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
6898 -{
6899 - yaffs_BlockInfo *theBlock;
6900 -
6901 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
6902 -
6903 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
6904 - if (theBlock) {
6905 - theBlock->softDeletions++;
6906 - dev->nFreeChunks++;
6907 - }
6908 -}
6909 -
6910 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
6911 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
6912 - * of the tnode.
6913 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
6914 - */
6915 -
6916 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
6917 - __u32 level, int chunkOffset)
6918 -{
6919 - int i;
6920 - int theChunk;
6921 - int allDone = 1;
6922 - yaffs_Device *dev = in->myDev;
6923 -
6924 - if (tn) {
6925 - if (level > 0) {
6926 -
6927 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
6928 - i--) {
6929 - if (tn->internal[i]) {
6930 - allDone =
6931 - yaffs_SoftDeleteWorker(in,
6932 - tn->
6933 - internal[i],
6934 - level - 1,
6935 - (chunkOffset
6936 - <<
6937 - YAFFS_TNODES_INTERNAL_BITS)
6938 - + i);
6939 - if (allDone) {
6940 - yaffs_FreeTnode(dev,
6941 - tn->
6942 - internal[i]);
6943 - tn->internal[i] = NULL;
6944 - } else {
6945 - /* Hoosterman... how could this happen? */
6946 - }
6947 - }
6948 - }
6949 - return (allDone) ? 1 : 0;
6950 - } else if (level == 0) {
6951 -
6952 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
6953 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
6954 - if (theChunk) {
6955 - /* Note this does not find the real chunk, only the chunk group.
6956 - * We make an assumption that a chunk group is not larger than
6957 - * a block.
6958 - */
6959 - yaffs_SoftDeleteChunk(dev, theChunk);
6960 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
6961 - }
6962 -
6963 - }
6964 - return 1;
6965 -
6966 - }
6967 -
6968 - }
6969 -
6970 - return 1;
6971 -
6972 -}
6973 -
6974 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
6975 -{
6976 - if (obj->deleted &&
6977 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
6978 - if (obj->nDataChunks <= 0) {
6979 - /* Empty file with no duplicate object headers, just delete it immediately */
6980 - yaffs_FreeTnode(obj->myDev,
6981 - obj->variant.fileVariant.top);
6982 - obj->variant.fileVariant.top = NULL;
6983 - T(YAFFS_TRACE_TRACING,
6984 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
6985 - obj->objectId));
6986 - yaffs_DoGenericObjectDeletion(obj);
6987 - } else {
6988 - yaffs_SoftDeleteWorker(obj,
6989 - obj->variant.fileVariant.top,
6990 - obj->variant.fileVariant.
6991 - topLevel, 0);
6992 - obj->softDeleted = 1;
6993 - }
6994 - }
6995 -}
6996 -
6997 -/* Pruning removes any part of the file structure tree that is beyond the
6998 - * bounds of the file (ie that does not point to chunks).
6999 - *
7000 - * A file should only get pruned when its size is reduced.
7001 - *
7002 - * Before pruning, the chunks must be pulled from the tree and the
7003 - * level 0 tnode entries must be zeroed out.
7004 - * Could also use this for file deletion, but that's probably better handled
7005 - * by a special case.
7006 - */
7007 -
7008 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7009 - __u32 level, int del0)
7010 -{
7011 - int i;
7012 - int hasData;
7013 -
7014 - if (tn) {
7015 - hasData = 0;
7016 -
7017 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7018 - if (tn->internal[i] && level > 0) {
7019 - tn->internal[i] =
7020 - yaffs_PruneWorker(dev, tn->internal[i],
7021 - level - 1,
7022 - (i == 0) ? del0 : 1);
7023 - }
7024 -
7025 - if (tn->internal[i])
7026 - hasData++;
7027 - }
7028 -
7029 - if (hasData == 0 && del0) {
7030 - /* Free and return NULL */
7031 -
7032 - yaffs_FreeTnode(dev, tn);
7033 - tn = NULL;
7034 - }
7035 -
7036 - }
7037 -
7038 - return tn;
7039 -
7040 -}
7041 -
7042 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
7043 - yaffs_FileStructure *fStruct)
7044 -{
7045 - int i;
7046 - int hasData;
7047 - int done = 0;
7048 - yaffs_Tnode *tn;
7049 -
7050 - if (fStruct->topLevel > 0) {
7051 - fStruct->top =
7052 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7053 -
7054 - /* Now we have a tree with all the non-zero branches NULL but the height
7055 - * is the same as it was.
7056 - * Let's see if we can trim internal tnodes to shorten the tree.
7057 - * We can do this if only the 0th element in the tnode is in use
7058 - * (ie all the non-zero are NULL)
7059 - */
7060 -
7061 - while (fStruct->topLevel && !done) {
7062 - tn = fStruct->top;
7063 -
7064 - hasData = 0;
7065 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7066 - if (tn->internal[i])
7067 - hasData++;
7068 - }
7069 -
7070 - if (!hasData) {
7071 - fStruct->top = tn->internal[0];
7072 - fStruct->topLevel--;
7073 - yaffs_FreeTnode(dev, tn);
7074 - } else {
7075 - done = 1;
7076 - }
7077 - }
7078 - }
7079 -
7080 - return YAFFS_OK;
7081 -}
7082 -
7083 -/*-------------------- End of File Structure functions.-------------------*/
7084 -
7085 -/* yaffs_CreateFreeObjects creates a bunch more objects and
7086 - * adds them to the object free list.
7087 - */
7088 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
7089 -{
7090 - int i;
7091 - yaffs_Object *newObjects;
7092 - yaffs_ObjectList *list;
7093 -
7094 - if (nObjects < 1)
7095 - return YAFFS_OK;
7096 -
7097 - /* make these things */
7098 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
7099 - list = YMALLOC(sizeof(yaffs_ObjectList));
7100 -
7101 - if (!newObjects || !list) {
7102 - if (newObjects)
7103 - YFREE(newObjects);
7104 - if (list)
7105 - YFREE(list);
7106 - T(YAFFS_TRACE_ALLOCATE,
7107 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
7108 - return YAFFS_FAIL;
7109 - }
7110 -
7111 - /* Hook them into the free list */
7112 - for (i = 0; i < nObjects - 1; i++) {
7113 - newObjects[i].siblings.next =
7114 - (struct ylist_head *)(&newObjects[i + 1]);
7115 - }
7116 -
7117 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
7118 - dev->freeObjects = newObjects;
7119 - dev->nFreeObjects += nObjects;
7120 - dev->nObjectsCreated += nObjects;
7121 -
7122 - /* Now add this bunch of Objects to a list for freeing up. */
7123 -
7124 - list->objects = newObjects;
7125 - list->next = dev->allocatedObjectList;
7126 - dev->allocatedObjectList = list;
7127 -
7128 - return YAFFS_OK;
7129 -}
7130 -
7131 -
7132 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7133 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7134 -{
7135 - yaffs_Object *tn = NULL;
7136 -
7137 -#ifdef VALGRIND_TEST
7138 - tn = YMALLOC(sizeof(yaffs_Object));
7139 -#else
7140 - /* If there are none left make more */
7141 - if (!dev->freeObjects)
7142 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
7143 -
7144 - if (dev->freeObjects) {
7145 - tn = dev->freeObjects;
7146 - dev->freeObjects =
7147 - (yaffs_Object *) (dev->freeObjects->siblings.next);
7148 - dev->nFreeObjects--;
7149 - }
7150 -#endif
7151 - if (tn) {
7152 - /* Now sweeten it up... */
7153 -
7154 - memset(tn, 0, sizeof(yaffs_Object));
7155 - tn->beingCreated = 1;
7156 -
7157 - tn->myDev = dev;
7158 - tn->hdrChunk = 0;
7159 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7160 - YINIT_LIST_HEAD(&(tn->hardLinks));
7161 - YINIT_LIST_HEAD(&(tn->hashLink));
7162 - YINIT_LIST_HEAD(&tn->siblings);
7163 -
7164 -
7165 - /* Now make the directory sane */
7166 - if (dev->rootDir) {
7167 - tn->parent = dev->rootDir;
7168 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
7169 - }
7170 -
7171 - /* Add it to the lost and found directory.
7172 - * NB Can't put root or lostNFound in lostNFound so
7173 - * check if lostNFound exists first
7174 - */
7175 - if (dev->lostNFoundDir)
7176 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
7177 -
7178 - tn->beingCreated = 0;
7179 - }
7180 -
7181 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7182 -
7183 - return tn;
7184 -}
7185 -
7186 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
7187 - __u32 mode)
7188 -{
7189 -
7190 - yaffs_Object *obj =
7191 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
7192 - if (obj) {
7193 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
7194 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
7195 - obj->unlinkAllowed = 0; /* ... or unlink it */
7196 - obj->deleted = 0;
7197 - obj->unlinked = 0;
7198 - obj->yst_mode = mode;
7199 - obj->myDev = dev;
7200 - obj->hdrChunk = 0; /* Not a valid chunk. */
7201 - }
7202 -
7203 - return obj;
7204 -
7205 -}
7206 -
7207 -static void yaffs_UnhashObject(yaffs_Object *tn)
7208 -{
7209 - int bucket;
7210 - yaffs_Device *dev = tn->myDev;
7211 -
7212 - /* If it is still linked into the bucket list, free from the list */
7213 - if (!ylist_empty(&tn->hashLink)) {
7214 - ylist_del_init(&tn->hashLink);
7215 - bucket = yaffs_HashFunction(tn->objectId);
7216 - dev->objectBucket[bucket].count--;
7217 - }
7218 -}
7219 -
7220 -/* FreeObject frees up a Object and puts it back on the free list */
7221 -static void yaffs_FreeObject(yaffs_Object *tn)
7222 -{
7223 - yaffs_Device *dev = tn->myDev;
7224 -
7225 -#ifdef __KERNEL__
7226 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
7227 -#endif
7228 -
7229 - if (tn->parent)
7230 - YBUG();
7231 - if (!ylist_empty(&tn->siblings))
7232 - YBUG();
7233 -
7234 -
7235 -#ifdef __KERNEL__
7236 - if (tn->myInode) {
7237 - /* We're still hooked up to a cached inode.
7238 - * Don't delete now, but mark for later deletion
7239 - */
7240 - tn->deferedFree = 1;
7241 - return;
7242 - }
7243 -#endif
7244 -
7245 - yaffs_UnhashObject(tn);
7246 -
7247 -#ifdef VALGRIND_TEST
7248 - YFREE(tn);
7249 -#else
7250 - /* Link into the free list. */
7251 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
7252 - dev->freeObjects = tn;
7253 - dev->nFreeObjects++;
7254 -#endif
7255 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7256 -}
7257 -
7258 -#ifdef __KERNEL__
7259 -
7260 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
7261 -{
7262 - if (obj->deferedFree)
7263 - yaffs_FreeObject(obj);
7264 -}
7265 -
7266 -#endif
7267 -
7268 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
7269 -{
7270 - /* Free the list of allocated Objects */
7271 -
7272 - yaffs_ObjectList *tmp;
7273 -
7274 - while (dev->allocatedObjectList) {
7275 - tmp = dev->allocatedObjectList->next;
7276 - YFREE(dev->allocatedObjectList->objects);
7277 - YFREE(dev->allocatedObjectList);
7278 -
7279 - dev->allocatedObjectList = tmp;
7280 - }
7281 -
7282 - dev->freeObjects = NULL;
7283 - dev->nFreeObjects = 0;
7284 -}
7285 -
7286 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
7287 -{
7288 - int i;
7289 -
7290 - dev->allocatedObjectList = NULL;
7291 - dev->freeObjects = NULL;
7292 - dev->nFreeObjects = 0;
7293 -
7294 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
7295 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
7296 - dev->objectBucket[i].count = 0;
7297 - }
7298 -}
7299 -
7300 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
7301 -{
7302 - static int x;
7303 - int i;
7304 - int l = 999;
7305 - int lowest = 999999;
7306 -
7307 - /* First let's see if we can find one that's empty. */
7308 -
7309 - for (i = 0; i < 10 && lowest > 0; i++) {
7310 - x++;
7311 - x %= YAFFS_NOBJECT_BUCKETS;
7312 - if (dev->objectBucket[x].count < lowest) {
7313 - lowest = dev->objectBucket[x].count;
7314 - l = x;
7315 - }
7316 -
7317 - }
7318 -
7319 - /* If we didn't find an empty list, then try
7320 - * looking a bit further for a short one
7321 - */
7322 -
7323 - for (i = 0; i < 10 && lowest > 3; i++) {
7324 - x++;
7325 - x %= YAFFS_NOBJECT_BUCKETS;
7326 - if (dev->objectBucket[x].count < lowest) {
7327 - lowest = dev->objectBucket[x].count;
7328 - l = x;
7329 - }
7330 -
7331 - }
7332 -
7333 - return l;
7334 -}
7335 -
7336 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
7337 -{
7338 - int bucket = yaffs_FindNiceObjectBucket(dev);
7339 -
7340 - /* Now find an object value that has not already been taken
7341 - * by scanning the list.
7342 - */
7343 -
7344 - int found = 0;
7345 - struct ylist_head *i;
7346 -
7347 - __u32 n = (__u32) bucket;
7348 -
7349 - /* yaffs_CheckObjectHashSanity(); */
7350 -
7351 - while (!found) {
7352 - found = 1;
7353 - n += YAFFS_NOBJECT_BUCKETS;
7354 - if (1 || dev->objectBucket[bucket].count > 0) {
7355 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
7356 - /* If there is already one in the list */
7357 - if (i && ylist_entry(i, yaffs_Object,
7358 - hashLink)->objectId == n) {
7359 - found = 0;
7360 - }
7361 - }
7362 - }
7363 - }
7364 -
7365 - return n;
7366 -}
7367 -
7368 -static void yaffs_HashObject(yaffs_Object *in)
7369 -{
7370 - int bucket = yaffs_HashFunction(in->objectId);
7371 - yaffs_Device *dev = in->myDev;
7372 -
7373 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
7374 - dev->objectBucket[bucket].count++;
7375 -}
7376 -
7377 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
7378 -{
7379 - int bucket = yaffs_HashFunction(number);
7380 - struct ylist_head *i;
7381 - yaffs_Object *in;
7382 -
7383 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
7384 - /* Look if it is in the list */
7385 - if (i) {
7386 - in = ylist_entry(i, yaffs_Object, hashLink);
7387 - if (in->objectId == number) {
7388 -#ifdef __KERNEL__
7389 - /* Don't tell the VFS about this one if it is defered free */
7390 - if (in->deferedFree)
7391 - return NULL;
7392 -#endif
7393 -
7394 - return in;
7395 - }
7396 - }
7397 - }
7398 -
7399 - return NULL;
7400 -}
7401 -
7402 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
7403 - yaffs_ObjectType type)
7404 -{
7405 - yaffs_Object *theObject;
7406 - yaffs_Tnode *tn = NULL;
7407 -
7408 - if (number < 0)
7409 - number = yaffs_CreateNewObjectNumber(dev);
7410 -
7411 - theObject = yaffs_AllocateEmptyObject(dev);
7412 - if (!theObject)
7413 - return NULL;
7414 -
7415 - if (type == YAFFS_OBJECT_TYPE_FILE) {
7416 - tn = yaffs_GetTnode(dev);
7417 - if (!tn) {
7418 - yaffs_FreeObject(theObject);
7419 - return NULL;
7420 - }
7421 - }
7422 -
7423 - if (theObject) {
7424 - theObject->fake = 0;
7425 - theObject->renameAllowed = 1;
7426 - theObject->unlinkAllowed = 1;
7427 - theObject->objectId = number;
7428 - yaffs_HashObject(theObject);
7429 - theObject->variantType = type;
7430 -#ifdef CONFIG_YAFFS_WINCE
7431 - yfsd_WinFileTimeNow(theObject->win_atime);
7432 - theObject->win_ctime[0] = theObject->win_mtime[0] =
7433 - theObject->win_atime[0];
7434 - theObject->win_ctime[1] = theObject->win_mtime[1] =
7435 - theObject->win_atime[1];
7436 -
7437 -#else
7438 -
7439 - theObject->yst_atime = theObject->yst_mtime =
7440 - theObject->yst_ctime = Y_CURRENT_TIME;
7441 -#endif
7442 - switch (type) {
7443 - case YAFFS_OBJECT_TYPE_FILE:
7444 - theObject->variant.fileVariant.fileSize = 0;
7445 - theObject->variant.fileVariant.scannedFileSize = 0;
7446 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
7447 - theObject->variant.fileVariant.topLevel = 0;
7448 - theObject->variant.fileVariant.top = tn;
7449 - break;
7450 - case YAFFS_OBJECT_TYPE_DIRECTORY:
7451 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
7452 - children);
7453 - break;
7454 - case YAFFS_OBJECT_TYPE_SYMLINK:
7455 - case YAFFS_OBJECT_TYPE_HARDLINK:
7456 - case YAFFS_OBJECT_TYPE_SPECIAL:
7457 - /* No action required */
7458 - break;
7459 - case YAFFS_OBJECT_TYPE_UNKNOWN:
7460 - /* todo this should not happen */
7461 - break;
7462 - }
7463 - }
7464 -
7465 - return theObject;
7466 -}
7467 -
7468 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
7469 - int number,
7470 - yaffs_ObjectType type)
7471 -{
7472 - yaffs_Object *theObject = NULL;
7473 -
7474 - if (number > 0)
7475 - theObject = yaffs_FindObjectByNumber(dev, number);
7476 -
7477 - if (!theObject)
7478 - theObject = yaffs_CreateNewObject(dev, number, type);
7479 -
7480 - return theObject;
7481 -
7482 -}
7483 -
7484 -
7485 -static YCHAR *yaffs_CloneString(const YCHAR *str)
7486 -{
7487 - YCHAR *newStr = NULL;
7488 -
7489 - if (str && *str) {
7490 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
7491 - if (newStr)
7492 - yaffs_strcpy(newStr, str);
7493 - }
7494 -
7495 - return newStr;
7496 -
7497 -}
7498 -
7499 -/*
7500 - * Mknod (create) a new object.
7501 - * equivalentObject only has meaning for a hard link;
7502 - * aliasString only has meaning for a sumlink.
7503 - * rdev only has meaning for devices (a subset of special objects)
7504 - */
7505 -
7506 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
7507 - yaffs_Object *parent,
7508 - const YCHAR *name,
7509 - __u32 mode,
7510 - __u32 uid,
7511 - __u32 gid,
7512 - yaffs_Object *equivalentObject,
7513 - const YCHAR *aliasString, __u32 rdev)
7514 -{
7515 - yaffs_Object *in;
7516 - YCHAR *str = NULL;
7517 -
7518 - yaffs_Device *dev = parent->myDev;
7519 -
7520 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
7521 - if (yaffs_FindObjectByName(parent, name))
7522 - return NULL;
7523 -
7524 - in = yaffs_CreateNewObject(dev, -1, type);
7525 -
7526 - if (!in)
7527 - return YAFFS_FAIL;
7528 -
7529 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
7530 - str = yaffs_CloneString(aliasString);
7531 - if (!str) {
7532 - yaffs_FreeObject(in);
7533 - return NULL;
7534 - }
7535 - }
7536 -
7537 -
7538 -
7539 - if (in) {
7540 - in->hdrChunk = 0;
7541 - in->valid = 1;
7542 - in->variantType = type;
7543 -
7544 - in->yst_mode = mode;
7545 -
7546 -#ifdef CONFIG_YAFFS_WINCE
7547 - yfsd_WinFileTimeNow(in->win_atime);
7548 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
7549 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
7550 -
7551 -#else
7552 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
7553 -
7554 - in->yst_rdev = rdev;
7555 - in->yst_uid = uid;
7556 - in->yst_gid = gid;
7557 -#endif
7558 - in->nDataChunks = 0;
7559 -
7560 - yaffs_SetObjectName(in, name);
7561 - in->dirty = 1;
7562 -
7563 - yaffs_AddObjectToDirectory(parent, in);
7564 -
7565 - in->myDev = parent->myDev;
7566 -
7567 - switch (type) {
7568 - case YAFFS_OBJECT_TYPE_SYMLINK:
7569 - in->variant.symLinkVariant.alias = str;
7570 - break;
7571 - case YAFFS_OBJECT_TYPE_HARDLINK:
7572 - in->variant.hardLinkVariant.equivalentObject =
7573 - equivalentObject;
7574 - in->variant.hardLinkVariant.equivalentObjectId =
7575 - equivalentObject->objectId;
7576 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
7577 - break;
7578 - case YAFFS_OBJECT_TYPE_FILE:
7579 - case YAFFS_OBJECT_TYPE_DIRECTORY:
7580 - case YAFFS_OBJECT_TYPE_SPECIAL:
7581 - case YAFFS_OBJECT_TYPE_UNKNOWN:
7582 - /* do nothing */
7583 - break;
7584 - }
7585 -
7586 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
7587 - /* Could not create the object header, fail the creation */
7588 - yaffs_DeleteObject(in);
7589 - in = NULL;
7590 - }
7591 -
7592 - }
7593 -
7594 - return in;
7595 -}
7596 -
7597 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
7598 - __u32 mode, __u32 uid, __u32 gid)
7599 -{
7600 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
7601 - uid, gid, NULL, NULL, 0);
7602 -}
7603 -
7604 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
7605 - __u32 mode, __u32 uid, __u32 gid)
7606 -{
7607 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
7608 - mode, uid, gid, NULL, NULL, 0);
7609 -}
7610 -
7611 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
7612 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
7613 -{
7614 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
7615 - uid, gid, NULL, NULL, rdev);
7616 -}
7617 -
7618 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
7619 - __u32 mode, __u32 uid, __u32 gid,
7620 - const YCHAR *alias)
7621 -{
7622 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
7623 - uid, gid, NULL, alias, 0);
7624 -}
7625 -
7626 -/* yaffs_Link returns the object id of the equivalent object.*/
7627 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
7628 - yaffs_Object *equivalentObject)
7629 -{
7630 - /* Get the real object in case we were fed a hard link as an equivalent object */
7631 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
7632 -
7633 - if (yaffs_MknodObject
7634 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
7635 - equivalentObject, NULL, 0)) {
7636 - return equivalentObject;
7637 - } else {
7638 - return NULL;
7639 - }
7640 -
7641 -}
7642 -
7643 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
7644 - const YCHAR *newName, int force, int shadows)
7645 -{
7646 - int unlinkOp;
7647 - int deleteOp;
7648 -
7649 - yaffs_Object *existingTarget;
7650 -
7651 - if (newDir == NULL)
7652 - newDir = obj->parent; /* use the old directory */
7653 -
7654 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
7655 - T(YAFFS_TRACE_ALWAYS,
7656 - (TSTR
7657 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
7658 - TENDSTR)));
7659 - YBUG();
7660 - }
7661 -
7662 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
7663 - if (obj->myDev->isYaffs2)
7664 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
7665 - else
7666 - unlinkOp = (newDir == obj->myDev->unlinkedDir
7667 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
7668 -
7669 - deleteOp = (newDir == obj->myDev->deletedDir);
7670 -
7671 - existingTarget = yaffs_FindObjectByName(newDir, newName);
7672 -
7673 - /* If the object is a file going into the unlinked directory,
7674 - * then it is OK to just stuff it in since duplicate names are allowed.
7675 - * else only proceed if the new name does not exist and if we're putting
7676 - * it into a directory.
7677 - */
7678 - if ((unlinkOp ||
7679 - deleteOp ||
7680 - force ||
7681 - (shadows > 0) ||
7682 - !existingTarget) &&
7683 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
7684 - yaffs_SetObjectName(obj, newName);
7685 - obj->dirty = 1;
7686 -
7687 - yaffs_AddObjectToDirectory(newDir, obj);
7688 -
7689 - if (unlinkOp)
7690 - obj->unlinked = 1;
7691 -
7692 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
7693 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
7694 - return YAFFS_OK;
7695 - }
7696 -
7697 - return YAFFS_FAIL;
7698 -}
7699 -
7700 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
7701 - yaffs_Object *newDir, const YCHAR *newName)
7702 -{
7703 - yaffs_Object *obj = NULL;
7704 - yaffs_Object *existingTarget = NULL;
7705 - int force = 0;
7706 -
7707 -
7708 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7709 - YBUG();
7710 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7711 - YBUG();
7712 -
7713 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
7714 - /* Special case for case insemsitive systems (eg. WinCE).
7715 - * While look-up is case insensitive, the name isn't.
7716 - * Therefore we might want to change x.txt to X.txt
7717 - */
7718 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
7719 - force = 1;
7720 -#endif
7721 -
7722 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
7723 - /* ENAMETOOLONG */
7724 - return YAFFS_FAIL;
7725 -
7726 - obj = yaffs_FindObjectByName(oldDir, oldName);
7727 -
7728 - if (obj && obj->renameAllowed) {
7729 -
7730 - /* Now do the handling for an existing target, if there is one */
7731 -
7732 - existingTarget = yaffs_FindObjectByName(newDir, newName);
7733 - if (existingTarget &&
7734 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
7735 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
7736 - /* There is a target that is a non-empty directory, so we fail */
7737 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
7738 - } else if (existingTarget && existingTarget != obj) {
7739 - /* Nuke the target first, using shadowing,
7740 - * but only if it isn't the same object
7741 - */
7742 - yaffs_ChangeObjectName(obj, newDir, newName, force,
7743 - existingTarget->objectId);
7744 - yaffs_UnlinkObject(existingTarget);
7745 - }
7746 -
7747 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
7748 - }
7749 - return YAFFS_FAIL;
7750 -}
7751 -
7752 -/*------------------------- Block Management and Page Allocation ----------------*/
7753 -
7754 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
7755 -{
7756 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
7757 -
7758 - dev->blockInfo = NULL;
7759 - dev->chunkBits = NULL;
7760 -
7761 - dev->allocationBlock = -1; /* force it to get a new one */
7762 -
7763 - /* If the first allocation strategy fails, thry the alternate one */
7764 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
7765 - if (!dev->blockInfo) {
7766 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
7767 - dev->blockInfoAlt = 1;
7768 - } else
7769 - dev->blockInfoAlt = 0;
7770 -
7771 - if (dev->blockInfo) {
7772 - /* Set up dynamic blockinfo stuff. */
7773 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
7774 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
7775 - if (!dev->chunkBits) {
7776 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
7777 - dev->chunkBitsAlt = 1;
7778 - } else
7779 - dev->chunkBitsAlt = 0;
7780 - }
7781 -
7782 - if (dev->blockInfo && dev->chunkBits) {
7783 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
7784 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
7785 - return YAFFS_OK;
7786 - }
7787 -
7788 - return YAFFS_FAIL;
7789 -}
7790 -
7791 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
7792 -{
7793 - if (dev->blockInfoAlt && dev->blockInfo)
7794 - YFREE_ALT(dev->blockInfo);
7795 - else if (dev->blockInfo)
7796 - YFREE(dev->blockInfo);
7797 -
7798 - dev->blockInfoAlt = 0;
7799 -
7800 - dev->blockInfo = NULL;
7801 -
7802 - if (dev->chunkBitsAlt && dev->chunkBits)
7803 - YFREE_ALT(dev->chunkBits);
7804 - else if (dev->chunkBits)
7805 - YFREE(dev->chunkBits);
7806 - dev->chunkBitsAlt = 0;
7807 - dev->chunkBits = NULL;
7808 -}
7809 -
7810 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
7811 - yaffs_BlockInfo *bi)
7812 -{
7813 - int i;
7814 - __u32 seq;
7815 - yaffs_BlockInfo *b;
7816 -
7817 - if (!dev->isYaffs2)
7818 - return 1; /* disqualification only applies to yaffs2. */
7819 -
7820 - if (!bi->hasShrinkHeader)
7821 - return 1; /* can gc */
7822 -
7823 - /* Find the oldest dirty sequence number if we don't know it and save it
7824 - * so we don't have to keep recomputing it.
7825 - */
7826 - if (!dev->oldestDirtySequence) {
7827 - seq = dev->sequenceNumber;
7828 -
7829 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
7830 - i++) {
7831 - b = yaffs_GetBlockInfo(dev, i);
7832 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
7833 - (b->pagesInUse - b->softDeletions) <
7834 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
7835 - seq = b->sequenceNumber;
7836 - }
7837 - }
7838 - dev->oldestDirtySequence = seq;
7839 - }
7840 -
7841 - /* Can't do gc of this block if there are any blocks older than this one that have
7842 - * discarded pages.
7843 - */
7844 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
7845 -}
7846 -
7847 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
7848 - * for garbage collection.
7849 - */
7850 -
7851 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
7852 - int aggressive)
7853 -{
7854 - int b = dev->currentDirtyChecker;
7855 -
7856 - int i;
7857 - int iterations;
7858 - int dirtiest = -1;
7859 - int pagesInUse = 0;
7860 - int prioritised = 0;
7861 - yaffs_BlockInfo *bi;
7862 - int pendingPrioritisedExist = 0;
7863 -
7864 - /* First let's see if we need to grab a prioritised block */
7865 - if (dev->hasPendingPrioritisedGCs) {
7866 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
7867 -
7868 - bi = yaffs_GetBlockInfo(dev, i);
7869 - /* yaffs_VerifyBlock(dev,bi,i); */
7870 -
7871 - if (bi->gcPrioritise) {
7872 - pendingPrioritisedExist = 1;
7873 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
7874 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
7875 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
7876 - dirtiest = i;
7877 - prioritised = 1;
7878 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
7879 - }
7880 - }
7881 - }
7882 -
7883 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
7884 - dev->hasPendingPrioritisedGCs = 0;
7885 - }
7886 -
7887 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
7888 - * search harder.
7889 - * else (we're doing a leasurely gc), then we only bother to do this if the
7890 - * block has only a few pages in use.
7891 - */
7892 -
7893 - dev->nonAggressiveSkip--;
7894 -
7895 - if (!aggressive && (dev->nonAggressiveSkip > 0))
7896 - return -1;
7897 -
7898 - if (!prioritised)
7899 - pagesInUse =
7900 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
7901 -
7902 - if (aggressive)
7903 - iterations =
7904 - dev->internalEndBlock - dev->internalStartBlock + 1;
7905 - else {
7906 - iterations =
7907 - dev->internalEndBlock - dev->internalStartBlock + 1;
7908 - iterations = iterations / 16;
7909 - if (iterations > 200)
7910 - iterations = 200;
7911 - }
7912 -
7913 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
7914 - b++;
7915 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
7916 - b = dev->internalStartBlock;
7917 -
7918 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
7919 - T(YAFFS_TRACE_ERROR,
7920 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
7921 - YBUG();
7922 - }
7923 -
7924 - bi = yaffs_GetBlockInfo(dev, b);
7925 -
7926 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
7927 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
7928 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
7929 - dirtiest = b;
7930 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
7931 - }
7932 - }
7933 -
7934 - dev->currentDirtyChecker = b;
7935 -
7936 - if (dirtiest > 0) {
7937 - T(YAFFS_TRACE_GC,
7938 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
7939 - dev->nChunksPerBlock - pagesInUse, prioritised));
7940 - }
7941 -
7942 - dev->oldestDirtySequence = 0;
7943 -
7944 - if (dirtiest > 0)
7945 - dev->nonAggressiveSkip = 4;
7946 -
7947 - return dirtiest;
7948 -}
7949 -
7950 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
7951 -{
7952 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
7953 -
7954 - int erasedOk = 0;
7955 -
7956 - /* If the block is still healthy erase it and mark as clean.
7957 - * If the block has had a data failure, then retire it.
7958 - */
7959 -
7960 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
7961 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
7962 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
7963 -
7964 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
7965 -
7966 - if (!bi->needsRetiring) {
7967 - yaffs_InvalidateCheckpoint(dev);
7968 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
7969 - if (!erasedOk) {
7970 - dev->nErasureFailures++;
7971 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
7972 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
7973 - }
7974 - }
7975 -
7976 - if (erasedOk &&
7977 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
7978 - int i;
7979 - for (i = 0; i < dev->nChunksPerBlock; i++) {
7980 - if (!yaffs_CheckChunkErased
7981 - (dev, blockNo * dev->nChunksPerBlock + i)) {
7982 - T(YAFFS_TRACE_ERROR,
7983 - (TSTR
7984 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
7985 - TENDSTR), blockNo, i));
7986 - }
7987 - }
7988 - }
7989 -
7990 - if (erasedOk) {
7991 - /* Clean it up... */
7992 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
7993 - dev->nErasedBlocks++;
7994 - bi->pagesInUse = 0;
7995 - bi->softDeletions = 0;
7996 - bi->hasShrinkHeader = 0;
7997 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
7998 - bi->gcPrioritise = 0;
7999 - yaffs_ClearChunkBits(dev, blockNo);
8000 -
8001 - T(YAFFS_TRACE_ERASE,
8002 - (TSTR("Erased block %d" TENDSTR), blockNo));
8003 - } else {
8004 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
8005 -
8006 - yaffs_RetireBlock(dev, blockNo);
8007 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
8008 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
8009 - }
8010 -}
8011 -
8012 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
8013 -{
8014 - int i;
8015 -
8016 - yaffs_BlockInfo *bi;
8017 -
8018 - if (dev->nErasedBlocks < 1) {
8019 - /* Hoosterman we've got a problem.
8020 - * Can't get space to gc
8021 - */
8022 - T(YAFFS_TRACE_ERROR,
8023 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
8024 -
8025 - return -1;
8026 - }
8027 -
8028 - /* Find an empty block. */
8029 -
8030 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
8031 - dev->allocationBlockFinder++;
8032 - if (dev->allocationBlockFinder < dev->internalStartBlock
8033 - || dev->allocationBlockFinder > dev->internalEndBlock) {
8034 - dev->allocationBlockFinder = dev->internalStartBlock;
8035 - }
8036 -
8037 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
8038 -
8039 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
8040 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
8041 - dev->sequenceNumber++;
8042 - bi->sequenceNumber = dev->sequenceNumber;
8043 - dev->nErasedBlocks--;
8044 - T(YAFFS_TRACE_ALLOCATE,
8045 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
8046 - dev->allocationBlockFinder, dev->sequenceNumber,
8047 - dev->nErasedBlocks));
8048 - return dev->allocationBlockFinder;
8049 - }
8050 - }
8051 -
8052 - T(YAFFS_TRACE_ALWAYS,
8053 - (TSTR
8054 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
8055 - TENDSTR), dev->nErasedBlocks));
8056 -
8057 - return -1;
8058 -}
8059 -
8060 -
8061 -
8062 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
8063 -{
8064 - if (!dev->nCheckpointBlocksRequired &&
8065 - dev->isYaffs2) {
8066 - /* Not a valid value so recalculate */
8067 - int nBytes = 0;
8068 - int nBlocks;
8069 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
8070 - int tnodeSize;
8071 -
8072 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
8073 -
8074 - if (tnodeSize < sizeof(yaffs_Tnode))
8075 - tnodeSize = sizeof(yaffs_Tnode);
8076 -
8077 - nBytes += sizeof(yaffs_CheckpointValidity);
8078 - nBytes += sizeof(yaffs_CheckpointDevice);
8079 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
8080 - nBytes += devBlocks * dev->chunkBitmapStride;
8081 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
8082 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
8083 - nBytes += sizeof(yaffs_CheckpointValidity);
8084 - nBytes += sizeof(__u32); /* checksum*/
8085 -
8086 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
8087 -
8088 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
8089 -
8090 - dev->nCheckpointBlocksRequired = nBlocks;
8091 - }
8092 -
8093 - return dev->nCheckpointBlocksRequired;
8094 -}
8095 -
8096 -/*
8097 - * Check if there's space to allocate...
8098 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
8099 - */
8100 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
8101 -{
8102 - int reservedChunks;
8103 - int reservedBlocks = dev->nReservedBlocks;
8104 - int checkpointBlocks;
8105 -
8106 - if (dev->isYaffs2) {
8107 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
8108 - dev->blocksInCheckpoint;
8109 - if (checkpointBlocks < 0)
8110 - checkpointBlocks = 0;
8111 - } else {
8112 - checkpointBlocks = 0;
8113 - }
8114 -
8115 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
8116 -
8117 - return (dev->nFreeChunks > reservedChunks);
8118 -}
8119 -
8120 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
8121 - yaffs_BlockInfo **blockUsedPtr)
8122 -{
8123 - int retVal;
8124 - yaffs_BlockInfo *bi;
8125 -
8126 - if (dev->allocationBlock < 0) {
8127 - /* Get next block to allocate off */
8128 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
8129 - dev->allocationPage = 0;
8130 - }
8131 -
8132 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
8133 - /* Not enough space to allocate unless we're allowed to use the reserve. */
8134 - return -1;
8135 - }
8136 -
8137 - if (dev->nErasedBlocks < dev->nReservedBlocks
8138 - && dev->allocationPage == 0) {
8139 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
8140 - }
8141 -
8142 - /* Next page please.... */
8143 - if (dev->allocationBlock >= 0) {
8144 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
8145 -
8146 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
8147 - dev->allocationPage;
8148 - bi->pagesInUse++;
8149 - yaffs_SetChunkBit(dev, dev->allocationBlock,
8150 - dev->allocationPage);
8151 -
8152 - dev->allocationPage++;
8153 -
8154 - dev->nFreeChunks--;
8155 -
8156 - /* If the block is full set the state to full */
8157 - if (dev->allocationPage >= dev->nChunksPerBlock) {
8158 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
8159 - dev->allocationBlock = -1;
8160 - }
8161 -
8162 - if (blockUsedPtr)
8163 - *blockUsedPtr = bi;
8164 -
8165 - return retVal;
8166 - }
8167 -
8168 - T(YAFFS_TRACE_ERROR,
8169 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
8170 -
8171 - return -1;
8172 -}
8173 -
8174 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
8175 -{
8176 - int n;
8177 -
8178 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
8179 -
8180 - if (dev->allocationBlock > 0)
8181 - n += (dev->nChunksPerBlock - dev->allocationPage);
8182 -
8183 - return n;
8184 -
8185 -}
8186 -
8187 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
8188 - int wholeBlock)
8189 -{
8190 - int oldChunk;
8191 - int newChunk;
8192 - int markNAND;
8193 - int retVal = YAFFS_OK;
8194 - int cleanups = 0;
8195 - int i;
8196 - int isCheckpointBlock;
8197 - int matchingChunk;
8198 - int maxCopies;
8199 -
8200 - int chunksBefore = yaffs_GetErasedChunks(dev);
8201 - int chunksAfter;
8202 -
8203 - yaffs_ExtendedTags tags;
8204 -
8205 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
8206 -
8207 - yaffs_Object *object;
8208 -
8209 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
8210 -
8211 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
8212 -
8213 - T(YAFFS_TRACE_TRACING,
8214 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
8215 - block,
8216 - bi->pagesInUse,
8217 - bi->hasShrinkHeader,
8218 - wholeBlock));
8219 -
8220 - /*yaffs_VerifyFreeChunks(dev); */
8221 -
8222 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
8223 -
8224 - /* Take off the number of soft deleted entries because
8225 - * they're going to get really deleted during GC.
8226 - */
8227 - dev->nFreeChunks -= bi->softDeletions;
8228 -
8229 - dev->isDoingGC = 1;
8230 -
8231 - if (isCheckpointBlock ||
8232 - !yaffs_StillSomeChunkBits(dev, block)) {
8233 - T(YAFFS_TRACE_TRACING,
8234 - (TSTR
8235 - ("Collecting block %d that has no chunks in use" TENDSTR),
8236 - block));
8237 - yaffs_BlockBecameDirty(dev, block);
8238 - } else {
8239 -
8240 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
8241 -
8242 - yaffs_VerifyBlock(dev, bi, block);
8243 -
8244 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
8245 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
8246 -
8247 - for (/* init already done */;
8248 - retVal == YAFFS_OK &&
8249 - dev->gcChunk < dev->nChunksPerBlock &&
8250 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
8251 - maxCopies > 0;
8252 - dev->gcChunk++, oldChunk++) {
8253 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
8254 -
8255 - /* This page is in use and might need to be copied off */
8256 -
8257 - maxCopies--;
8258 -
8259 - markNAND = 1;
8260 -
8261 - yaffs_InitialiseTags(&tags);
8262 -
8263 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
8264 - buffer, &tags);
8265 -
8266 - object =
8267 - yaffs_FindObjectByNumber(dev,
8268 - tags.objectId);
8269 -
8270 - T(YAFFS_TRACE_GC_DETAIL,
8271 - (TSTR
8272 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
8273 - dev->gcChunk, tags.objectId, tags.chunkId,
8274 - tags.byteCount));
8275 -
8276 - if (object && !yaffs_SkipVerification(dev)) {
8277 - if (tags.chunkId == 0)
8278 - matchingChunk = object->hdrChunk;
8279 - else if (object->softDeleted)
8280 - matchingChunk = oldChunk; /* Defeat the test */
8281 - else
8282 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
8283 -
8284 - if (oldChunk != matchingChunk)
8285 - T(YAFFS_TRACE_ERROR,
8286 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
8287 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
8288 -
8289 - }
8290 -
8291 - if (!object) {
8292 - T(YAFFS_TRACE_ERROR,
8293 - (TSTR
8294 - ("page %d in gc has no object: %d %d %d "
8295 - TENDSTR), oldChunk,
8296 - tags.objectId, tags.chunkId, tags.byteCount));
8297 - }
8298 -
8299 - if (object &&
8300 - object->deleted &&
8301 - object->softDeleted &&
8302 - tags.chunkId != 0) {
8303 - /* Data chunk in a soft deleted file, throw it away
8304 - * It's a soft deleted data chunk,
8305 - * No need to copy this, just forget about it and
8306 - * fix up the object.
8307 - */
8308 -
8309 - object->nDataChunks--;
8310 -
8311 - if (object->nDataChunks <= 0) {
8312 - /* remeber to clean up the object */
8313 - dev->gcCleanupList[cleanups] =
8314 - tags.objectId;
8315 - cleanups++;
8316 - }
8317 - markNAND = 0;
8318 - } else if (0) {
8319 - /* Todo object && object->deleted && object->nDataChunks == 0 */
8320 - /* Deleted object header with no data chunks.
8321 - * Can be discarded and the file deleted.
8322 - */
8323 - object->hdrChunk = 0;
8324 - yaffs_FreeTnode(object->myDev,
8325 - object->variant.
8326 - fileVariant.top);
8327 - object->variant.fileVariant.top = NULL;
8328 - yaffs_DoGenericObjectDeletion(object);
8329 -
8330 - } else if (object) {
8331 - /* It's either a data chunk in a live file or
8332 - * an ObjectHeader, so we're interested in it.
8333 - * NB Need to keep the ObjectHeaders of deleted files
8334 - * until the whole file has been deleted off
8335 - */
8336 - tags.serialNumber++;
8337 -
8338 - dev->nGCCopies++;
8339 -
8340 - if (tags.chunkId == 0) {
8341 - /* It is an object Id,
8342 - * We need to nuke the shrinkheader flags first
8343 - * We no longer want the shrinkHeader flag since its work is done
8344 - * and if it is left in place it will mess up scanning.
8345 - */
8346 -
8347 - yaffs_ObjectHeader *oh;
8348 - oh = (yaffs_ObjectHeader *)buffer;
8349 - oh->isShrink = 0;
8350 - tags.extraIsShrinkHeader = 0;
8351 -
8352 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
8353 - }
8354 -
8355 - newChunk =
8356 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
8357 -
8358 - if (newChunk < 0) {
8359 - retVal = YAFFS_FAIL;
8360 - } else {
8361 -
8362 - /* Ok, now fix up the Tnodes etc. */
8363 -
8364 - if (tags.chunkId == 0) {
8365 - /* It's a header */
8366 - object->hdrChunk = newChunk;
8367 - object->serial = tags.serialNumber;
8368 - } else {
8369 - /* It's a data chunk */
8370 - yaffs_PutChunkIntoFile
8371 - (object,
8372 - tags.chunkId,
8373 - newChunk, 0);
8374 - }
8375 - }
8376 - }
8377 -
8378 - if (retVal == YAFFS_OK)
8379 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
8380 -
8381 - }
8382 - }
8383 -
8384 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8385 -
8386 -
8387 - /* Do any required cleanups */
8388 - for (i = 0; i < cleanups; i++) {
8389 - /* Time to delete the file too */
8390 - object =
8391 - yaffs_FindObjectByNumber(dev,
8392 - dev->gcCleanupList[i]);
8393 - if (object) {
8394 - yaffs_FreeTnode(dev,
8395 - object->variant.fileVariant.
8396 - top);
8397 - object->variant.fileVariant.top = NULL;
8398 - T(YAFFS_TRACE_GC,
8399 - (TSTR
8400 - ("yaffs: About to finally delete object %d"
8401 - TENDSTR), object->objectId));
8402 - yaffs_DoGenericObjectDeletion(object);
8403 - object->myDev->nDeletedFiles--;
8404 - }
8405 -
8406 - }
8407 -
8408 - }
8409 -
8410 - yaffs_VerifyCollectedBlock(dev, bi, block);
8411 -
8412 - chunksAfter = yaffs_GetErasedChunks(dev);
8413 - if (chunksBefore >= chunksAfter) {
8414 - T(YAFFS_TRACE_GC,
8415 - (TSTR
8416 - ("gc did not increase free chunks before %d after %d"
8417 - TENDSTR), chunksBefore, chunksAfter));
8418 - }
8419 -
8420 - /* If the gc completed then clear the current gcBlock so that we find another. */
8421 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
8422 - dev->gcBlock = -1;
8423 - dev->gcChunk = 0;
8424 - }
8425 -
8426 - dev->isDoingGC = 0;
8427 -
8428 - return retVal;
8429 -}
8430 -
8431 -/* New garbage collector
8432 - * If we're very low on erased blocks then we do aggressive garbage collection
8433 - * otherwise we do "leasurely" garbage collection.
8434 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
8435 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
8436 - *
8437 - * The idea is to help clear out space in a more spread-out manner.
8438 - * Dunno if it really does anything useful.
8439 - */
8440 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
8441 -{
8442 - int block;
8443 - int aggressive;
8444 - int gcOk = YAFFS_OK;
8445 - int maxTries = 0;
8446 -
8447 - int checkpointBlockAdjust;
8448 -
8449 - if (dev->isDoingGC) {
8450 - /* Bail out so we don't get recursive gc */
8451 - return YAFFS_OK;
8452 - }
8453 -
8454 - /* This loop should pass the first time.
8455 - * We'll only see looping here if the erase of the collected block fails.
8456 - */
8457 -
8458 - do {
8459 - maxTries++;
8460 -
8461 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
8462 - if (checkpointBlockAdjust < 0)
8463 - checkpointBlockAdjust = 0;
8464 -
8465 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
8466 - /* We need a block soon...*/
8467 - aggressive = 1;
8468 - } else {
8469 - /* We're in no hurry */
8470 - aggressive = 0;
8471 - }
8472 -
8473 - if (dev->gcBlock <= 0) {
8474 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
8475 - dev->gcChunk = 0;
8476 - }
8477 -
8478 - block = dev->gcBlock;
8479 -
8480 - if (block > 0) {
8481 - dev->garbageCollections++;
8482 - if (!aggressive)
8483 - dev->passiveGarbageCollections++;
8484 -
8485 - T(YAFFS_TRACE_GC,
8486 - (TSTR
8487 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
8488 - dev->nErasedBlocks, aggressive));
8489 -
8490 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
8491 - }
8492 -
8493 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
8494 - T(YAFFS_TRACE_GC,
8495 - (TSTR
8496 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
8497 - TENDSTR), dev->nErasedBlocks, maxTries, block));
8498 - }
8499 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
8500 - (block > 0) &&
8501 - (maxTries < 2));
8502 -
8503 - return aggressive ? gcOk : YAFFS_OK;
8504 -}
8505 -
8506 -/*------------------------- TAGS --------------------------------*/
8507 -
8508 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
8509 - int chunkInObject)
8510 -{
8511 - return (tags->chunkId == chunkInObject &&
8512 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
8513 -
8514 -}
8515 -
8516 -
8517 -/*-------------------- Data file manipulation -----------------*/
8518 -
8519 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
8520 - yaffs_ExtendedTags *tags)
8521 -{
8522 - /*Get the Tnode, then get the level 0 offset chunk offset */
8523 - yaffs_Tnode *tn;
8524 - int theChunk = -1;
8525 - yaffs_ExtendedTags localTags;
8526 - int retVal = -1;
8527 -
8528 - yaffs_Device *dev = in->myDev;
8529 -
8530 - if (!tags) {
8531 - /* Passed a NULL, so use our own tags space */
8532 - tags = &localTags;
8533 - }
8534 -
8535 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
8536 -
8537 - if (tn) {
8538 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8539 -
8540 - retVal =
8541 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
8542 - chunkInInode);
8543 - }
8544 - return retVal;
8545 -}
8546 -
8547 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
8548 - yaffs_ExtendedTags *tags)
8549 -{
8550 - /* Get the Tnode, then get the level 0 offset chunk offset */
8551 - yaffs_Tnode *tn;
8552 - int theChunk = -1;
8553 - yaffs_ExtendedTags localTags;
8554 -
8555 - yaffs_Device *dev = in->myDev;
8556 - int retVal = -1;
8557 -
8558 - if (!tags) {
8559 - /* Passed a NULL, so use our own tags space */
8560 - tags = &localTags;
8561 - }
8562 -
8563 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
8564 -
8565 - if (tn) {
8566 -
8567 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8568 -
8569 - retVal =
8570 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
8571 - chunkInInode);
8572 -
8573 - /* Delete the entry in the filestructure (if found) */
8574 - if (retVal != -1)
8575 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
8576 - }
8577 -
8578 - return retVal;
8579 -}
8580 -
8581 -#ifdef YAFFS_PARANOID
8582 -
8583 -static int yaffs_CheckFileSanity(yaffs_Object *in)
8584 -{
8585 - int chunk;
8586 - int nChunks;
8587 - int fSize;
8588 - int failed = 0;
8589 - int objId;
8590 - yaffs_Tnode *tn;
8591 - yaffs_Tags localTags;
8592 - yaffs_Tags *tags = &localTags;
8593 - int theChunk;
8594 - int chunkDeleted;
8595 -
8596 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
8597 - return YAFFS_FAIL;
8598 -
8599 - objId = in->objectId;
8600 - fSize = in->variant.fileVariant.fileSize;
8601 - nChunks =
8602 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
8603 -
8604 - for (chunk = 1; chunk <= nChunks; chunk++) {
8605 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
8606 - chunk);
8607 -
8608 - if (tn) {
8609 -
8610 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
8611 -
8612 - if (yaffs_CheckChunkBits
8613 - (dev, theChunk / dev->nChunksPerBlock,
8614 - theChunk % dev->nChunksPerBlock)) {
8615 -
8616 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
8617 - tags,
8618 - &chunkDeleted);
8619 - if (yaffs_TagsMatch
8620 - (tags, in->objectId, chunk, chunkDeleted)) {
8621 - /* found it; */
8622 -
8623 - }
8624 - } else {
8625 -
8626 - failed = 1;
8627 - }
8628 -
8629 - } else {
8630 - /* T(("No level 0 found for %d\n", chunk)); */
8631 - }
8632 - }
8633 -
8634 - return failed ? YAFFS_FAIL : YAFFS_OK;
8635 -}
8636 -
8637 -#endif
8638 -
8639 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
8640 - int chunkInNAND, int inScan)
8641 -{
8642 - /* NB inScan is zero unless scanning.
8643 - * For forward scanning, inScan is > 0;
8644 - * for backward scanning inScan is < 0
8645 - */
8646 -
8647 - yaffs_Tnode *tn;
8648 - yaffs_Device *dev = in->myDev;
8649 - int existingChunk;
8650 - yaffs_ExtendedTags existingTags;
8651 - yaffs_ExtendedTags newTags;
8652 - unsigned existingSerial, newSerial;
8653 -
8654 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
8655 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
8656 - * If it is not during Scanning then something went wrong!
8657 - */
8658 - if (!inScan) {
8659 - T(YAFFS_TRACE_ERROR,
8660 - (TSTR
8661 - ("yaffs tragedy:attempt to put data chunk into a non-file"
8662 - TENDSTR)));
8663 - YBUG();
8664 - }
8665 -
8666 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
8667 - return YAFFS_OK;
8668 - }
8669 -
8670 - tn = yaffs_AddOrFindLevel0Tnode(dev,
8671 - &in->variant.fileVariant,
8672 - chunkInInode,
8673 - NULL);
8674 - if (!tn)
8675 - return YAFFS_FAIL;
8676 -
8677 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8678 -
8679 - if (inScan != 0) {
8680 - /* If we're scanning then we need to test for duplicates
8681 - * NB This does not need to be efficient since it should only ever
8682 - * happen when the power fails during a write, then only one
8683 - * chunk should ever be affected.
8684 - *
8685 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
8686 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
8687 - */
8688 -
8689 - if (existingChunk > 0) {
8690 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
8691 - * thus we have to do a FindChunkInFile to get the real chunk id.
8692 - *
8693 - * We have a duplicate now we need to decide which one to use:
8694 - *
8695 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
8696 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
8697 - * YAFFS1: Get both sets of tags and compare serial numbers.
8698 - */
8699 -
8700 - if (inScan > 0) {
8701 - /* Only do this for forward scanning */
8702 - yaffs_ReadChunkWithTagsFromNAND(dev,
8703 - chunkInNAND,
8704 - NULL, &newTags);
8705 -
8706 - /* Do a proper find */
8707 - existingChunk =
8708 - yaffs_FindChunkInFile(in, chunkInInode,
8709 - &existingTags);
8710 - }
8711 -
8712 - if (existingChunk <= 0) {
8713 - /*Hoosterman - how did this happen? */
8714 -
8715 - T(YAFFS_TRACE_ERROR,
8716 - (TSTR
8717 - ("yaffs tragedy: existing chunk < 0 in scan"
8718 - TENDSTR)));
8719 -
8720 - }
8721 -
8722 - /* NB The deleted flags should be false, otherwise the chunks will
8723 - * not be loaded during a scan
8724 - */
8725 -
8726 - if (inScan > 0) {
8727 - newSerial = newTags.serialNumber;
8728 - existingSerial = existingTags.serialNumber;
8729 - }
8730 -
8731 - if ((inScan > 0) &&
8732 - (in->myDev->isYaffs2 ||
8733 - existingChunk <= 0 ||
8734 - ((existingSerial + 1) & 3) == newSerial)) {
8735 - /* Forward scanning.
8736 - * Use new
8737 - * Delete the old one and drop through to update the tnode
8738 - */
8739 - yaffs_DeleteChunk(dev, existingChunk, 1,
8740 - __LINE__);
8741 - } else {
8742 - /* Backward scanning or we want to use the existing one
8743 - * Use existing.
8744 - * Delete the new one and return early so that the tnode isn't changed
8745 - */
8746 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
8747 - __LINE__);
8748 - return YAFFS_OK;
8749 - }
8750 - }
8751 -
8752 - }
8753 -
8754 - if (existingChunk == 0)
8755 - in->nDataChunks++;
8756 -
8757 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
8758 -
8759 - return YAFFS_OK;
8760 -}
8761 -
8762 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
8763 - __u8 *buffer)
8764 -{
8765 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
8766 -
8767 - if (chunkInNAND >= 0)
8768 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
8769 - buffer, NULL);
8770 - else {
8771 - T(YAFFS_TRACE_NANDACCESS,
8772 - (TSTR("Chunk %d not found zero instead" TENDSTR),
8773 - chunkInNAND));
8774 - /* get sane (zero) data if you read a hole */
8775 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
8776 - return 0;
8777 - }
8778 -
8779 -}
8780 -
8781 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
8782 -{
8783 - int block;
8784 - int page;
8785 - yaffs_ExtendedTags tags;
8786 - yaffs_BlockInfo *bi;
8787 -
8788 - if (chunkId <= 0)
8789 - return;
8790 -
8791 - dev->nDeletions++;
8792 - block = chunkId / dev->nChunksPerBlock;
8793 - page = chunkId % dev->nChunksPerBlock;
8794 -
8795 -
8796 - if (!yaffs_CheckChunkBit(dev, block, page))
8797 - T(YAFFS_TRACE_VERIFY,
8798 - (TSTR("Deleting invalid chunk %d"TENDSTR),
8799 - chunkId));
8800 -
8801 - bi = yaffs_GetBlockInfo(dev, block);
8802 -
8803 - T(YAFFS_TRACE_DELETION,
8804 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
8805 -
8806 - if (markNAND &&
8807 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
8808 -
8809 - yaffs_InitialiseTags(&tags);
8810 -
8811 - tags.chunkDeleted = 1;
8812 -
8813 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
8814 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
8815 - } else {
8816 - dev->nUnmarkedDeletions++;
8817 - }
8818 -
8819 - /* Pull out of the management area.
8820 - * If the whole block became dirty, this will kick off an erasure.
8821 - */
8822 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8823 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8824 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8825 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8826 - dev->nFreeChunks++;
8827 -
8828 - yaffs_ClearChunkBit(dev, block, page);
8829 -
8830 - bi->pagesInUse--;
8831 -
8832 - if (bi->pagesInUse == 0 &&
8833 - !bi->hasShrinkHeader &&
8834 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8835 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8836 - yaffs_BlockBecameDirty(dev, block);
8837 - }
8838 -
8839 - }
8840 -
8841 -}
8842 -
8843 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8844 - const __u8 *buffer, int nBytes,
8845 - int useReserve)
8846 -{
8847 - /* Find old chunk Need to do this to get serial number
8848 - * Write new one and patch into tree.
8849 - * Invalidate old tags.
8850 - */
8851 -
8852 - int prevChunkId;
8853 - yaffs_ExtendedTags prevTags;
8854 -
8855 - int newChunkId;
8856 - yaffs_ExtendedTags newTags;
8857 -
8858 - yaffs_Device *dev = in->myDev;
8859 -
8860 - yaffs_CheckGarbageCollection(dev);
8861 -
8862 - /* Get the previous chunk at this location in the file if it exists */
8863 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8864 -
8865 - /* Set up new tags */
8866 - yaffs_InitialiseTags(&newTags);
8867 -
8868 - newTags.chunkId = chunkInInode;
8869 - newTags.objectId = in->objectId;
8870 - newTags.serialNumber =
8871 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8872 - newTags.byteCount = nBytes;
8873 -
8874 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8875 - T(YAFFS_TRACE_ERROR,
8876 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8877 - YBUG();
8878 - }
8879 -
8880 - newChunkId =
8881 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8882 - useReserve);
8883 -
8884 - if (newChunkId >= 0) {
8885 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8886 -
8887 - if (prevChunkId >= 0)
8888 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8889 -
8890 - yaffs_CheckFileSanity(in);
8891 - }
8892 - return newChunkId;
8893 -
8894 -}
8895 -
8896 -/* UpdateObjectHeader updates the header on NAND for an object.
8897 - * If name is not NULL, then that new name is used.
8898 - */
8899 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8900 - int isShrink, int shadows)
8901 -{
8902 -
8903 - yaffs_BlockInfo *bi;
8904 -
8905 - yaffs_Device *dev = in->myDev;
8906 -
8907 - int prevChunkId;
8908 - int retVal = 0;
8909 - int result = 0;
8910 -
8911 - int newChunkId;
8912 - yaffs_ExtendedTags newTags;
8913 - yaffs_ExtendedTags oldTags;
8914 -
8915 - __u8 *buffer = NULL;
8916 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8917 -
8918 - yaffs_ObjectHeader *oh = NULL;
8919 + yaffs_obj_t *in;
8920 + YCHAR *str = NULL;
8921
8922 - yaffs_strcpy(oldName, _Y("silly old name"));
8923 + yaffs_dev_t *dev = parent->my_dev;
8924
8925 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8926 + if (yaffs_find_by_name(parent, name))
8927 + return NULL;
8928
8929 - if (!in->fake ||
8930 - in == dev->rootDir || /* The rootDir should also be saved */
8931 - force) {
8932 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8933 + str = yaffs_clone_str(aliasString);
8934 + if (!str)
8935 + return NULL;
8936 + }
8937
8938 - yaffs_CheckGarbageCollection(dev);
8939 - yaffs_CheckObjectDetailsLoaded(in);
8940 + in = yaffs_new_obj(dev, -1, type);
8941
8942 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8943 - oh = (yaffs_ObjectHeader *) buffer;
8944 + if (!in){
8945 + if(str)
8946 + YFREE(str);
8947 + return NULL;
8948 + }
8949
8950 - prevChunkId = in->hdrChunk;
8951
8952 - if (prevChunkId > 0) {
8953 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8954 - buffer, &oldTags);
8955
8956 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8957
8958 - memcpy(oldName, oh->name, sizeof(oh->name));
8959 - }
8960
8961 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8962 + if (in) {
8963 + in->hdr_chunk = 0;
8964 + in->valid = 1;
8965 + in->variant_type = type;
8966
8967 - oh->type = in->variantType;
8968 - oh->yst_mode = in->yst_mode;
8969 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8970 + in->yst_mode = mode;
8971
8972 #ifdef CONFIG_YAFFS_WINCE
8973 - oh->win_atime[0] = in->win_atime[0];
8974 - oh->win_ctime[0] = in->win_ctime[0];
8975 - oh->win_mtime[0] = in->win_mtime[0];
8976 - oh->win_atime[1] = in->win_atime[1];
8977 - oh->win_ctime[1] = in->win_ctime[1];
8978 - oh->win_mtime[1] = in->win_mtime[1];
8979 + yfsd_win_file_time_now(in->win_atime);
8980 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8981 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
8982 +
8983 #else
8984 - oh->yst_uid = in->yst_uid;
8985 - oh->yst_gid = in->yst_gid;
8986 - oh->yst_atime = in->yst_atime;
8987 - oh->yst_mtime = in->yst_mtime;
8988 - oh->yst_ctime = in->yst_ctime;
8989 - oh->yst_rdev = in->yst_rdev;
8990 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
8991 +
8992 + in->yst_rdev = rdev;
8993 + in->yst_uid = uid;
8994 + in->yst_gid = gid;
8995 #endif
8996 - if (in->parent)
8997 - oh->parentObjectId = in->parent->objectId;
8998 - else
8999 - oh->parentObjectId = 0;
9000 + in->n_data_chunks = 0;
9001
9002 - if (name && *name) {
9003 - memset(oh->name, 0, sizeof(oh->name));
9004 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
9005 - } else if (prevChunkId >= 0)
9006 - memcpy(oh->name, oldName, sizeof(oh->name));
9007 - else
9008 - memset(oh->name, 0, sizeof(oh->name));
9009 + yaffs_set_obj_name(in, name);
9010 + in->dirty = 1;
9011
9012 - oh->isShrink = isShrink;
9013 + yaffs_add_obj_to_dir(parent, in);
9014
9015 - switch (in->variantType) {
9016 - case YAFFS_OBJECT_TYPE_UNKNOWN:
9017 - /* Should not happen */
9018 - break;
9019 - case YAFFS_OBJECT_TYPE_FILE:
9020 - oh->fileSize =
9021 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
9022 - || oh->parentObjectId ==
9023 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
9024 - fileVariant.fileSize;
9025 + in->my_dev = parent->my_dev;
9026 +
9027 + switch (type) {
9028 + case YAFFS_OBJECT_TYPE_SYMLINK:
9029 + in->variant.symlink_variant.alias = str;
9030 break;
9031 case YAFFS_OBJECT_TYPE_HARDLINK:
9032 - oh->equivalentObjectId =
9033 - in->variant.hardLinkVariant.equivalentObjectId;
9034 - break;
9035 - case YAFFS_OBJECT_TYPE_SPECIAL:
9036 - /* Do nothing */
9037 + in->variant.hardlink_variant.equiv_obj =
9038 + equiv_obj;
9039 + in->variant.hardlink_variant.equiv_id =
9040 + equiv_obj->obj_id;
9041 + ylist_add(&in->hard_links, &equiv_obj->hard_links);
9042 break;
9043 + case YAFFS_OBJECT_TYPE_FILE:
9044 case YAFFS_OBJECT_TYPE_DIRECTORY:
9045 - /* Do nothing */
9046 - break;
9047 - case YAFFS_OBJECT_TYPE_SYMLINK:
9048 - yaffs_strncpy(oh->alias,
9049 - in->variant.symLinkVariant.alias,
9050 - YAFFS_MAX_ALIAS_LENGTH);
9051 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
9052 + case YAFFS_OBJECT_TYPE_SPECIAL:
9053 + case YAFFS_OBJECT_TYPE_UNKNOWN:
9054 + /* do nothing */
9055 break;
9056 }
9057
9058 - /* Tags */
9059 - yaffs_InitialiseTags(&newTags);
9060 - in->serial++;
9061 - newTags.chunkId = 0;
9062 - newTags.objectId = in->objectId;
9063 - newTags.serialNumber = in->serial;
9064 -
9065 - /* Add extra info for file header */
9066 -
9067 - newTags.extraHeaderInfoAvailable = 1;
9068 - newTags.extraParentObjectId = oh->parentObjectId;
9069 - newTags.extraFileLength = oh->fileSize;
9070 - newTags.extraIsShrinkHeader = oh->isShrink;
9071 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
9072 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
9073 - newTags.extraObjectType = in->variantType;
9074 -
9075 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
9076 -
9077 - /* Create new chunk in NAND */
9078 - newChunkId =
9079 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
9080 - (prevChunkId >= 0) ? 1 : 0);
9081 -
9082 - if (newChunkId >= 0) {
9083 -
9084 - in->hdrChunk = newChunkId;
9085 -
9086 - if (prevChunkId >= 0) {
9087 - yaffs_DeleteChunk(dev, prevChunkId, 1,
9088 - __LINE__);
9089 - }
9090 -
9091 - if (!yaffs_ObjectHasCachedWriteData(in))
9092 - in->dirty = 0;
9093 -
9094 - /* If this was a shrink, then mark the block that the chunk lives on */
9095 - if (isShrink) {
9096 - bi = yaffs_GetBlockInfo(in->myDev,
9097 - newChunkId / in->myDev->nChunksPerBlock);
9098 - bi->hasShrinkHeader = 1;
9099 - }
9100 -
9101 + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
9102 + /* Could not create the object header, fail the creation */
9103 + yaffs_del_obj(in);
9104 + in = NULL;
9105 }
9106
9107 - retVal = newChunkId;
9108 -
9109 + yaffs_update_parent(parent);
9110 }
9111
9112 - if (buffer)
9113 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9114 -
9115 - return retVal;
9116 + return in;
9117 }
9118
9119 -/*------------------------ Short Operations Cache ----------------------------------------
9120 - * In many situations where there is no high level buffering (eg WinCE) a lot of
9121 - * reads might be short sequential reads, and a lot of writes may be short
9122 - * sequential writes. eg. scanning/writing a jpeg file.
9123 - * In these cases, a short read/write cache can provide a huge perfomance benefit
9124 - * with dumb-as-a-rock code.
9125 - * In Linux, the page cache provides read buffering aand the short op cache provides write
9126 - * buffering.
9127 - *
9128 - * There are a limited number (~10) of cache chunks per device so that we don't
9129 - * need a very intelligent search.
9130 - */
9131 -
9132 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
9133 +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
9134 + __u32 mode, __u32 uid, __u32 gid)
9135 {
9136 - yaffs_Device *dev = obj->myDev;
9137 - int i;
9138 - yaffs_ChunkCache *cache;
9139 - int nCaches = obj->myDev->nShortOpCaches;
9140 -
9141 - for (i = 0; i < nCaches; i++) {
9142 - cache = &dev->srCache[i];
9143 - if (cache->object == obj &&
9144 - cache->dirty)
9145 - return 1;
9146 - }
9147 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
9148 + uid, gid, NULL, NULL, 0);
9149 +}
9150
9151 - return 0;
9152 +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
9153 + __u32 mode, __u32 uid, __u32 gid)
9154 +{
9155 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
9156 + mode, uid, gid, NULL, NULL, 0);
9157 }
9158
9159 +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
9160 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
9161 +{
9162 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
9163 + uid, gid, NULL, NULL, rdev);
9164 +}
9165
9166 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
9167 +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
9168 + __u32 mode, __u32 uid, __u32 gid,
9169 + const YCHAR *alias)
9170 {
9171 - yaffs_Device *dev = obj->myDev;
9172 - int lowest = -99; /* Stop compiler whining. */
9173 - int i;
9174 - yaffs_ChunkCache *cache;
9175 - int chunkWritten = 0;
9176 - int nCaches = obj->myDev->nShortOpCaches;
9177 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
9178 + uid, gid, NULL, alias, 0);
9179 +}
9180
9181 - if (nCaches > 0) {
9182 - do {
9183 - cache = NULL;
9184 +/* yaffs_link_obj returns the object id of the equivalent object.*/
9185 +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
9186 + yaffs_obj_t *equiv_obj)
9187 +{
9188 + /* Get the real object in case we were fed a hard link as an equivalent object */
9189 + equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
9190
9191 - /* Find the dirty cache for this object with the lowest chunk id. */
9192 - for (i = 0; i < nCaches; i++) {
9193 - if (dev->srCache[i].object == obj &&
9194 - dev->srCache[i].dirty) {
9195 - if (!cache
9196 - || dev->srCache[i].chunkId <
9197 - lowest) {
9198 - cache = &dev->srCache[i];
9199 - lowest = cache->chunkId;
9200 - }
9201 - }
9202 - }
9203 + if (yaffs_create_obj
9204 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
9205 + equiv_obj, NULL, 0)) {
9206 + return equiv_obj;
9207 + } else {
9208 + return NULL;
9209 + }
9210
9211 - if (cache && !cache->locked) {
9212 - /* Write it out and free it up */
9213 +}
9214
9215 - chunkWritten =
9216 - yaffs_WriteChunkDataToObject(cache->object,
9217 - cache->chunkId,
9218 - cache->data,
9219 - cache->nBytes,
9220 - 1);
9221 - cache->dirty = 0;
9222 - cache->object = NULL;
9223 - }
9224 +static int yaffs_change_obj_name(yaffs_obj_t *obj, yaffs_obj_t *new_dir,
9225 + const YCHAR *new_name, int force, int shadows)
9226 +{
9227 + int unlinkOp;
9228 + int deleteOp;
9229
9230 - } while (cache && chunkWritten > 0);
9231 + yaffs_obj_t *existingTarget;
9232
9233 - if (cache) {
9234 - /* Hoosterman, disk full while writing cache out. */
9235 - T(YAFFS_TRACE_ERROR,
9236 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
9237 + if (new_dir == NULL)
9238 + new_dir = obj->parent; /* use the old directory */
9239
9240 - }
9241 + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
9242 + T(YAFFS_TRACE_ALWAYS,
9243 + (TSTR
9244 + ("tragedy: yaffs_change_obj_name: new_dir is not a directory"
9245 + TENDSTR)));
9246 + YBUG();
9247 }
9248
9249 -}
9250 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
9251 + if (obj->my_dev->param.is_yaffs2)
9252 + unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
9253 + else
9254 + unlinkOp = (new_dir == obj->my_dev->unlinked_dir
9255 + && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
9256
9257 -/*yaffs_FlushEntireDeviceCache(dev)
9258 - *
9259 - *
9260 - */
9261 + deleteOp = (new_dir == obj->my_dev->del_dir);
9262
9263 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
9264 -{
9265 - yaffs_Object *obj;
9266 - int nCaches = dev->nShortOpCaches;
9267 - int i;
9268 + existingTarget = yaffs_find_by_name(new_dir, new_name);
9269
9270 - /* Find a dirty object in the cache and flush it...
9271 - * until there are no further dirty objects.
9272 + /* If the object is a file going into the unlinked directory,
9273 + * then it is OK to just stuff it in since duplicate names are allowed.
9274 + * else only proceed if the new name does not exist and if we're putting
9275 + * it into a directory.
9276 */
9277 - do {
9278 - obj = NULL;
9279 - for (i = 0; i < nCaches && !obj; i++) {
9280 - if (dev->srCache[i].object &&
9281 - dev->srCache[i].dirty)
9282 - obj = dev->srCache[i].object;
9283 -
9284 - }
9285 - if (obj)
9286 - yaffs_FlushFilesChunkCache(obj);
9287 -
9288 - } while (obj);
9289 -
9290 -}
9291 + if ((unlinkOp ||
9292 + deleteOp ||
9293 + force ||
9294 + (shadows > 0) ||
9295 + !existingTarget) &&
9296 + new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
9297 + yaffs_set_obj_name(obj, new_name);
9298 + obj->dirty = 1;
9299
9300 + yaffs_add_obj_to_dir(new_dir, obj);
9301
9302 -/* Grab us a cache chunk for use.
9303 - * First look for an empty one.
9304 - * Then look for the least recently used non-dirty one.
9305 - * Then look for the least recently used dirty one...., flush and look again.
9306 - */
9307 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
9308 -{
9309 - int i;
9310 + if (unlinkOp)
9311 + obj->unlinked = 1;
9312
9313 - if (dev->nShortOpCaches > 0) {
9314 - for (i = 0; i < dev->nShortOpCaches; i++) {
9315 - if (!dev->srCache[i].object)
9316 - return &dev->srCache[i];
9317 - }
9318 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
9319 + if (yaffs_update_oh(obj, new_name, 0, deleteOp, shadows, NULL) >= 0)
9320 + return YAFFS_OK;
9321 }
9322
9323 - return NULL;
9324 + return YAFFS_FAIL;
9325 }
9326
9327 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
9328 +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
9329 + yaffs_obj_t *new_dir, const YCHAR *new_name)
9330 {
9331 - yaffs_ChunkCache *cache;
9332 - yaffs_Object *theObj;
9333 - int usage;
9334 - int i;
9335 - int pushout;
9336 -
9337 - if (dev->nShortOpCaches > 0) {
9338 - /* Try find a non-dirty one... */
9339 -
9340 - cache = yaffs_GrabChunkCacheWorker(dev);
9341 + yaffs_obj_t *obj = NULL;
9342 + yaffs_obj_t *existingTarget = NULL;
9343 + int force = 0;
9344 + int result;
9345 + yaffs_dev_t *dev;
9346
9347 - if (!cache) {
9348 - /* They were all dirty, find the last recently used object and flush
9349 - * its cache, then find again.
9350 - * NB what's here is not very accurate, we actually flush the object
9351 - * the last recently used page.
9352 - */
9353
9354 - /* With locking we can't assume we can use entry zero */
9355 + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
9356 + YBUG();
9357 + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
9358 + YBUG();
9359
9360 - theObj = NULL;
9361 - usage = -1;
9362 - cache = NULL;
9363 - pushout = -1;
9364 + dev = old_dir->my_dev;
9365
9366 - for (i = 0; i < dev->nShortOpCaches; i++) {
9367 - if (dev->srCache[i].object &&
9368 - !dev->srCache[i].locked &&
9369 - (dev->srCache[i].lastUse < usage || !cache)) {
9370 - usage = dev->srCache[i].lastUse;
9371 - theObj = dev->srCache[i].object;
9372 - cache = &dev->srCache[i];
9373 - pushout = i;
9374 - }
9375 - }
9376 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
9377 + /* Special case for case insemsitive systems (eg. WinCE).
9378 + * While look-up is case insensitive, the name isn't.
9379 + * Therefore we might want to change x.txt to X.txt
9380 + */
9381 + if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0)
9382 + force = 1;
9383 +#endif
9384
9385 - if (!cache || cache->dirty) {
9386 - /* Flush and try again */
9387 - yaffs_FlushFilesChunkCache(theObj);
9388 - cache = yaffs_GrabChunkCacheWorker(dev);
9389 - }
9390 + if(yaffs_strnlen(new_name,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
9391 + /* ENAMETOOLONG */
9392 + return YAFFS_FAIL;
9393
9394 - }
9395 - return cache;
9396 - } else
9397 - return NULL;
9398 + obj = yaffs_find_by_name(old_dir, old_name);
9399
9400 -}
9401 + if (obj && obj->rename_allowed) {
9402
9403 -/* Find a cached chunk */
9404 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
9405 - int chunkId)
9406 -{
9407 - yaffs_Device *dev = obj->myDev;
9408 - int i;
9409 - if (dev->nShortOpCaches > 0) {
9410 - for (i = 0; i < dev->nShortOpCaches; i++) {
9411 - if (dev->srCache[i].object == obj &&
9412 - dev->srCache[i].chunkId == chunkId) {
9413 - dev->cacheHits++;
9414 + /* Now do the handling for an existing target, if there is one */
9415
9416 - return &dev->srCache[i];
9417 - }
9418 + existingTarget = yaffs_find_by_name(new_dir, new_name);
9419 + if (existingTarget &&
9420 + existingTarget->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
9421 + !ylist_empty(&existingTarget->variant.dir_variant.children)) {
9422 + /* There is a target that is a non-empty directory, so we fail */
9423 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
9424 + } else if (existingTarget && existingTarget != obj) {
9425 + /* Nuke the target first, using shadowing,
9426 + * but only if it isn't the same object.
9427 + *
9428 + * Note we must disable gc otherwise it can mess up the shadowing.
9429 + *
9430 + */
9431 + dev->gc_disable=1;
9432 + yaffs_change_obj_name(obj, new_dir, new_name, force,
9433 + existingTarget->obj_id);
9434 + existingTarget->is_shadowed = 1;
9435 + yaffs_unlink_obj(existingTarget);
9436 + dev->gc_disable=0;
9437 }
9438 +
9439 + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
9440 +
9441 + yaffs_update_parent(old_dir);
9442 + if(new_dir != old_dir)
9443 + yaffs_update_parent(new_dir);
9444 +
9445 + return result;
9446 }
9447 - return NULL;
9448 + return YAFFS_FAIL;
9449 }
9450
9451 -/* Mark the chunk for the least recently used algorithym */
9452 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
9453 - int isAWrite)
9454 +/*------------------------- Block Management and Page Allocation ----------------*/
9455 +
9456 +static int yaffs_init_blocks(yaffs_dev_t *dev)
9457 {
9458 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
9459
9460 - if (dev->nShortOpCaches > 0) {
9461 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
9462 - /* Reset the cache usages */
9463 - int i;
9464 - for (i = 1; i < dev->nShortOpCaches; i++)
9465 - dev->srCache[i].lastUse = 0;
9466 + dev->block_info = NULL;
9467 + dev->chunk_bits = NULL;
9468
9469 - dev->srLastUse = 0;
9470 - }
9471 + dev->alloc_block = -1; /* force it to get a new one */
9472
9473 - dev->srLastUse++;
9474 + /* If the first allocation strategy fails, thry the alternate one */
9475 + dev->block_info = YMALLOC(nBlocks * sizeof(yaffs_block_info_t));
9476 + if (!dev->block_info) {
9477 + dev->block_info = YMALLOC_ALT(nBlocks * sizeof(yaffs_block_info_t));
9478 + dev->block_info_alt = 1;
9479 + } else
9480 + dev->block_info_alt = 0;
9481
9482 - cache->lastUse = dev->srLastUse;
9483 + if (dev->block_info) {
9484 + /* Set up dynamic blockinfo stuff. */
9485 + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; /* round up bytes */
9486 + dev->chunk_bits = YMALLOC(dev->chunk_bit_stride * nBlocks);
9487 + if (!dev->chunk_bits) {
9488 + dev->chunk_bits = YMALLOC_ALT(dev->chunk_bit_stride * nBlocks);
9489 + dev->chunk_bits_alt = 1;
9490 + } else
9491 + dev->chunk_bits_alt = 0;
9492 + }
9493
9494 - if (isAWrite)
9495 - cache->dirty = 1;
9496 + if (dev->block_info && dev->chunk_bits) {
9497 + memset(dev->block_info, 0, nBlocks * sizeof(yaffs_block_info_t));
9498 + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * nBlocks);
9499 + return YAFFS_OK;
9500 }
9501 +
9502 + return YAFFS_FAIL;
9503 }
9504
9505 -/* Invalidate a single cache page.
9506 - * Do this when a whole page gets written,
9507 - * ie the short cache for this page is no longer valid.
9508 - */
9509 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
9510 +static void yaffs_deinit_blocks(yaffs_dev_t *dev)
9511 {
9512 - if (object->myDev->nShortOpCaches > 0) {
9513 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
9514 + if (dev->block_info_alt && dev->block_info)
9515 + YFREE_ALT(dev->block_info);
9516 + else if (dev->block_info)
9517 + YFREE(dev->block_info);
9518
9519 - if (cache)
9520 - cache->object = NULL;
9521 - }
9522 -}
9523 + dev->block_info_alt = 0;
9524
9525 -/* Invalidate all the cache pages associated with this object
9526 - * Do this whenever ther file is deleted or resized.
9527 - */
9528 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
9529 -{
9530 - int i;
9531 - yaffs_Device *dev = in->myDev;
9532 + dev->block_info = NULL;
9533
9534 - if (dev->nShortOpCaches > 0) {
9535 - /* Invalidate it. */
9536 - for (i = 0; i < dev->nShortOpCaches; i++) {
9537 - if (dev->srCache[i].object == in)
9538 - dev->srCache[i].object = NULL;
9539 - }
9540 - }
9541 + if (dev->chunk_bits_alt && dev->chunk_bits)
9542 + YFREE_ALT(dev->chunk_bits);
9543 + else if (dev->chunk_bits)
9544 + YFREE(dev->chunk_bits);
9545 + dev->chunk_bits_alt = 0;
9546 + dev->chunk_bits = NULL;
9547 }
9548
9549 -/*--------------------- Checkpointing --------------------*/
9550 +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no)
9551 +{
9552 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block_no);
9553
9554 + int erasedOk = 0;
9555
9556 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
9557 -{
9558 - yaffs_CheckpointValidity cp;
9559 + /* If the block is still healthy erase it and mark as clean.
9560 + * If the block has had a data failure, then retire it.
9561 + */
9562
9563 - memset(&cp, 0, sizeof(cp));
9564 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9565 + (TSTR("yaffs_block_became_dirty block %d state %d %s"TENDSTR),
9566 + block_no, bi->block_state, (bi->needs_retiring) ? "needs retiring" : ""));
9567
9568 - cp.structType = sizeof(cp);
9569 - cp.magic = YAFFS_MAGIC;
9570 - cp.version = YAFFS_CHECKPOINT_VERSION;
9571 - cp.head = (head) ? 1 : 0;
9572 + yaffs2_clear_oldest_dirty_seq(dev,bi);
9573
9574 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
9575 - 1 : 0;
9576 -}
9577 + bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
9578
9579 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
9580 -{
9581 - yaffs_CheckpointValidity cp;
9582 - int ok;
9583 + /* If this is the block being garbage collected then stop gc'ing this block */
9584 + if(block_no == dev->gc_block)
9585 + dev->gc_block = 0;
9586
9587 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9588 + /* If this block is currently the best candidate for gc then drop as a candidate */
9589 + if(block_no == dev->gc_dirtiest){
9590 + dev->gc_dirtiest = 0;
9591 + dev->gc_pages_in_use = 0;
9592 + }
9593
9594 - if (ok)
9595 - ok = (cp.structType == sizeof(cp)) &&
9596 - (cp.magic == YAFFS_MAGIC) &&
9597 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
9598 - (cp.head == ((head) ? 1 : 0));
9599 - return ok ? 1 : 0;
9600 -}
9601 + if (!bi->needs_retiring) {
9602 + yaffs2_checkpt_invalidate(dev);
9603 + erasedOk = yaffs_erase_block(dev, block_no);
9604 + if (!erasedOk) {
9605 + dev->n_erase_failures++;
9606 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9607 + (TSTR("**>> Erasure failed %d" TENDSTR), block_no));
9608 + }
9609 + }
9610
9611 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
9612 - yaffs_Device *dev)
9613 -{
9614 - cp->nErasedBlocks = dev->nErasedBlocks;
9615 - cp->allocationBlock = dev->allocationBlock;
9616 - cp->allocationPage = dev->allocationPage;
9617 - cp->nFreeChunks = dev->nFreeChunks;
9618 + if (erasedOk &&
9619 + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || !yaffs_skip_verification(dev))) {
9620 + int i;
9621 + for (i = 0; i < dev->param.chunks_per_block; i++) {
9622 + if (!yaffs_check_chunk_erased
9623 + (dev, block_no * dev->param.chunks_per_block + i)) {
9624 + T(YAFFS_TRACE_ERROR,
9625 + (TSTR
9626 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9627 + TENDSTR), block_no, i));
9628 + }
9629 + }
9630 + }
9631 +
9632 + if (erasedOk) {
9633 + /* Clean it up... */
9634 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
9635 + bi->seq_number = 0;
9636 + dev->n_erased_blocks++;
9637 + bi->pages_in_use = 0;
9638 + bi->soft_del_pages = 0;
9639 + bi->has_shrink_hdr = 0;
9640 + bi->skip_erased_check = 1; /* This is clean, so no need to check */
9641 + bi->gc_prioritise = 0;
9642 + yaffs_clear_chunk_bits(dev, block_no);
9643
9644 - cp->nDeletedFiles = dev->nDeletedFiles;
9645 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9646 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9647 - cp->sequenceNumber = dev->sequenceNumber;
9648 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9649 + T(YAFFS_TRACE_ERASE,
9650 + (TSTR("Erased block %d" TENDSTR), block_no));
9651 + } else {
9652 + dev->n_free_chunks -= dev->param.chunks_per_block; /* We lost a block of free space */
9653
9654 + yaffs_retire_block(dev, block_no);
9655 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9656 + (TSTR("**>> Block %d retired" TENDSTR), block_no));
9657 + }
9658 }
9659
9660 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9661 - yaffs_CheckpointDevice *cp)
9662 +static int yaffs_find_alloc_block(yaffs_dev_t *dev)
9663 {
9664 - dev->nErasedBlocks = cp->nErasedBlocks;
9665 - dev->allocationBlock = cp->allocationBlock;
9666 - dev->allocationPage = cp->allocationPage;
9667 - dev->nFreeChunks = cp->nFreeChunks;
9668 -
9669 - dev->nDeletedFiles = cp->nDeletedFiles;
9670 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9671 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9672 - dev->sequenceNumber = cp->sequenceNumber;
9673 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9674 -}
9675 + int i;
9676
9677 + yaffs_block_info_t *bi;
9678
9679 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9680 -{
9681 - yaffs_CheckpointDevice cp;
9682 - __u32 nBytes;
9683 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9684 + if (dev->n_erased_blocks < 1) {
9685 + /* Hoosterman we've got a problem.
9686 + * Can't get space to gc
9687 + */
9688 + T(YAFFS_TRACE_ERROR,
9689 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9690
9691 - int ok;
9692 + return -1;
9693 + }
9694
9695 - /* Write device runtime values*/
9696 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9697 - cp.structType = sizeof(cp);
9698 + /* Find an empty block. */
9699
9700 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9701 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
9702 + dev->alloc_block_finder++;
9703 + if (dev->alloc_block_finder < dev->internal_start_block
9704 + || dev->alloc_block_finder > dev->internal_end_block) {
9705 + dev->alloc_block_finder = dev->internal_start_block;
9706 + }
9707
9708 - /* Write block info */
9709 - if (ok) {
9710 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9711 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9712 + bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
9713 +
9714 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
9715 + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
9716 + dev->seq_number++;
9717 + bi->seq_number = dev->seq_number;
9718 + dev->n_erased_blocks--;
9719 + T(YAFFS_TRACE_ALLOCATE,
9720 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9721 + dev->alloc_block_finder, dev->seq_number,
9722 + dev->n_erased_blocks));
9723 + return dev->alloc_block_finder;
9724 + }
9725 }
9726
9727 - /* Write chunk bits */
9728 - if (ok) {
9729 - nBytes = nBlocks * dev->chunkBitmapStride;
9730 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9731 - }
9732 - return ok ? 1 : 0;
9733 + T(YAFFS_TRACE_ALWAYS,
9734 + (TSTR
9735 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9736 + TENDSTR), dev->n_erased_blocks));
9737
9738 + return -1;
9739 }
9740
9741 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9742 +
9743 +/*
9744 + * Check if there's space to allocate...
9745 + * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()?
9746 + */
9747 +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks)
9748 {
9749 - yaffs_CheckpointDevice cp;
9750 - __u32 nBytes;
9751 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9752 + int reservedChunks;
9753 + int reservedBlocks = dev->param.n_reserved_blocks;
9754 + int checkpointBlocks;
9755
9756 - int ok;
9757 + checkpointBlocks = yaffs_calc_checkpt_blocks_required(dev);
9758
9759 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9760 - if (!ok)
9761 - return 0;
9762 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.chunks_per_block);
9763
9764 - if (cp.structType != sizeof(cp))
9765 - return 0;
9766 + return (dev->n_free_chunks > (reservedChunks + n_chunks));
9767 +}
9768 +
9769 +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
9770 + yaffs_block_info_t **blockUsedPtr)
9771 +{
9772 + int retVal;
9773 + yaffs_block_info_t *bi;
9774 +
9775 + if (dev->alloc_block < 0) {
9776 + /* Get next block to allocate off */
9777 + dev->alloc_block = yaffs_find_alloc_block(dev);
9778 + dev->alloc_page = 0;
9779 + }
9780
9781 + if (!useReserve && !yaffs_check_alloc_available(dev, 1)) {
9782 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9783 + return -1;
9784 + }
9785
9786 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9787 + if (dev->n_erased_blocks < dev->param.n_reserved_blocks
9788 + && dev->alloc_page == 0) {
9789 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9790 + }
9791
9792 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9793 + /* Next page please.... */
9794 + if (dev->alloc_block >= 0) {
9795 + bi = yaffs_get_block_info(dev, dev->alloc_block);
9796
9797 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9798 + retVal = (dev->alloc_block * dev->param.chunks_per_block) +
9799 + dev->alloc_page;
9800 + bi->pages_in_use++;
9801 + yaffs_set_chunk_bit(dev, dev->alloc_block,
9802 + dev->alloc_page);
9803
9804 - if (!ok)
9805 - return 0;
9806 - nBytes = nBlocks * dev->chunkBitmapStride;
9807 + dev->alloc_page++;
9808
9809 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9810 + dev->n_free_chunks--;
9811
9812 - return ok ? 1 : 0;
9813 -}
9814 + /* If the block is full set the state to full */
9815 + if (dev->alloc_page >= dev->param.chunks_per_block) {
9816 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
9817 + dev->alloc_block = -1;
9818 + }
9819
9820 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9821 - yaffs_Object *obj)
9822 -{
9823 + if (blockUsedPtr)
9824 + *blockUsedPtr = bi;
9825 +
9826 + return retVal;
9827 + }
9828
9829 - cp->objectId = obj->objectId;
9830 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9831 - cp->hdrChunk = obj->hdrChunk;
9832 - cp->variantType = obj->variantType;
9833 - cp->deleted = obj->deleted;
9834 - cp->softDeleted = obj->softDeleted;
9835 - cp->unlinked = obj->unlinked;
9836 - cp->fake = obj->fake;
9837 - cp->renameAllowed = obj->renameAllowed;
9838 - cp->unlinkAllowed = obj->unlinkAllowed;
9839 - cp->serial = obj->serial;
9840 - cp->nDataChunks = obj->nDataChunks;
9841 + T(YAFFS_TRACE_ERROR,
9842 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9843
9844 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9845 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9846 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9847 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9848 + return -1;
9849 }
9850
9851 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9852 +static int yaffs_get_erased_chunks(yaffs_dev_t *dev)
9853 {
9854 + int n;
9855
9856 - yaffs_Object *parent;
9857 + n = dev->n_erased_blocks * dev->param.chunks_per_block;
9858
9859 - if (obj->variantType != cp->variantType) {
9860 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9861 - TCONT("chunk %d does not match existing object type %d")
9862 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9863 - obj->variantType));
9864 - return 0;
9865 - }
9866 + if (dev->alloc_block > 0)
9867 + n += (dev->param.chunks_per_block - dev->alloc_page);
9868
9869 - obj->objectId = cp->objectId;
9870 + return n;
9871
9872 - if (cp->parentId)
9873 - parent = yaffs_FindOrCreateObjectByNumber(
9874 - obj->myDev,
9875 - cp->parentId,
9876 - YAFFS_OBJECT_TYPE_DIRECTORY);
9877 - else
9878 - parent = NULL;
9879 +}
9880
9881 - if (parent) {
9882 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9883 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9884 - TCONT(" chunk %d Parent type, %d, not directory")
9885 - TENDSTR),
9886 - cp->objectId, cp->parentId, cp->variantType,
9887 - cp->hdrChunk, parent->variantType));
9888 - return 0;
9889 +/*
9890 + * yaffs_skip_rest_of_block() skips over the rest of the allocation block
9891 + * if we don't want to write to it.
9892 + */
9893 +void yaffs_skip_rest_of_block(yaffs_dev_t *dev)
9894 +{
9895 + if(dev->alloc_block > 0){
9896 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->alloc_block);
9897 + if(bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING){
9898 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
9899 + dev->alloc_block = -1;
9900 }
9901 - yaffs_AddObjectToDirectory(parent, obj);
9902 }
9903 -
9904 - obj->hdrChunk = cp->hdrChunk;
9905 - obj->variantType = cp->variantType;
9906 - obj->deleted = cp->deleted;
9907 - obj->softDeleted = cp->softDeleted;
9908 - obj->unlinked = cp->unlinked;
9909 - obj->fake = cp->fake;
9910 - obj->renameAllowed = cp->renameAllowed;
9911 - obj->unlinkAllowed = cp->unlinkAllowed;
9912 - obj->serial = cp->serial;
9913 - obj->nDataChunks = cp->nDataChunks;
9914 -
9915 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9916 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9917 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9918 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9919 -
9920 - if (obj->hdrChunk > 0)
9921 - obj->lazyLoaded = 1;
9922 - return 1;
9923 }
9924
9925
9926 -
9927 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9928 - __u32 level, int chunkOffset)
9929 +static int yaffs_gc_block(yaffs_dev_t *dev, int block,
9930 + int wholeBlock)
9931 {
9932 + int oldChunk;
9933 + int newChunk;
9934 + int mark_flash;
9935 + int retVal = YAFFS_OK;
9936 int i;
9937 - yaffs_Device *dev = in->myDev;
9938 - int ok = 1;
9939 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9940 -
9941 - if (tnodeSize < sizeof(yaffs_Tnode))
9942 - tnodeSize = sizeof(yaffs_Tnode);
9943 + int isCheckpointBlock;
9944 + int matchingChunk;
9945 + int maxCopies;
9946
9947 + int chunksBefore = yaffs_get_erased_chunks(dev);
9948 + int chunksAfter;
9949
9950 - if (tn) {
9951 - if (level > 0) {
9952 + yaffs_ext_tags tags;
9953
9954 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9955 - if (tn->internal[i]) {
9956 - ok = yaffs_CheckpointTnodeWorker(in,
9957 - tn->internal[i],
9958 - level - 1,
9959 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9960 - }
9961 - }
9962 - } else if (level == 0) {
9963 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9964 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9965 - if (ok)
9966 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9967 - }
9968 - }
9969 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block);
9970
9971 - return ok;
9972 + yaffs_obj_t *object;
9973
9974 -}
9975 + isCheckpointBlock = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
9976
9977 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9978 -{
9979 - __u32 endMarker = ~0;
9980 - int ok = 1;
9981
9982 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
9983 - ok = yaffs_CheckpointTnodeWorker(obj,
9984 - obj->variant.fileVariant.top,
9985 - obj->variant.fileVariant.topLevel,
9986 - 0);
9987 - if (ok)
9988 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
9989 - sizeof(endMarker));
9990 - }
9991 + T(YAFFS_TRACE_TRACING,
9992 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
9993 + block,
9994 + bi->pages_in_use,
9995 + bi->has_shrink_hdr,
9996 + wholeBlock));
9997
9998 - return ok ? 1 : 0;
9999 -}
10000 + /*yaffs_verify_free_chunks(dev); */
10001
10002 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
10003 -{
10004 - __u32 baseChunk;
10005 - int ok = 1;
10006 - yaffs_Device *dev = obj->myDev;
10007 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
10008 - yaffs_Tnode *tn;
10009 - int nread = 0;
10010 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
10011 + if(bi->block_state == YAFFS_BLOCK_STATE_FULL)
10012 + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
10013 +
10014 + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
10015
10016 - if (tnodeSize < sizeof(yaffs_Tnode))
10017 - tnodeSize = sizeof(yaffs_Tnode);
10018 + dev->gc_disable = 1;
10019
10020 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
10021 + if (isCheckpointBlock ||
10022 + !yaffs_still_some_chunks(dev, block)) {
10023 + T(YAFFS_TRACE_TRACING,
10024 + (TSTR
10025 + ("Collecting block %d that has no chunks in use" TENDSTR),
10026 + block));
10027 + yaffs_block_became_dirty(dev, block);
10028 + } else {
10029
10030 - while (ok && (~baseChunk)) {
10031 - nread++;
10032 - /* Read level 0 tnode */
10033 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
10034
10035 + yaffs_verify_blk(dev, bi, block);
10036
10037 - tn = yaffs_GetTnodeRaw(dev);
10038 - if (tn)
10039 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
10040 - else
10041 - ok = 0;
10042 + maxCopies = (wholeBlock) ? dev->param.chunks_per_block : 5;
10043 + oldChunk = block * dev->param.chunks_per_block + dev->gc_chunk;
10044
10045 - if (tn && ok)
10046 - ok = yaffs_AddOrFindLevel0Tnode(dev,
10047 - fileStructPtr,
10048 - baseChunk,
10049 - tn) ? 1 : 0;
10050 + for (/* init already done */;
10051 + retVal == YAFFS_OK &&
10052 + dev->gc_chunk < dev->param.chunks_per_block &&
10053 + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
10054 + maxCopies > 0;
10055 + dev->gc_chunk++, oldChunk++) {
10056 + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
10057
10058 - if (ok)
10059 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
10060 + /* This page is in use and might need to be copied off */
10061
10062 - }
10063 + maxCopies--;
10064
10065 - T(YAFFS_TRACE_CHECKPOINT, (
10066 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
10067 - nread, baseChunk, ok));
10068 + mark_flash = 1;
10069
10070 - return ok ? 1 : 0;
10071 -}
10072 + yaffs_init_tags(&tags);
10073
10074 + yaffs_rd_chunk_tags_nand(dev, oldChunk,
10075 + buffer, &tags);
10076
10077 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
10078 -{
10079 - yaffs_Object *obj;
10080 - yaffs_CheckpointObject cp;
10081 - int i;
10082 - int ok = 1;
10083 - struct ylist_head *lh;
10084 + object =
10085 + yaffs_find_by_number(dev,
10086 + tags.obj_id);
10087
10088 + T(YAFFS_TRACE_GC_DETAIL,
10089 + (TSTR
10090 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
10091 + dev->gc_chunk, tags.obj_id, tags.chunk_id,
10092 + tags.n_bytes));
10093
10094 - /* Iterate through the objects in each hash entry,
10095 - * dumping them to the checkpointing stream.
10096 - */
10097 + if (object && !yaffs_skip_verification(dev)) {
10098 + if (tags.chunk_id == 0)
10099 + matchingChunk = object->hdr_chunk;
10100 + else if (object->soft_del)
10101 + matchingChunk = oldChunk; /* Defeat the test */
10102 + else
10103 + matchingChunk = yaffs_find_chunk_in_file(object, tags.chunk_id, NULL);
10104
10105 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
10106 - ylist_for_each(lh, &dev->objectBucket[i].list) {
10107 - if (lh) {
10108 - obj = ylist_entry(lh, yaffs_Object, hashLink);
10109 - if (!obj->deferedFree) {
10110 - yaffs_ObjectToCheckpointObject(&cp, obj);
10111 - cp.structType = sizeof(cp);
10112 -
10113 - T(YAFFS_TRACE_CHECKPOINT, (
10114 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
10115 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
10116 + if (oldChunk != matchingChunk)
10117 + T(YAFFS_TRACE_ERROR,
10118 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
10119 + oldChunk, matchingChunk, tags.obj_id, tags.chunk_id));
10120
10121 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
10122 + }
10123
10124 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
10125 - ok = yaffs_WriteCheckpointTnodes(obj);
10126 + if (!object) {
10127 + T(YAFFS_TRACE_ERROR,
10128 + (TSTR
10129 + ("page %d in gc has no object: %d %d %d "
10130 + TENDSTR), oldChunk,
10131 + tags.obj_id, tags.chunk_id, tags.n_bytes));
10132 }
10133 - }
10134 - }
10135 - }
10136
10137 - /* Dump end of list */
10138 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
10139 - cp.structType = sizeof(cp);
10140 + if (object &&
10141 + object->deleted &&
10142 + object->soft_del &&
10143 + tags.chunk_id != 0) {
10144 + /* Data chunk in a soft deleted file, throw it away
10145 + * It's a soft deleted data chunk,
10146 + * No need to copy this, just forget about it and
10147 + * fix up the object.
10148 + */
10149 +
10150 + /* Free chunks already includes softdeleted chunks.
10151 + * How ever this chunk is going to soon be really deleted
10152 + * which will increment free chunks.
10153 + * We have to decrement free chunks so this works out properly.
10154 + */
10155 + dev->n_free_chunks--;
10156 + bi->soft_del_pages--;
10157 +
10158 + object->n_data_chunks--;
10159
10160 - if (ok)
10161 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
10162 + if (object->n_data_chunks <= 0) {
10163 + /* remeber to clean up the object */
10164 + dev->gc_cleanup_list[dev->n_clean_ups] =
10165 + tags.obj_id;
10166 + dev->n_clean_ups++;
10167 + }
10168 + mark_flash = 0;
10169 + } else if (0) {
10170 + /* Todo object && object->deleted && object->n_data_chunks == 0 */
10171 + /* Deleted object header with no data chunks.
10172 + * Can be discarded and the file deleted.
10173 + */
10174 + object->hdr_chunk = 0;
10175 + yaffs_free_tnode(object->my_dev,
10176 + object->variant.
10177 + file_variant.top);
10178 + object->variant.file_variant.top = NULL;
10179 + yaffs_generic_obj_del(object);
10180
10181 - return ok ? 1 : 0;
10182 -}
10183 + } else if (object) {
10184 + /* It's either a data chunk in a live file or
10185 + * an ObjectHeader, so we're interested in it.
10186 + * NB Need to keep the ObjectHeaders of deleted files
10187 + * until the whole file has been deleted off
10188 + */
10189 + tags.serial_number++;
10190
10191 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
10192 -{
10193 - yaffs_Object *obj;
10194 - yaffs_CheckpointObject cp;
10195 - int ok = 1;
10196 - int done = 0;
10197 - yaffs_Object *hardList = NULL;
10198 + dev->n_gc_copies++;
10199
10200 - while (ok && !done) {
10201 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
10202 - if (cp.structType != sizeof(cp)) {
10203 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
10204 - cp.structType, sizeof(cp), ok));
10205 - ok = 0;
10206 - }
10207 -
10208 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
10209 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
10210 -
10211 - if (ok && cp.objectId == ~0)
10212 - done = 1;
10213 - else if (ok) {
10214 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
10215 - if (obj) {
10216 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
10217 - if (!ok)
10218 - break;
10219 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
10220 - ok = yaffs_ReadCheckpointTnodes(obj);
10221 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
10222 - obj->hardLinks.next =
10223 - (struct ylist_head *) hardList;
10224 - hardList = obj;
10225 - }
10226 - } else
10227 - ok = 0;
10228 - }
10229 - }
10230 + if (tags.chunk_id == 0) {
10231 + /* It is an object Id,
10232 + * We need to nuke the shrinkheader flags first
10233 + * Also need to clean up shadowing.
10234 + * We no longer want the shrinkHeader flag since its work is done
10235 + * and if it is left in place it will mess up scanning.
10236 + */
10237
10238 - if (ok)
10239 - yaffs_HardlinkFixup(dev, hardList);
10240 + yaffs_obj_header *oh;
10241 + oh = (yaffs_obj_header *)buffer;
10242
10243 - return ok ? 1 : 0;
10244 -}
10245 + oh->is_shrink = 0;
10246 + tags.extra_is_shrink = 0;
10247
10248 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
10249 -{
10250 - __u32 checkpointSum;
10251 - int ok;
10252 + oh->shadows_obj = 0;
10253 + oh->inband_shadowed_obj_id = 0;
10254 + tags.extra_shadows = 0;
10255 +
10256 + /* Update file size */
10257 + if(object->variant_type == YAFFS_OBJECT_TYPE_FILE){
10258 + oh->file_size = object->variant.file_variant.file_size;
10259 + tags.extra_length = oh->file_size;
10260 + }
10261 +
10262 + yaffs_verify_oh(object, oh, &tags, 1);
10263 + newChunk =
10264 + yaffs_write_new_chunk(dev,(__u8 *) oh, &tags, 1);
10265 + } else
10266 + newChunk =
10267 + yaffs_write_new_chunk(dev, buffer, &tags, 1);
10268 +
10269 + if (newChunk < 0) {
10270 + retVal = YAFFS_FAIL;
10271 + } else {
10272
10273 - yaffs_GetCheckpointSum(dev, &checkpointSum);
10274 + /* Ok, now fix up the Tnodes etc. */
10275
10276 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
10277 + if (tags.chunk_id == 0) {
10278 + /* It's a header */
10279 + object->hdr_chunk = newChunk;
10280 + object->serial = tags.serial_number;
10281 + } else {
10282 + /* It's a data chunk */
10283 + int ok;
10284 + ok = yaffs_put_chunk_in_file
10285 + (object,
10286 + tags.chunk_id,
10287 + newChunk, 0);
10288 + }
10289 + }
10290 + }
10291
10292 - if (!ok)
10293 - return 0;
10294 + if (retVal == YAFFS_OK)
10295 + yaffs_chunk_del(dev, oldChunk, mark_flash, __LINE__);
10296
10297 - return 1;
10298 -}
10299 + }
10300 + }
10301
10302 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
10303 -{
10304 - __u32 checkpointSum0;
10305 - __u32 checkpointSum1;
10306 - int ok;
10307 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
10308
10309 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
10310
10311 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
10312
10313 - if (!ok)
10314 - return 0;
10315 + }
10316
10317 - if (checkpointSum0 != checkpointSum1)
10318 - return 0;
10319 + yaffs_verify_collected_blk(dev, bi, block);
10320
10321 - return 1;
10322 -}
10323
10324
10325 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
10326 -{
10327 - int ok = 1;
10328 + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
10329 + /*
10330 + * The gc did not complete. Set block state back to FULL
10331 + * because checkpointing does not restore gc.
10332 + */
10333 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
10334 + } else {
10335 + /* The gc completed. */
10336 + /* Do any required cleanups */
10337 + for (i = 0; i < dev->n_clean_ups; i++) {
10338 + /* Time to delete the file too */
10339 + object =
10340 + yaffs_find_by_number(dev,
10341 + dev->gc_cleanup_list[i]);
10342 + if (object) {
10343 + yaffs_free_tnode(dev,
10344 + object->variant.file_variant.
10345 + top);
10346 + object->variant.file_variant.top = NULL;
10347 + T(YAFFS_TRACE_GC,
10348 + (TSTR
10349 + ("yaffs: About to finally delete object %d"
10350 + TENDSTR), object->obj_id));
10351 + yaffs_generic_obj_del(object);
10352 + object->my_dev->n_deleted_files--;
10353 + }
10354
10355 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
10356 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
10357 - ok = 0;
10358 - }
10359 + }
10360
10361 - if (ok)
10362 - ok = yaffs_CheckpointOpen(dev, 1);
10363
10364 - if (ok) {
10365 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
10366 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
10367 - }
10368 - if (ok) {
10369 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
10370 - ok = yaffs_WriteCheckpointDevice(dev);
10371 - }
10372 - if (ok) {
10373 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
10374 - ok = yaffs_WriteCheckpointObjects(dev);
10375 - }
10376 - if (ok) {
10377 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
10378 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
10379 + chunksAfter = yaffs_get_erased_chunks(dev);
10380 + if (chunksBefore >= chunksAfter) {
10381 + T(YAFFS_TRACE_GC,
10382 + (TSTR
10383 + ("gc did not increase free chunks before %d after %d"
10384 + TENDSTR), chunksBefore, chunksAfter));
10385 + }
10386 + dev->gc_block = 0;
10387 + dev->gc_chunk = 0;
10388 + dev->n_clean_ups = 0;
10389 }
10390
10391 - if (ok)
10392 - ok = yaffs_WriteCheckpointSum(dev);
10393 -
10394 - if (!yaffs_CheckpointClose(dev))
10395 - ok = 0;
10396 -
10397 - if (ok)
10398 - dev->isCheckpointed = 1;
10399 - else
10400 - dev->isCheckpointed = 0;
10401 + dev->gc_disable = 0;
10402
10403 - return dev->isCheckpointed;
10404 + return retVal;
10405 }
10406
10407 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
10408 +/*
10409 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
10410 + * for garbage collection.
10411 + */
10412 +
10413 +static unsigned yaffs_find_gc_block(yaffs_dev_t *dev,
10414 + int aggressive,
10415 + int background)
10416 {
10417 - int ok = 1;
10418 + int i;
10419 + int iterations;
10420 + unsigned selected = 0;
10421 + int prioritised = 0;
10422 + int prioritisedExists = 0;
10423 + yaffs_block_info_t *bi;
10424 + int threshold;
10425
10426 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
10427 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
10428 - ok = 0;
10429 - }
10430 + /* First let's see if we need to grab a prioritised block */
10431 + if (dev->has_pending_prioritised_gc && !aggressive) {
10432 + dev->gc_dirtiest = 0;
10433 + bi = dev->block_info;
10434 + for (i = dev->internal_start_block;
10435 + i <= dev->internal_end_block && !selected;
10436 + i++) {
10437 +
10438 + if (bi->gc_prioritise) {
10439 + prioritisedExists = 1;
10440 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
10441 + yaffs_block_ok_for_gc(dev, bi)) {
10442 + selected = i;
10443 + prioritised = 1;
10444 + }
10445 + }
10446 + bi++;
10447 + }
10448
10449 - if (ok)
10450 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
10451 + /*
10452 + * If there is a prioritised block and none was selected then
10453 + * this happened because there is at least one old dirty block gumming
10454 + * up the works. Let's gc the oldest dirty block.
10455 + */
10456
10457 - if (ok) {
10458 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
10459 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
10460 - }
10461 - if (ok) {
10462 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
10463 - ok = yaffs_ReadCheckpointDevice(dev);
10464 - }
10465 - if (ok) {
10466 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
10467 - ok = yaffs_ReadCheckpointObjects(dev);
10468 - }
10469 - if (ok) {
10470 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
10471 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
10472 - }
10473 + if(prioritisedExists &&
10474 + !selected &&
10475 + dev->oldest_dirty_block > 0)
10476 + selected = dev->oldest_dirty_block;
10477
10478 - if (ok) {
10479 - ok = yaffs_ReadCheckpointSum(dev);
10480 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
10481 + if (!prioritisedExists) /* None found, so we can clear this */
10482 + dev->has_pending_prioritised_gc = 0;
10483 }
10484
10485 - if (!yaffs_CheckpointClose(dev))
10486 - ok = 0;
10487 -
10488 - if (ok)
10489 - dev->isCheckpointed = 1;
10490 - else
10491 - dev->isCheckpointed = 0;
10492 -
10493 - return ok ? 1 : 0;
10494 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
10495 + * search harder.
10496 + * else (we're doing a leasurely gc), then we only bother to do this if the
10497 + * block has only a few pages in use.
10498 + */
10499
10500 -}
10501 + if (!selected){
10502 + int pagesUsed;
10503 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
10504 + if (aggressive){
10505 + threshold = dev->param.chunks_per_block;
10506 + iterations = nBlocks;
10507 + } else {
10508 + int maxThreshold;
10509
10510 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
10511 -{
10512 - if (dev->isCheckpointed ||
10513 - dev->blocksInCheckpoint > 0) {
10514 - dev->isCheckpointed = 0;
10515 - yaffs_CheckpointInvalidateStream(dev);
10516 - if (dev->superBlock && dev->markSuperBlockDirty)
10517 - dev->markSuperBlockDirty(dev->superBlock);
10518 - }
10519 -}
10520 + if(background)
10521 + maxThreshold = dev->param.chunks_per_block/2;
10522 + else
10523 + maxThreshold = dev->param.chunks_per_block/8;
10524
10525 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
10526 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
10527
10528 -int yaffs_CheckpointSave(yaffs_Device *dev)
10529 -{
10530 + threshold = background ?
10531 + (dev->gc_not_done + 2) * 2 : 0;
10532 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10533 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10534 + if(threshold > maxThreshold)
10535 + threshold = maxThreshold;
10536
10537 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10538 + iterations = nBlocks / 16 + 1;
10539 + if (iterations > 100)
10540 + iterations = 100;
10541 + }
10542
10543 - yaffs_VerifyObjects(dev);
10544 - yaffs_VerifyBlocks(dev);
10545 - yaffs_VerifyFreeChunks(dev);
10546 + for (i = 0;
10547 + i < iterations &&
10548 + (dev->gc_dirtiest < 1 ||
10549 + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
10550 + i++) {
10551 + dev->gc_block_finder++;
10552 + if (dev->gc_block_finder < dev->internal_start_block ||
10553 + dev->gc_block_finder > dev->internal_end_block)
10554 + dev->gc_block_finder = dev->internal_start_block;
10555
10556 - if (!dev->isCheckpointed) {
10557 - yaffs_InvalidateCheckpoint(dev);
10558 - yaffs_WriteCheckpointData(dev);
10559 - }
10560 + bi = yaffs_get_block_info(dev, dev->gc_block_finder);
10561
10562 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10563 + pagesUsed = bi->pages_in_use - bi->soft_del_pages;
10564
10565 - return dev->isCheckpointed;
10566 -}
10567 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
10568 + pagesUsed < dev->param.chunks_per_block &&
10569 + (dev->gc_dirtiest < 1 || pagesUsed < dev->gc_pages_in_use) &&
10570 + yaffs_block_ok_for_gc(dev, bi)) {
10571 + dev->gc_dirtiest = dev->gc_block_finder;
10572 + dev->gc_pages_in_use = pagesUsed;
10573 + }
10574 + }
10575
10576 -int yaffs_CheckpointRestore(yaffs_Device *dev)
10577 -{
10578 - int retval;
10579 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10580 + if(dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
10581 + selected = dev->gc_dirtiest;
10582 + }
10583
10584 - retval = yaffs_ReadCheckpointData(dev);
10585 + /*
10586 + * If nothing has been selected for a while, try selecting the oldest dirty
10587 + * because that's gumming up the works.
10588 + */
10589
10590 - if (dev->isCheckpointed) {
10591 - yaffs_VerifyObjects(dev);
10592 - yaffs_VerifyBlocks(dev);
10593 - yaffs_VerifyFreeChunks(dev);
10594 + if(!selected && dev->param.is_yaffs2 &&
10595 + dev->gc_not_done >= ( background ? 10 : 20)){
10596 + yaffs2_find_oldest_dirty_seq(dev);
10597 + if(dev->oldest_dirty_block > 0) {
10598 + selected = dev->oldest_dirty_block;
10599 + dev->gc_dirtiest = selected;
10600 + dev->oldest_dirty_gc_count++;
10601 + bi = yaffs_get_block_info(dev, selected);
10602 + dev->gc_pages_in_use = bi->pages_in_use - bi->soft_del_pages;
10603 + } else
10604 + dev->gc_not_done = 0;
10605 }
10606
10607 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10608 + if(selected){
10609 + T(YAFFS_TRACE_GC,
10610 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10611 + selected,
10612 + dev->param.chunks_per_block - dev->gc_pages_in_use,
10613 + prioritised));
10614 +
10615 + dev->n_gc_blocks++;
10616 + if(background)
10617 + dev->bg_gcs++;
10618 +
10619 + dev->gc_dirtiest = 0;
10620 + dev->gc_pages_in_use = 0;
10621 + dev->gc_not_done = 0;
10622 + if(dev->refresh_skip > 0)
10623 + dev->refresh_skip--;
10624 + } else{
10625 + dev->gc_not_done++;
10626 + T(YAFFS_TRACE_GC,
10627 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10628 + dev->gc_block_finder, dev->gc_not_done,
10629 + threshold,
10630 + dev->gc_dirtiest, dev->gc_pages_in_use,
10631 + dev->oldest_dirty_block,
10632 + background ? " bg" : ""));
10633 + }
10634
10635 - return retval;
10636 + return selected;
10637 }
10638
10639 -/*--------------------- File read/write ------------------------
10640 - * Read and write have very similar structures.
10641 - * In general the read/write has three parts to it
10642 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
10643 - * Some complete chunks
10644 - * An incomplete chunk to end off with
10645 +/* New garbage collector
10646 + * If we're very low on erased blocks then we do aggressive garbage collection
10647 + * otherwise we do "leasurely" garbage collection.
10648 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10649 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10650 *
10651 - * Curve-balls: the first chunk might also be the last chunk.
10652 + * The idea is to help clear out space in a more spread-out manner.
10653 + * Dunno if it really does anything useful.
10654 */
10655 -
10656 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
10657 - int nBytes)
10658 +static int yaffs_check_gc(yaffs_dev_t *dev, int background)
10659 {
10660 + int aggressive = 0;
10661 + int gcOk = YAFFS_OK;
10662 + int maxTries = 0;
10663 + int minErased;
10664 + int erasedChunks;
10665 + int checkpointBlockAdjust;
10666
10667 - int chunk;
10668 - __u32 start;
10669 - int nToCopy;
10670 - int n = nBytes;
10671 - int nDone = 0;
10672 - yaffs_ChunkCache *cache;
10673 -
10674 - yaffs_Device *dev;
10675 -
10676 - dev = in->myDev;
10677 -
10678 - while (n > 0) {
10679 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10680 - /* start = offset % dev->nDataBytesPerChunk; */
10681 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10682 - chunk++;
10683 -
10684 - /* OK now check for the curveball where the start and end are in
10685 - * the same chunk.
10686 - */
10687 - if ((start + n) < dev->nDataBytesPerChunk)
10688 - nToCopy = n;
10689 - else
10690 - nToCopy = dev->nDataBytesPerChunk - start;
10691 -
10692 - cache = yaffs_FindChunkCache(in, chunk);
10693 -
10694 - /* If the chunk is already in the cache or it is less than a whole chunk
10695 - * or we're using inband tags then use the cache (if there is caching)
10696 - * else bypass the cache.
10697 - */
10698 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10699 - if (dev->nShortOpCaches > 0) {
10700 -
10701 - /* If we can't find the data in the cache, then load it up. */
10702 + if(dev->param.gc_control &&
10703 + (dev->param.gc_control(dev) & 1) == 0)
10704 + return YAFFS_OK;
10705
10706 - if (!cache) {
10707 - cache = yaffs_GrabChunkCache(in->myDev);
10708 - cache->object = in;
10709 - cache->chunkId = chunk;
10710 - cache->dirty = 0;
10711 - cache->locked = 0;
10712 - yaffs_ReadChunkDataFromObject(in, chunk,
10713 - cache->
10714 - data);
10715 - cache->nBytes = 0;
10716 - }
10717 + if (dev->gc_disable) {
10718 + /* Bail out so we don't get recursive gc */
10719 + return YAFFS_OK;
10720 + }
10721
10722 - yaffs_UseChunkCache(dev, cache, 0);
10723 + /* This loop should pass the first time.
10724 + * We'll only see looping here if the collection does not increase space.
10725 + */
10726
10727 - cache->locked = 1;
10728 + do {
10729 + maxTries++;
10730
10731 + checkpointBlockAdjust = yaffs_calc_checkpt_blocks_required(dev);
10732
10733 - memcpy(buffer, &cache->data[start], nToCopy);
10734 + minErased = dev->param.n_reserved_blocks + checkpointBlockAdjust + 1;
10735 + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
10736
10737 - cache->locked = 0;
10738 - } else {
10739 - /* Read into the local buffer then copy..*/
10740 + /* If we need a block soon then do aggressive gc.*/
10741 + if (dev->n_erased_blocks < minErased)
10742 + aggressive = 1;
10743 + else {
10744 + if(!background && erasedChunks > (dev->n_free_chunks / 4))
10745 + break;
10746
10747 - __u8 *localBuffer =
10748 - yaffs_GetTempBuffer(dev, __LINE__);
10749 - yaffs_ReadChunkDataFromObject(in, chunk,
10750 - localBuffer);
10751 + if(dev->gc_skip > 20)
10752 + dev->gc_skip = 20;
10753 + if(erasedChunks < dev->n_free_chunks/2 ||
10754 + dev->gc_skip < 1 ||
10755 + background)
10756 + aggressive = 0;
10757 + else {
10758 + dev->gc_skip--;
10759 + break;
10760 + }
10761 + }
10762
10763 - memcpy(buffer, &localBuffer[start], nToCopy);
10764 + dev->gc_skip = 5;
10765
10766 + /* If we don't already have a block being gc'd then see if we should start another */
10767
10768 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10769 - __LINE__);
10770 - }
10771 + if (dev->gc_block < 1 && !aggressive) {
10772 + dev->gc_block = yaffs2_find_refresh_block(dev);
10773 + dev->gc_chunk = 0;
10774 + dev->n_clean_ups=0;
10775 + }
10776 + if (dev->gc_block < 1) {
10777 + dev->gc_block = yaffs_find_gc_block(dev, aggressive, background);
10778 + dev->gc_chunk = 0;
10779 + dev->n_clean_ups=0;
10780 + }
10781
10782 - } else {
10783 + if (dev->gc_block > 0) {
10784 + dev->all_gcs++;
10785 + if (!aggressive)
10786 + dev->passive_gc_count++;
10787
10788 - /* A full chunk. Read directly into the supplied buffer. */
10789 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10790 + T(YAFFS_TRACE_GC,
10791 + (TSTR
10792 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10793 + dev->n_erased_blocks, aggressive));
10794
10795 + gcOk = yaffs_gc_block(dev, dev->gc_block, aggressive);
10796 }
10797
10798 - n -= nToCopy;
10799 - offset += nToCopy;
10800 - buffer += nToCopy;
10801 - nDone += nToCopy;
10802 -
10803 - }
10804 + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && dev->gc_block > 0) {
10805 + T(YAFFS_TRACE_GC,
10806 + (TSTR
10807 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10808 + TENDSTR), dev->n_erased_blocks, maxTries, dev->gc_block));
10809 + }
10810 + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
10811 + (dev->gc_block > 0) &&
10812 + (maxTries < 2));
10813
10814 - return nDone;
10815 + return aggressive ? gcOk : YAFFS_OK;
10816 }
10817
10818 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10819 - int nBytes, int writeThrough)
10820 +/*
10821 + * yaffs_bg_gc()
10822 + * Garbage collects. Intended to be called from a background thread.
10823 + * Returns non-zero if at least half the free chunks are erased.
10824 + */
10825 +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency)
10826 {
10827 + int erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
10828
10829 - int chunk;
10830 - __u32 start;
10831 - int nToCopy;
10832 - int n = nBytes;
10833 - int nDone = 0;
10834 - int nToWriteBack;
10835 - int startOfWrite = offset;
10836 - int chunkWritten = 0;
10837 - __u32 nBytesRead;
10838 - __u32 chunkStart;
10839 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10840
10841 - yaffs_Device *dev;
10842 + yaffs_check_gc(dev, 1);
10843 + return erasedChunks > dev->n_free_chunks/2;
10844 +}
10845
10846 - dev = in->myDev;
10847 +/*------------------------- TAGS --------------------------------*/
10848
10849 - while (n > 0 && chunkWritten >= 0) {
10850 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10851 - /* start = offset % dev->nDataBytesPerChunk; */
10852 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10853 +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
10854 + int chunkInObject)
10855 +{
10856 + return (tags->chunk_id == chunkInObject &&
10857 + tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
10858
10859 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10860 - start >= dev->nDataBytesPerChunk) {
10861 - T(YAFFS_TRACE_ERROR, (
10862 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10863 - TENDSTR),
10864 - (int)offset, chunk, start));
10865 - }
10866 - chunk++;
10867 +}
10868
10869 - /* OK now check for the curveball where the start and end are in
10870 - * the same chunk.
10871 - */
10872
10873 - if ((start + n) < dev->nDataBytesPerChunk) {
10874 - nToCopy = n;
10875 +/*-------------------- Data file manipulation -----------------*/
10876
10877 - /* Now folks, to calculate how many bytes to write back....
10878 - * If we're overwriting and not writing to then end of file then
10879 - * we need to write back as much as was there before.
10880 - */
10881 +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
10882 + yaffs_ext_tags *tags)
10883 +{
10884 + /*Get the Tnode, then get the level 0 offset chunk offset */
10885 + yaffs_tnode_t *tn;
10886 + int theChunk = -1;
10887 + yaffs_ext_tags localTags;
10888 + int retVal = -1;
10889
10890 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10891 + yaffs_dev_t *dev = in->my_dev;
10892
10893 - if (chunkStart > in->variant.fileVariant.fileSize)
10894 - nBytesRead = 0; /* Past end of file */
10895 - else
10896 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10897 + if (!tags) {
10898 + /* Passed a NULL, so use our own tags space */
10899 + tags = &localTags;
10900 + }
10901
10902 - if (nBytesRead > dev->nDataBytesPerChunk)
10903 - nBytesRead = dev->nDataBytesPerChunk;
10904 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
10905
10906 - nToWriteBack =
10907 - (nBytesRead >
10908 - (start + n)) ? nBytesRead : (start + n);
10909 + if (tn) {
10910 + theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
10911
10912 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10913 - YBUG();
10914 + retVal =
10915 + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
10916 + inode_chunk);
10917 + }
10918 + return retVal;
10919 +}
10920
10921 - } else {
10922 - nToCopy = dev->nDataBytesPerChunk - start;
10923 - nToWriteBack = dev->nDataBytesPerChunk;
10924 - }
10925 +static int yaffs_find_del_file_chunk(yaffs_obj_t *in, int inode_chunk,
10926 + yaffs_ext_tags *tags)
10927 +{
10928 + /* Get the Tnode, then get the level 0 offset chunk offset */
10929 + yaffs_tnode_t *tn;
10930 + int theChunk = -1;
10931 + yaffs_ext_tags localTags;
10932
10933 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10934 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10935 - * or we're using inband tags, so we want to use the cache buffers.
10936 - */
10937 - if (dev->nShortOpCaches > 0) {
10938 - yaffs_ChunkCache *cache;
10939 - /* If we can't find the data in the cache, then load the cache */
10940 - cache = yaffs_FindChunkCache(in, chunk);
10941 + yaffs_dev_t *dev = in->my_dev;
10942 + int retVal = -1;
10943
10944 - if (!cache
10945 - && yaffs_CheckSpaceForAllocation(in->
10946 - myDev)) {
10947 - cache = yaffs_GrabChunkCache(in->myDev);
10948 - cache->object = in;
10949 - cache->chunkId = chunk;
10950 - cache->dirty = 0;
10951 - cache->locked = 0;
10952 - yaffs_ReadChunkDataFromObject(in, chunk,
10953 - cache->
10954 - data);
10955 - } else if (cache &&
10956 - !cache->dirty &&
10957 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10958 - /* Drop the cache if it was a read cache item and
10959 - * no space check has been made for it.
10960 - */
10961 - cache = NULL;
10962 - }
10963 + if (!tags) {
10964 + /* Passed a NULL, so use our own tags space */
10965 + tags = &localTags;
10966 + }
10967
10968 - if (cache) {
10969 - yaffs_UseChunkCache(dev, cache, 1);
10970 - cache->locked = 1;
10971 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
10972
10973 + if (tn) {
10974
10975 - memcpy(&cache->data[start], buffer,
10976 - nToCopy);
10977 + theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
10978
10979 + retVal =
10980 + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
10981 + inode_chunk);
10982
10983 - cache->locked = 0;
10984 - cache->nBytes = nToWriteBack;
10985 + /* Delete the entry in the filestructure (if found) */
10986 + if (retVal != -1)
10987 + yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
10988 + }
10989
10990 - if (writeThrough) {
10991 - chunkWritten =
10992 - yaffs_WriteChunkDataToObject
10993 - (cache->object,
10994 - cache->chunkId,
10995 - cache->data, cache->nBytes,
10996 - 1);
10997 - cache->dirty = 0;
10998 - }
10999 + return retVal;
11000 +}
11001
11002 - } else {
11003 - chunkWritten = -1; /* fail the write */
11004 - }
11005 - } else {
11006 - /* An incomplete start or end chunk (or maybe both start and end chunk)
11007 - * Read into the local buffer then copy, then copy over and write back.
11008 - */
11009
11010 - __u8 *localBuffer =
11011 - yaffs_GetTempBuffer(dev, __LINE__);
11012 +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
11013 + int nand_chunk, int in_scan)
11014 +{
11015 + /* NB in_scan is zero unless scanning.
11016 + * For forward scanning, in_scan is > 0;
11017 + * for backward scanning in_scan is < 0
11018 + *
11019 + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
11020 + */
11021
11022 - yaffs_ReadChunkDataFromObject(in, chunk,
11023 - localBuffer);
11024 + yaffs_tnode_t *tn;
11025 + yaffs_dev_t *dev = in->my_dev;
11026 + int existingChunk;
11027 + yaffs_ext_tags existingTags;
11028 + yaffs_ext_tags newTags;
11029 + unsigned existingSerial, newSerial;
11030
11031 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
11032 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
11033 + * If it is not during Scanning then something went wrong!
11034 + */
11035 + if (!in_scan) {
11036 + T(YAFFS_TRACE_ERROR,
11037 + (TSTR
11038 + ("yaffs tragedy:attempt to put data chunk into a non-file"
11039 + TENDSTR)));
11040 + YBUG();
11041 + }
11042
11043 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
11044 + return YAFFS_OK;
11045 + }
11046
11047 - memcpy(&localBuffer[start], buffer, nToCopy);
11048 + tn = yaffs_add_find_tnode_0(dev,
11049 + &in->variant.file_variant,
11050 + inode_chunk,
11051 + NULL);
11052 + if (!tn)
11053 + return YAFFS_FAIL;
11054 +
11055 + if(!nand_chunk)
11056 + /* Dummy insert, bail now */
11057 + return YAFFS_OK;
11058
11059 - chunkWritten =
11060 - yaffs_WriteChunkDataToObject(in, chunk,
11061 - localBuffer,
11062 - nToWriteBack,
11063 - 0);
11064 + existingChunk = yaffs_get_group_base(dev, tn, inode_chunk);
11065
11066 - yaffs_ReleaseTempBuffer(dev, localBuffer,
11067 - __LINE__);
11068 + if (in_scan != 0) {
11069 + /* If we're scanning then we need to test for duplicates
11070 + * NB This does not need to be efficient since it should only ever
11071 + * happen when the power fails during a write, then only one
11072 + * chunk should ever be affected.
11073 + *
11074 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
11075 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
11076 + */
11077 +
11078 + if (existingChunk > 0) {
11079 + /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
11080 + * thus we have to do a FindChunkInFile to get the real chunk id.
11081 + *
11082 + * We have a duplicate now we need to decide which one to use:
11083 + *
11084 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
11085 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
11086 + * YAFFS1: Get both sets of tags and compare serial numbers.
11087 + */
11088 +
11089 + if (in_scan > 0) {
11090 + /* Only do this for forward scanning */
11091 + yaffs_rd_chunk_tags_nand(dev,
11092 + nand_chunk,
11093 + NULL, &newTags);
11094
11095 + /* Do a proper find */
11096 + existingChunk =
11097 + yaffs_find_chunk_in_file(in, inode_chunk,
11098 + &existingTags);
11099 }
11100
11101 - } else {
11102 - /* A full chunk. Write directly from the supplied buffer. */
11103 + if (existingChunk <= 0) {
11104 + /*Hoosterman - how did this happen? */
11105
11106 + T(YAFFS_TRACE_ERROR,
11107 + (TSTR
11108 + ("yaffs tragedy: existing chunk < 0 in scan"
11109 + TENDSTR)));
11110
11111 + }
11112
11113 - chunkWritten =
11114 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
11115 - dev->nDataBytesPerChunk,
11116 - 0);
11117 + /* NB The deleted flags should be false, otherwise the chunks will
11118 + * not be loaded during a scan
11119 + */
11120
11121 - /* Since we've overwritten the cached data, we better invalidate it. */
11122 - yaffs_InvalidateChunkCache(in, chunk);
11123 - }
11124 + if (in_scan > 0) {
11125 + newSerial = newTags.serial_number;
11126 + existingSerial = existingTags.serial_number;
11127 + }
11128
11129 - if (chunkWritten >= 0) {
11130 - n -= nToCopy;
11131 - offset += nToCopy;
11132 - buffer += nToCopy;
11133 - nDone += nToCopy;
11134 + if ((in_scan > 0) &&
11135 + (existingChunk <= 0 ||
11136 + ((existingSerial + 1) & 3) == newSerial)) {
11137 + /* Forward scanning.
11138 + * Use new
11139 + * Delete the old one and drop through to update the tnode
11140 + */
11141 + yaffs_chunk_del(dev, existingChunk, 1,
11142 + __LINE__);
11143 + } else {
11144 + /* Backward scanning or we want to use the existing one
11145 + * Use existing.
11146 + * Delete the new one and return early so that the tnode isn't changed
11147 + */
11148 + yaffs_chunk_del(dev, nand_chunk, 1,
11149 + __LINE__);
11150 + return YAFFS_OK;
11151 + }
11152 }
11153
11154 }
11155
11156 - /* Update file object */
11157 -
11158 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
11159 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
11160 + if (existingChunk == 0)
11161 + in->n_data_chunks++;
11162
11163 - in->dirty = 1;
11164 + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
11165
11166 - return nDone;
11167 + return YAFFS_OK;
11168 }
11169
11170 +static int yaffs_rd_data_obj(yaffs_obj_t *in, int inode_chunk,
11171 + __u8 *buffer)
11172 +{
11173 + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
11174
11175 -/* ---------------------- File resizing stuff ------------------ */
11176 + if (nand_chunk >= 0)
11177 + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
11178 + buffer, NULL);
11179 + else {
11180 + T(YAFFS_TRACE_NANDACCESS,
11181 + (TSTR("Chunk %d not found zero instead" TENDSTR),
11182 + nand_chunk));
11183 + /* get sane (zero) data if you read a hole */
11184 + memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
11185 + return 0;
11186 + }
11187 +
11188 +}
11189
11190 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
11191 +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn)
11192 {
11193 + int block;
11194 + int page;
11195 + yaffs_ext_tags tags;
11196 + yaffs_block_info_t *bi;
11197
11198 - yaffs_Device *dev = in->myDev;
11199 - int oldFileSize = in->variant.fileVariant.fileSize;
11200 + if (chunk_id <= 0)
11201 + return;
11202
11203 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
11204 + dev->n_deletions++;
11205 + block = chunk_id / dev->param.chunks_per_block;
11206 + page = chunk_id % dev->param.chunks_per_block;
11207
11208 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
11209 - dev->nDataBytesPerChunk;
11210 - int i;
11211 - int chunkId;
11212
11213 - /* Delete backwards so that we don't end up with holes if
11214 - * power is lost part-way through the operation.
11215 + if (!yaffs_check_chunk_bit(dev, block, page))
11216 + T(YAFFS_TRACE_VERIFY,
11217 + (TSTR("Deleting invalid chunk %d"TENDSTR),
11218 + chunk_id));
11219 +
11220 + bi = yaffs_get_block_info(dev, block);
11221 +
11222 + yaffs2_update_oldest_dirty_seq(dev, block, bi);
11223 +
11224 + T(YAFFS_TRACE_DELETION,
11225 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunk_id));
11226 +
11227 + if (!dev->param.is_yaffs2 && mark_flash &&
11228 + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
11229 +
11230 + yaffs_init_tags(&tags);
11231 +
11232 + tags.is_deleted = 1;
11233 +
11234 + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
11235 + yaffs_handle_chunk_update(dev, chunk_id, &tags);
11236 + } else {
11237 + dev->n_unmarked_deletions++;
11238 + }
11239 +
11240 + /* Pull out of the management area.
11241 + * If the whole block became dirty, this will kick off an erasure.
11242 */
11243 - for (i = lastDel; i >= startDel; i--) {
11244 - /* NB this could be optimised somewhat,
11245 - * eg. could retrieve the tags and write them without
11246 - * using yaffs_DeleteChunk
11247 - */
11248 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
11249 + bi->block_state == YAFFS_BLOCK_STATE_FULL ||
11250 + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
11251 + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
11252 + dev->n_free_chunks++;
11253
11254 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
11255 - if (chunkId > 0) {
11256 - if (chunkId <
11257 - (dev->internalStartBlock * dev->nChunksPerBlock)
11258 - || chunkId >=
11259 - ((dev->internalEndBlock +
11260 - 1) * dev->nChunksPerBlock)) {
11261 - T(YAFFS_TRACE_ALWAYS,
11262 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
11263 - chunkId, i));
11264 - } else {
11265 - in->nDataChunks--;
11266 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
11267 - }
11268 + yaffs_clear_chunk_bit(dev, block, page);
11269 +
11270 + bi->pages_in_use--;
11271 +
11272 + if (bi->pages_in_use == 0 &&
11273 + !bi->has_shrink_hdr &&
11274 + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
11275 + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
11276 + yaffs_block_became_dirty(dev, block);
11277 }
11278 +
11279 }
11280
11281 }
11282
11283 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
11284 +static int yaffs_wr_data_obj(yaffs_obj_t *in, int inode_chunk,
11285 + const __u8 *buffer, int n_bytes,
11286 + int useReserve)
11287 {
11288 + /* Find old chunk Need to do this to get serial number
11289 + * Write new one and patch into tree.
11290 + * Invalidate old tags.
11291 + */
11292
11293 - int oldFileSize = in->variant.fileVariant.fileSize;
11294 - __u32 newSizeOfPartialChunk;
11295 - int newFullChunks;
11296 + int prevChunkId;
11297 + yaffs_ext_tags prevTags;
11298
11299 - yaffs_Device *dev = in->myDev;
11300 + int newChunkId;
11301 + yaffs_ext_tags newTags;
11302
11303 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
11304 + yaffs_dev_t *dev = in->my_dev;
11305
11306 - yaffs_FlushFilesChunkCache(in);
11307 - yaffs_InvalidateWholeChunkCache(in);
11308 + yaffs_check_gc(dev,0);
11309
11310 - yaffs_CheckGarbageCollection(dev);
11311 + /* Get the previous chunk at this location in the file if it exists.
11312 + * If it does not exist then put a zero into the tree. This creates
11313 + * the tnode now, rather than later when it is harder to clean up.
11314 + */
11315 + prevChunkId = yaffs_find_chunk_in_file(in, inode_chunk, &prevTags);
11316 + if(prevChunkId < 1 &&
11317 + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
11318 + return 0;
11319
11320 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
11321 - return YAFFS_FAIL;
11322 + /* Set up new tags */
11323 + yaffs_init_tags(&newTags);
11324
11325 - if (newSize == oldFileSize)
11326 - return YAFFS_OK;
11327 + newTags.chunk_id = inode_chunk;
11328 + newTags.obj_id = in->obj_id;
11329 + newTags.serial_number =
11330 + (prevChunkId > 0) ? prevTags.serial_number + 1 : 1;
11331 + newTags.n_bytes = n_bytes;
11332
11333 - if (newSize < oldFileSize) {
11334 + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
11335 + T(YAFFS_TRACE_ERROR,
11336 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes));
11337 + YBUG();
11338 + }
11339 +
11340 +
11341 + newChunkId =
11342 + yaffs_write_new_chunk(dev, buffer, &newTags,
11343 + useReserve);
11344
11345 - yaffs_PruneResizedChunks(in, newSize);
11346 + if (newChunkId > 0) {
11347 + yaffs_put_chunk_in_file(in, inode_chunk, newChunkId, 0);
11348
11349 - if (newSizeOfPartialChunk != 0) {
11350 - int lastChunk = 1 + newFullChunks;
11351 + if (prevChunkId > 0)
11352 + yaffs_chunk_del(dev, prevChunkId, 1, __LINE__);
11353
11354 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
11355 + yaffs_verify_file_sane(in);
11356 + }
11357 + return newChunkId;
11358
11359 - /* Got to read and rewrite the last chunk with its new size and zero pad */
11360 - yaffs_ReadChunkDataFromObject(in, lastChunk,
11361 - localBuffer);
11362 +}
11363
11364 - memset(localBuffer + newSizeOfPartialChunk, 0,
11365 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
11366 +/* UpdateObjectHeader updates the header on NAND for an object.
11367 + * If name is not NULL, then that new name is used.
11368 + */
11369 +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name, int force,
11370 + int is_shrink, int shadows, yaffs_xattr_mod *xmod)
11371 +{
11372
11373 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
11374 - newSizeOfPartialChunk, 1);
11375 + yaffs_block_info_t *bi;
11376
11377 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
11378 - }
11379 + yaffs_dev_t *dev = in->my_dev;
11380
11381 - in->variant.fileVariant.fileSize = newSize;
11382 + int prevChunkId;
11383 + int retVal = 0;
11384 + int result = 0;
11385
11386 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
11387 - } else {
11388 - /* newsSize > oldFileSize */
11389 - in->variant.fileVariant.fileSize = newSize;
11390 - }
11391 + int newChunkId;
11392 + yaffs_ext_tags newTags;
11393 + yaffs_ext_tags oldTags;
11394 + const YCHAR *alias = NULL;
11395
11396 + __u8 *buffer = NULL;
11397 + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
11398
11399 - /* Write a new object header.
11400 - * show we've shrunk the file, if need be
11401 - * Do this only if the file is not in the deleted directories.
11402 - */
11403 - if (in->parent &&
11404 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
11405 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
11406 - yaffs_UpdateObjectHeader(in, NULL, 0,
11407 - (newSize < oldFileSize) ? 1 : 0, 0);
11408 + yaffs_obj_header *oh = NULL;
11409
11410 - return YAFFS_OK;
11411 -}
11412 + yaffs_strcpy(old_name, _Y("silly old name"));
11413
11414 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
11415 -{
11416 - obj = yaffs_GetEquivalentObject(obj);
11417
11418 - switch (obj->variantType) {
11419 - case YAFFS_OBJECT_TYPE_FILE:
11420 - return obj->variant.fileVariant.fileSize;
11421 - case YAFFS_OBJECT_TYPE_SYMLINK:
11422 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
11423 - default:
11424 - return 0;
11425 - }
11426 -}
11427 + if (!in->fake ||
11428 + in == dev->root_dir || /* The root_dir should also be saved */
11429 + force || xmod) {
11430
11431 + yaffs_check_gc(dev,0);
11432 + yaffs_check_obj_details_loaded(in);
11433
11434 + buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__);
11435 + oh = (yaffs_obj_header *) buffer;
11436 +
11437 + prevChunkId = in->hdr_chunk;
11438 +
11439 + if (prevChunkId > 0) {
11440 + result = yaffs_rd_chunk_tags_nand(dev, prevChunkId,
11441 + buffer, &oldTags);
11442 +
11443 + yaffs_verify_oh(in, oh, &oldTags, 0);
11444 +
11445 + memcpy(old_name, oh->name, sizeof(oh->name));
11446 + memset(buffer, 0xFF, sizeof(yaffs_obj_header));
11447 + } else
11448 + memset(buffer, 0xFF, dev->data_bytes_per_chunk);
11449 +
11450 + oh->type = in->variant_type;
11451 + oh->yst_mode = in->yst_mode;
11452 + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
11453
11454 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
11455 -{
11456 - int retVal;
11457 - if (in->dirty) {
11458 - yaffs_FlushFilesChunkCache(in);
11459 - if (updateTime) {
11460 #ifdef CONFIG_YAFFS_WINCE
11461 - yfsd_WinFileTimeNow(in->win_mtime);
11462 + oh->win_atime[0] = in->win_atime[0];
11463 + oh->win_ctime[0] = in->win_ctime[0];
11464 + oh->win_mtime[0] = in->win_mtime[0];
11465 + oh->win_atime[1] = in->win_atime[1];
11466 + oh->win_ctime[1] = in->win_ctime[1];
11467 + oh->win_mtime[1] = in->win_mtime[1];
11468 #else
11469 + oh->yst_uid = in->yst_uid;
11470 + oh->yst_gid = in->yst_gid;
11471 + oh->yst_atime = in->yst_atime;
11472 + oh->yst_mtime = in->yst_mtime;
11473 + oh->yst_ctime = in->yst_ctime;
11474 + oh->yst_rdev = in->yst_rdev;
11475 +#endif
11476 + if (in->parent)
11477 + oh->parent_obj_id = in->parent->obj_id;
11478 + else
11479 + oh->parent_obj_id = 0;
11480 +
11481 + if (name && *name) {
11482 + memset(oh->name, 0, sizeof(oh->name));
11483 + yaffs_load_oh_from_name(dev,oh->name,name);
11484 + } else if (prevChunkId > 0)
11485 + memcpy(oh->name, old_name, sizeof(oh->name));
11486 + else
11487 + memset(oh->name, 0, sizeof(oh->name));
11488
11489 - in->yst_mtime = Y_CURRENT_TIME;
11490 + oh->is_shrink = is_shrink;
11491
11492 -#endif
11493 + switch (in->variant_type) {
11494 + case YAFFS_OBJECT_TYPE_UNKNOWN:
11495 + /* Should not happen */
11496 + break;
11497 + case YAFFS_OBJECT_TYPE_FILE:
11498 + oh->file_size =
11499 + (oh->parent_obj_id == YAFFS_OBJECTID_DELETED
11500 + || oh->parent_obj_id ==
11501 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
11502 + file_variant.file_size;
11503 + break;
11504 + case YAFFS_OBJECT_TYPE_HARDLINK:
11505 + oh->equiv_id =
11506 + in->variant.hardlink_variant.equiv_id;
11507 + break;
11508 + case YAFFS_OBJECT_TYPE_SPECIAL:
11509 + /* Do nothing */
11510 + break;
11511 + case YAFFS_OBJECT_TYPE_DIRECTORY:
11512 + /* Do nothing */
11513 + break;
11514 + case YAFFS_OBJECT_TYPE_SYMLINK:
11515 + alias = in->variant.symlink_variant.alias;
11516 + if(!alias)
11517 + alias = _Y("no alias");
11518 + yaffs_strncpy(oh->alias,
11519 + alias,
11520 + YAFFS_MAX_ALIAS_LENGTH);
11521 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11522 + break;
11523 }
11524
11525 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
11526 - 0) ? YAFFS_OK : YAFFS_FAIL;
11527 - } else {
11528 - retVal = YAFFS_OK;
11529 - }
11530 + /* process any xattrib modifications */
11531 + if(xmod)
11532 + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
11533
11534 - return retVal;
11535
11536 -}
11537 + /* Tags */
11538 + yaffs_init_tags(&newTags);
11539 + in->serial++;
11540 + newTags.chunk_id = 0;
11541 + newTags.obj_id = in->obj_id;
11542 + newTags.serial_number = in->serial;
11543
11544 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
11545 -{
11546 + /* Add extra info for file header */
11547
11548 - /* First off, invalidate the file's data in the cache, without flushing. */
11549 - yaffs_InvalidateWholeChunkCache(in);
11550 + newTags.extra_available = 1;
11551 + newTags.extra_parent_id = oh->parent_obj_id;
11552 + newTags.extra_length = oh->file_size;
11553 + newTags.extra_is_shrink = oh->is_shrink;
11554 + newTags.extra_equiv_id = oh->equiv_id;
11555 + newTags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
11556 + newTags.extra_obj_type = in->variant_type;
11557
11558 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
11559 - /* Move to the unlinked directory so we have a record that it was deleted. */
11560 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
11561 + yaffs_verify_oh(in, oh, &newTags, 1);
11562
11563 - }
11564 + /* Create new chunk in NAND */
11565 + newChunkId =
11566 + yaffs_write_new_chunk(dev, buffer, &newTags,
11567 + (prevChunkId > 0) ? 1 : 0);
11568
11569 - yaffs_RemoveObjectFromDirectory(in);
11570 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
11571 - in->hdrChunk = 0;
11572 + if (newChunkId >= 0) {
11573
11574 - yaffs_FreeObject(in);
11575 - return YAFFS_OK;
11576 + in->hdr_chunk = newChunkId;
11577
11578 -}
11579 + if (prevChunkId > 0) {
11580 + yaffs_chunk_del(dev, prevChunkId, 1,
11581 + __LINE__);
11582 + }
11583
11584 -/* yaffs_DeleteFile deletes the whole file data
11585 - * and the inode associated with the file.
11586 - * It does not delete the links associated with the file.
11587 - */
11588 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
11589 -{
11590 + if (!yaffs_obj_cache_dirty(in))
11591 + in->dirty = 0;
11592
11593 - int retVal;
11594 - int immediateDeletion = 0;
11595 + /* If this was a shrink, then mark the block that the chunk lives on */
11596 + if (is_shrink) {
11597 + bi = yaffs_get_block_info(in->my_dev,
11598 + newChunkId / in->my_dev->param.chunks_per_block);
11599 + bi->has_shrink_hdr = 1;
11600 + }
11601
11602 -#ifdef __KERNEL__
11603 - if (!in->myInode)
11604 - immediateDeletion = 1;
11605 -#else
11606 - if (in->inUse <= 0)
11607 - immediateDeletion = 1;
11608 -#endif
11609 + }
11610 +
11611 + retVal = newChunkId;
11612
11613 - if (immediateDeletion) {
11614 - retVal =
11615 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
11616 - _Y("deleted"), 0, 0);
11617 - T(YAFFS_TRACE_TRACING,
11618 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
11619 - in->objectId));
11620 - in->deleted = 1;
11621 - in->myDev->nDeletedFiles++;
11622 - if (1 || in->myDev->isYaffs2)
11623 - yaffs_ResizeFile(in, 0);
11624 - yaffs_SoftDeleteFile(in);
11625 - } else {
11626 - retVal =
11627 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
11628 - _Y("unlinked"), 0, 0);
11629 }
11630
11631 + if (buffer)
11632 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
11633
11634 return retVal;
11635 }
11636
11637 -int yaffs_DeleteFile(yaffs_Object *in)
11638 -{
11639 - int retVal = YAFFS_OK;
11640 - int deleted = in->deleted;
11641 -
11642 - yaffs_ResizeFile(in, 0);
11643 -
11644 - if (in->nDataChunks > 0) {
11645 - /* Use soft deletion if there is data in the file.
11646 - * That won't be the case if it has been resized to zero.
11647 - */
11648 - if (!in->unlinked)
11649 - retVal = yaffs_UnlinkFileIfNeeded(in);
11650 -
11651 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11652 - in->deleted = 1;
11653 - deleted = 1;
11654 - in->myDev->nDeletedFiles++;
11655 - yaffs_SoftDeleteFile(in);
11656 - }
11657 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11658 - } else {
11659 - /* The file has no data chunks so we toss it immediately */
11660 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11661 - in->variant.fileVariant.top = NULL;
11662 - yaffs_DoGenericObjectDeletion(in);
11663 -
11664 - return YAFFS_OK;
11665 - }
11666 -}
11667 +/*------------------------ Short Operations Cache ----------------------------------------
11668 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11669 + * reads might be short sequential reads, and a lot of writes may be short
11670 + * sequential writes. eg. scanning/writing a jpeg file.
11671 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11672 + * with dumb-as-a-rock code.
11673 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11674 + * buffering.
11675 + *
11676 + * There are a limited number (~10) of cache chunks per device so that we don't
11677 + * need a very intelligent search.
11678 + */
11679
11680 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11681 +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj)
11682 {
11683 - /* First check that the directory is empty. */
11684 - if (ylist_empty(&in->variant.directoryVariant.children))
11685 - return yaffs_DoGenericObjectDeletion(in);
11686 + yaffs_dev_t *dev = obj->my_dev;
11687 + int i;
11688 + yaffs_cache_t *cache;
11689 + int nCaches = obj->my_dev->param.n_caches;
11690
11691 - return YAFFS_FAIL;
11692 + for (i = 0; i < nCaches; i++) {
11693 + cache = &dev->cache[i];
11694 + if (cache->object == obj &&
11695 + cache->dirty)
11696 + return 1;
11697 + }
11698
11699 + return 0;
11700 }
11701
11702 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11703 -{
11704 - YFREE(in->variant.symLinkVariant.alias);
11705 -
11706 - return yaffs_DoGenericObjectDeletion(in);
11707 -}
11708
11709 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11710 +static void yaffs_flush_file_cache(yaffs_obj_t *obj)
11711 {
11712 - /* remove this hardlink from the list assocaited with the equivalent
11713 - * object
11714 - */
11715 - ylist_del_init(&in->hardLinks);
11716 - return yaffs_DoGenericObjectDeletion(in);
11717 -}
11718 + yaffs_dev_t *dev = obj->my_dev;
11719 + int lowest = -99; /* Stop compiler whining. */
11720 + int i;
11721 + yaffs_cache_t *cache;
11722 + int chunkWritten = 0;
11723 + int nCaches = obj->my_dev->param.n_caches;
11724
11725 -int yaffs_DeleteObject(yaffs_Object *obj)
11726 -{
11727 -int retVal = -1;
11728 - switch (obj->variantType) {
11729 - case YAFFS_OBJECT_TYPE_FILE:
11730 - retVal = yaffs_DeleteFile(obj);
11731 - break;
11732 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11733 - return yaffs_DeleteDirectory(obj);
11734 - break;
11735 - case YAFFS_OBJECT_TYPE_SYMLINK:
11736 - retVal = yaffs_DeleteSymLink(obj);
11737 - break;
11738 - case YAFFS_OBJECT_TYPE_HARDLINK:
11739 - retVal = yaffs_DeleteHardLink(obj);
11740 - break;
11741 - case YAFFS_OBJECT_TYPE_SPECIAL:
11742 - retVal = yaffs_DoGenericObjectDeletion(obj);
11743 - break;
11744 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11745 - retVal = 0;
11746 - break; /* should not happen. */
11747 - }
11748 + if (nCaches > 0) {
11749 + do {
11750 + cache = NULL;
11751
11752 - return retVal;
11753 -}
11754 + /* Find the dirty cache for this object with the lowest chunk id. */
11755 + for (i = 0; i < nCaches; i++) {
11756 + if (dev->cache[i].object == obj &&
11757 + dev->cache[i].dirty) {
11758 + if (!cache
11759 + || dev->cache[i].chunk_id <
11760 + lowest) {
11761 + cache = &dev->cache[i];
11762 + lowest = cache->chunk_id;
11763 + }
11764 + }
11765 + }
11766
11767 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11768 -{
11769 + if (cache && !cache->locked) {
11770 + /* Write it out and free it up */
11771
11772 - int immediateDeletion = 0;
11773 + chunkWritten =
11774 + yaffs_wr_data_obj(cache->object,
11775 + cache->chunk_id,
11776 + cache->data,
11777 + cache->n_bytes,
11778 + 1);
11779 + cache->dirty = 0;
11780 + cache->object = NULL;
11781 + }
11782
11783 -#ifdef __KERNEL__
11784 - if (!obj->myInode)
11785 - immediateDeletion = 1;
11786 -#else
11787 - if (obj->inUse <= 0)
11788 - immediateDeletion = 1;
11789 -#endif
11790 + } while (cache && chunkWritten > 0);
11791
11792 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11793 - return yaffs_DeleteHardLink(obj);
11794 - } else if (!ylist_empty(&obj->hardLinks)) {
11795 - /* Curve ball: We're unlinking an object that has a hardlink.
11796 - *
11797 - * This problem arises because we are not strictly following
11798 - * The Linux link/inode model.
11799 - *
11800 - * We can't really delete the object.
11801 - * Instead, we do the following:
11802 - * - Select a hardlink.
11803 - * - Unhook it from the hard links
11804 - * - Unhook it from its parent directory (so that the rename can work)
11805 - * - Rename the object to the hardlink's name.
11806 - * - Delete the hardlink
11807 - */
11808 + if (cache) {
11809 + /* Hoosterman, disk full while writing cache out. */
11810 + T(YAFFS_TRACE_ERROR,
11811 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11812
11813 - yaffs_Object *hl;
11814 - int retVal;
11815 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11816 + }
11817 + }
11818
11819 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11820 +}
11821
11822 - ylist_del_init(&hl->hardLinks);
11823 - ylist_del_init(&hl->siblings);
11824 +/*yaffs_flush_whole_cache(dev)
11825 + *
11826 + *
11827 + */
11828
11829 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11830 +void yaffs_flush_whole_cache(yaffs_dev_t *dev)
11831 +{
11832 + yaffs_obj_t *obj;
11833 + int nCaches = dev->param.n_caches;
11834 + int i;
11835
11836 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11837 + /* Find a dirty object in the cache and flush it...
11838 + * until there are no further dirty objects.
11839 + */
11840 + do {
11841 + obj = NULL;
11842 + for (i = 0; i < nCaches && !obj; i++) {
11843 + if (dev->cache[i].object &&
11844 + dev->cache[i].dirty)
11845 + obj = dev->cache[i].object;
11846
11847 - if (retVal == YAFFS_OK)
11848 - retVal = yaffs_DoGenericObjectDeletion(hl);
11849 + }
11850 + if (obj)
11851 + yaffs_flush_file_cache(obj);
11852
11853 - return retVal;
11854 + } while (obj);
11855
11856 - } else if (immediateDeletion) {
11857 - switch (obj->variantType) {
11858 - case YAFFS_OBJECT_TYPE_FILE:
11859 - return yaffs_DeleteFile(obj);
11860 - break;
11861 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11862 - return yaffs_DeleteDirectory(obj);
11863 - break;
11864 - case YAFFS_OBJECT_TYPE_SYMLINK:
11865 - return yaffs_DeleteSymLink(obj);
11866 - break;
11867 - case YAFFS_OBJECT_TYPE_SPECIAL:
11868 - return yaffs_DoGenericObjectDeletion(obj);
11869 - break;
11870 - case YAFFS_OBJECT_TYPE_HARDLINK:
11871 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11872 - default:
11873 - return YAFFS_FAIL;
11874 - }
11875 - } else
11876 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11877 - _Y("unlinked"), 0, 0);
11878 }
11879
11880
11881 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11882 +/* Grab us a cache chunk for use.
11883 + * First look for an empty one.
11884 + * Then look for the least recently used non-dirty one.
11885 + * Then look for the least recently used dirty one...., flush and look again.
11886 + */
11887 +static yaffs_cache_t *yaffs_grab_chunk_worker(yaffs_dev_t *dev)
11888 {
11889 + int i;
11890
11891 - if (obj && obj->unlinkAllowed)
11892 - return yaffs_UnlinkWorker(obj);
11893 -
11894 - return YAFFS_FAIL;
11895 -
11896 -}
11897 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11898 -{
11899 - yaffs_Object *obj;
11900 + if (dev->param.n_caches > 0) {
11901 + for (i = 0; i < dev->param.n_caches; i++) {
11902 + if (!dev->cache[i].object)
11903 + return &dev->cache[i];
11904 + }
11905 + }
11906
11907 - obj = yaffs_FindObjectByName(dir, name);
11908 - return yaffs_UnlinkObject(obj);
11909 + return NULL;
11910 }
11911
11912 -/*----------------------- Initialisation Scanning ---------------------- */
11913 -
11914 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11915 - int backwardScanning)
11916 +static yaffs_cache_t *yaffs_grab_chunk_cache(yaffs_dev_t *dev)
11917 {
11918 - yaffs_Object *obj;
11919 + yaffs_cache_t *cache;
11920 + yaffs_obj_t *theObj;
11921 + int usage;
11922 + int i;
11923 + int pushout;
11924
11925 - if (!backwardScanning) {
11926 - /* Handle YAFFS1 forward scanning case
11927 - * For YAFFS1 we always do the deletion
11928 - */
11929 + if (dev->param.n_caches > 0) {
11930 + /* Try find a non-dirty one... */
11931
11932 - } else {
11933 - /* Handle YAFFS2 case (backward scanning)
11934 - * If the shadowed object exists then ignore.
11935 - */
11936 - if (yaffs_FindObjectByNumber(dev, objId))
11937 - return;
11938 - }
11939 + cache = yaffs_grab_chunk_worker(dev);
11940
11941 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11942 - * We put it in unlinked dir to be cleaned up after the scanning
11943 - */
11944 - obj =
11945 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11946 - YAFFS_OBJECT_TYPE_FILE);
11947 - if (!obj)
11948 - return;
11949 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11950 - obj->variant.fileVariant.shrinkSize = 0;
11951 - obj->valid = 1; /* So that we don't read any other info for this file */
11952 + if (!cache) {
11953 + /* They were all dirty, find the last recently used object and flush
11954 + * its cache, then find again.
11955 + * NB what's here is not very accurate, we actually flush the object
11956 + * the last recently used page.
11957 + */
11958
11959 -}
11960 + /* With locking we can't assume we can use entry zero */
11961
11962 -typedef struct {
11963 - int seq;
11964 - int block;
11965 -} yaffs_BlockIndex;
11966 + theObj = NULL;
11967 + usage = -1;
11968 + cache = NULL;
11969 + pushout = -1;
11970
11971 + for (i = 0; i < dev->param.n_caches; i++) {
11972 + if (dev->cache[i].object &&
11973 + !dev->cache[i].locked &&
11974 + (dev->cache[i].last_use < usage || !cache)) {
11975 + usage = dev->cache[i].last_use;
11976 + theObj = dev->cache[i].object;
11977 + cache = &dev->cache[i];
11978 + pushout = i;
11979 + }
11980 + }
11981
11982 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
11983 -{
11984 - yaffs_Object *hl;
11985 - yaffs_Object *in;
11986 + if (!cache || cache->dirty) {
11987 + /* Flush and try again */
11988 + yaffs_flush_file_cache(theObj);
11989 + cache = yaffs_grab_chunk_worker(dev);
11990 + }
11991
11992 - while (hardList) {
11993 - hl = hardList;
11994 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
11995 + }
11996 + return cache;
11997 + } else
11998 + return NULL;
11999
12000 - in = yaffs_FindObjectByNumber(dev,
12001 - hl->variant.hardLinkVariant.
12002 - equivalentObjectId);
12003 +}
12004
12005 - if (in) {
12006 - /* Add the hardlink pointers */
12007 - hl->variant.hardLinkVariant.equivalentObject = in;
12008 - ylist_add(&hl->hardLinks, &in->hardLinks);
12009 - } else {
12010 - /* Todo Need to report/handle this better.
12011 - * Got a problem... hardlink to a non-existant object
12012 - */
12013 - hl->variant.hardLinkVariant.equivalentObject = NULL;
12014 - YINIT_LIST_HEAD(&hl->hardLinks);
12015 +/* Find a cached chunk */
12016 +static yaffs_cache_t *yaffs_find_chunk_cache(const yaffs_obj_t *obj,
12017 + int chunk_id)
12018 +{
12019 + yaffs_dev_t *dev = obj->my_dev;
12020 + int i;
12021 + if (dev->param.n_caches > 0) {
12022 + for (i = 0; i < dev->param.n_caches; i++) {
12023 + if (dev->cache[i].object == obj &&
12024 + dev->cache[i].chunk_id == chunk_id) {
12025 + dev->cache_hits++;
12026
12027 + return &dev->cache[i];
12028 + }
12029 }
12030 }
12031 + return NULL;
12032 }
12033
12034 +/* Mark the chunk for the least recently used algorithym */
12035 +static void yaffs_use_cache(yaffs_dev_t *dev, yaffs_cache_t *cache,
12036 + int isAWrite)
12037 +{
12038 +
12039 + if (dev->param.n_caches > 0) {
12040 + if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) {
12041 + /* Reset the cache usages */
12042 + int i;
12043 + for (i = 1; i < dev->param.n_caches; i++)
12044 + dev->cache[i].last_use = 0;
12045
12046 + dev->cache_last_use = 0;
12047 + }
12048
12049 + dev->cache_last_use++;
12050
12051 + cache->last_use = dev->cache_last_use;
12052
12053 -static int ybicmp(const void *a, const void *b)
12054 -{
12055 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
12056 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
12057 - register int ablock = ((yaffs_BlockIndex *)a)->block;
12058 - register int bblock = ((yaffs_BlockIndex *)b)->block;
12059 - if (aseq == bseq)
12060 - return ablock - bblock;
12061 - else
12062 - return aseq - bseq;
12063 + if (isAWrite)
12064 + cache->dirty = 1;
12065 + }
12066 }
12067
12068 +/* Invalidate a single cache page.
12069 + * Do this when a whole page gets written,
12070 + * ie the short cache for this page is no longer valid.
12071 + */
12072 +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id)
12073 +{
12074 + if (object->my_dev->param.n_caches > 0) {
12075 + yaffs_cache_t *cache = yaffs_find_chunk_cache(object, chunk_id);
12076
12077 -struct yaffs_ShadowFixerStruct {
12078 - int objectId;
12079 - int shadowedId;
12080 - struct yaffs_ShadowFixerStruct *next;
12081 -};
12082 -
12083 + if (cache)
12084 + cache->object = NULL;
12085 + }
12086 +}
12087
12088 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
12089 +/* Invalidate all the cache pages associated with this object
12090 + * Do this whenever ther file is deleted or resized.
12091 + */
12092 +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in)
12093 {
12094 - /*
12095 - * Sort out state of unlinked and deleted objects after scanning.
12096 - */
12097 - struct ylist_head *i;
12098 - struct ylist_head *n;
12099 - yaffs_Object *l;
12100 + int i;
12101 + yaffs_dev_t *dev = in->my_dev;
12102
12103 - /* Soft delete all the unlinked files */
12104 - ylist_for_each_safe(i, n,
12105 - &dev->unlinkedDir->variant.directoryVariant.children) {
12106 - if (i) {
12107 - l = ylist_entry(i, yaffs_Object, siblings);
12108 - yaffs_DeleteObject(l);
12109 + if (dev->param.n_caches > 0) {
12110 + /* Invalidate it. */
12111 + for (i = 0; i < dev->param.n_caches; i++) {
12112 + if (dev->cache[i].object == in)
12113 + dev->cache[i].object = NULL;
12114 }
12115 }
12116 +}
12117
12118 - ylist_for_each_safe(i, n,
12119 - &dev->deletedDir->variant.directoryVariant.children) {
12120 - if (i) {
12121 - l = ylist_entry(i, yaffs_Object, siblings);
12122 - yaffs_DeleteObject(l);
12123 - }
12124 - }
12125
12126 -}
12127 +/*--------------------- File read/write ------------------------
12128 + * Read and write have very similar structures.
12129 + * In general the read/write has three parts to it
12130 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
12131 + * Some complete chunks
12132 + * An incomplete chunk to end off with
12133 + *
12134 + * Curve-balls: the first chunk might also be the last chunk.
12135 + */
12136
12137 -static int yaffs_Scan(yaffs_Device *dev)
12138 +int yaffs_file_rd(yaffs_obj_t *in, __u8 *buffer, loff_t offset,
12139 + int n_bytes)
12140 {
12141 - yaffs_ExtendedTags tags;
12142 - int blk;
12143 - int blockIterator;
12144 - int startIterator;
12145 - int endIterator;
12146 - int result;
12147
12148 int chunk;
12149 - int c;
12150 - int deleted;
12151 - yaffs_BlockState state;
12152 - yaffs_Object *hardList = NULL;
12153 - yaffs_BlockInfo *bi;
12154 - __u32 sequenceNumber;
12155 - yaffs_ObjectHeader *oh;
12156 - yaffs_Object *in;
12157 - yaffs_Object *parent;
12158 + __u32 start;
12159 + int nToCopy;
12160 + int n = n_bytes;
12161 + int nDone = 0;
12162 + yaffs_cache_t *cache;
12163
12164 - int alloc_failed = 0;
12165 + yaffs_dev_t *dev;
12166
12167 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
12168 + dev = in->my_dev;
12169
12170 + while (n > 0) {
12171 + /* chunk = offset / dev->data_bytes_per_chunk + 1; */
12172 + /* start = offset % dev->data_bytes_per_chunk; */
12173 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
12174 + chunk++;
12175
12176 - __u8 *chunkData;
12177 + /* OK now check for the curveball where the start and end are in
12178 + * the same chunk.
12179 + */
12180 + if ((start + n) < dev->data_bytes_per_chunk)
12181 + nToCopy = n;
12182 + else
12183 + nToCopy = dev->data_bytes_per_chunk - start;
12184
12185 + cache = yaffs_find_chunk_cache(in, chunk);
12186
12187 + /* If the chunk is already in the cache or it is less than a whole chunk
12188 + * or we're using inband tags then use the cache (if there is caching)
12189 + * else bypass the cache.
12190 + */
12191 + if (cache || nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
12192 + if (dev->param.n_caches > 0) {
12193
12194 - T(YAFFS_TRACE_SCAN,
12195 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
12196 - dev->internalStartBlock, dev->internalEndBlock));
12197 + /* If we can't find the data in the cache, then load it up. */
12198
12199 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12200 + if (!cache) {
12201 + cache = yaffs_grab_chunk_cache(in->my_dev);
12202 + cache->object = in;
12203 + cache->chunk_id = chunk;
12204 + cache->dirty = 0;
12205 + cache->locked = 0;
12206 + yaffs_rd_data_obj(in, chunk,
12207 + cache->
12208 + data);
12209 + cache->n_bytes = 0;
12210 + }
12211
12212 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12213 + yaffs_use_cache(dev, cache, 0);
12214
12215 - /* Scan all the blocks to determine their state */
12216 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12217 - bi = yaffs_GetBlockInfo(dev, blk);
12218 - yaffs_ClearChunkBits(dev, blk);
12219 - bi->pagesInUse = 0;
12220 - bi->softDeletions = 0;
12221 + cache->locked = 1;
12222
12223 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12224
12225 - bi->blockState = state;
12226 - bi->sequenceNumber = sequenceNumber;
12227 + memcpy(buffer, &cache->data[start], nToCopy);
12228
12229 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12230 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12231 + cache->locked = 0;
12232 + } else {
12233 + /* Read into the local buffer then copy..*/
12234
12235 - T(YAFFS_TRACE_SCAN_DEBUG,
12236 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12237 - state, sequenceNumber));
12238 + __u8 *localBuffer =
12239 + yaffs_get_temp_buffer(dev, __LINE__);
12240 + yaffs_rd_data_obj(in, chunk,
12241 + localBuffer);
12242
12243 - if (state == YAFFS_BLOCK_STATE_DEAD) {
12244 - T(YAFFS_TRACE_BAD_BLOCKS,
12245 - (TSTR("block %d is bad" TENDSTR), blk));
12246 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12247 - T(YAFFS_TRACE_SCAN_DEBUG,
12248 - (TSTR("Block empty " TENDSTR)));
12249 - dev->nErasedBlocks++;
12250 - dev->nFreeChunks += dev->nChunksPerBlock;
12251 - }
12252 - }
12253 + memcpy(buffer, &localBuffer[start], nToCopy);
12254
12255 - startIterator = dev->internalStartBlock;
12256 - endIterator = dev->internalEndBlock;
12257
12258 - /* For each block.... */
12259 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
12260 - blockIterator++) {
12261 + yaffs_release_temp_buffer(dev, localBuffer,
12262 + __LINE__);
12263 + }
12264
12265 - YYIELD();
12266 + } else {
12267
12268 - YYIELD();
12269 + /* A full chunk. Read directly into the supplied buffer. */
12270 + yaffs_rd_data_obj(in, chunk, buffer);
12271
12272 - blk = blockIterator;
12273 + }
12274
12275 - bi = yaffs_GetBlockInfo(dev, blk);
12276 - state = bi->blockState;
12277 + n -= nToCopy;
12278 + offset += nToCopy;
12279 + buffer += nToCopy;
12280 + nDone += nToCopy;
12281
12282 - deleted = 0;
12283 + }
12284
12285 - /* For each chunk in each block that needs scanning....*/
12286 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
12287 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
12288 - /* Read the tags and decide what to do */
12289 - chunk = blk * dev->nChunksPerBlock + c;
12290 + return nDone;
12291 +}
12292
12293 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12294 - &tags);
12295 +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
12296 + int n_bytes, int write_trhrough)
12297 +{
12298
12299 - /* Let's have a good look at this chunk... */
12300 + int chunk;
12301 + __u32 start;
12302 + int nToCopy;
12303 + int n = n_bytes;
12304 + int nDone = 0;
12305 + int nToWriteBack;
12306 + int startOfWrite = offset;
12307 + int chunkWritten = 0;
12308 + __u32 n_bytesRead;
12309 + __u32 chunkStart;
12310
12311 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
12312 - /* YAFFS1 only...
12313 - * A deleted chunk
12314 - */
12315 - deleted++;
12316 - dev->nFreeChunks++;
12317 - /*T((" %d %d deleted\n",blk,c)); */
12318 - } else if (!tags.chunkUsed) {
12319 - /* An unassigned chunk in the block
12320 - * This means that either the block is empty or
12321 - * this is the one being allocated from
12322 - */
12323 + yaffs_dev_t *dev;
12324
12325 - if (c == 0) {
12326 - /* We're looking at the first chunk in the block so the block is unused */
12327 - state = YAFFS_BLOCK_STATE_EMPTY;
12328 - dev->nErasedBlocks++;
12329 - } else {
12330 - /* this is the block being allocated from */
12331 - T(YAFFS_TRACE_SCAN,
12332 - (TSTR
12333 - (" Allocating from %d %d" TENDSTR),
12334 - blk, c));
12335 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12336 - dev->allocationBlock = blk;
12337 - dev->allocationPage = c;
12338 - dev->allocationBlockFinder = blk;
12339 - /* Set it to here to encourage the allocator to go forth from here. */
12340 + dev = in->my_dev;
12341
12342 - }
12343 + while (n > 0 && chunkWritten >= 0) {
12344 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
12345
12346 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
12347 - } else if (tags.chunkId > 0) {
12348 - /* chunkId > 0 so it is a data chunk... */
12349 - unsigned int endpos;
12350 -
12351 - yaffs_SetChunkBit(dev, blk, c);
12352 - bi->pagesInUse++;
12353 -
12354 - in = yaffs_FindOrCreateObjectByNumber(dev,
12355 - tags.
12356 - objectId,
12357 - YAFFS_OBJECT_TYPE_FILE);
12358 - /* PutChunkIntoFile checks for a clash (two data chunks with
12359 - * the same chunkId).
12360 - */
12361 + if (chunk * dev->data_bytes_per_chunk + start != offset ||
12362 + start >= dev->data_bytes_per_chunk) {
12363 + T(YAFFS_TRACE_ERROR, (
12364 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
12365 + TENDSTR),
12366 + (int)offset, chunk, start));
12367 + }
12368 + chunk++; /* File pos to chunk in file offset */
12369
12370 - if (!in)
12371 - alloc_failed = 1;
12372 + /* OK now check for the curveball where the start and end are in
12373 + * the same chunk.
12374 + */
12375
12376 - if (in) {
12377 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
12378 - alloc_failed = 1;
12379 - }
12380 + if ((start + n) < dev->data_bytes_per_chunk) {
12381 + nToCopy = n;
12382
12383 - endpos =
12384 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
12385 - tags.byteCount;
12386 - if (in &&
12387 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12388 - && in->variant.fileVariant.scannedFileSize <
12389 - endpos) {
12390 - in->variant.fileVariant.
12391 - scannedFileSize = endpos;
12392 - if (!dev->useHeaderFileSize) {
12393 - in->variant.fileVariant.
12394 - fileSize =
12395 - in->variant.fileVariant.
12396 - scannedFileSize;
12397 - }
12398 + /* Now folks, to calculate how many bytes to write back....
12399 + * If we're overwriting and not writing to then end of file then
12400 + * we need to write back as much as was there before.
12401 + */
12402
12403 - }
12404 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
12405 - } else {
12406 - /* chunkId == 0, so it is an ObjectHeader.
12407 - * Thus, we read in the object header and make the object
12408 - */
12409 - yaffs_SetChunkBit(dev, blk, c);
12410 - bi->pagesInUse++;
12411 + chunkStart = ((chunk - 1) * dev->data_bytes_per_chunk);
12412
12413 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
12414 - chunkData,
12415 - NULL);
12416 -
12417 - oh = (yaffs_ObjectHeader *) chunkData;
12418 -
12419 - in = yaffs_FindObjectByNumber(dev,
12420 - tags.objectId);
12421 - if (in && in->variantType != oh->type) {
12422 - /* This should not happen, but somehow
12423 - * Wev'e ended up with an objectId that has been reused but not yet
12424 - * deleted, and worse still it has changed type. Delete the old object.
12425 - */
12426 + if (chunkStart > in->variant.file_variant.file_size)
12427 + n_bytesRead = 0; /* Past end of file */
12428 + else
12429 + n_bytesRead = in->variant.file_variant.file_size - chunkStart;
12430
12431 - yaffs_DeleteObject(in);
12432 + if (n_bytesRead > dev->data_bytes_per_chunk)
12433 + n_bytesRead = dev->data_bytes_per_chunk;
12434
12435 - in = 0;
12436 - }
12437 + nToWriteBack =
12438 + (n_bytesRead >
12439 + (start + n)) ? n_bytesRead : (start + n);
12440
12441 - in = yaffs_FindOrCreateObjectByNumber(dev,
12442 - tags.
12443 - objectId,
12444 - oh->type);
12445 -
12446 - if (!in)
12447 - alloc_failed = 1;
12448 -
12449 - if (in && oh->shadowsObject > 0) {
12450 -
12451 - struct yaffs_ShadowFixerStruct *fixer;
12452 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
12453 - if (fixer) {
12454 - fixer->next = shadowFixerList;
12455 - shadowFixerList = fixer;
12456 - fixer->objectId = tags.objectId;
12457 - fixer->shadowedId = oh->shadowsObject;
12458 - }
12459 + if (nToWriteBack < 0 || nToWriteBack > dev->data_bytes_per_chunk)
12460 + YBUG();
12461 +
12462 + } else {
12463 + nToCopy = dev->data_bytes_per_chunk - start;
12464 + nToWriteBack = dev->data_bytes_per_chunk;
12465 + }
12466 +
12467 + if (nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
12468 + /* An incomplete start or end chunk (or maybe both start and end chunk),
12469 + * or we're using inband tags, so we want to use the cache buffers.
12470 + */
12471 + if (dev->param.n_caches > 0) {
12472 + yaffs_cache_t *cache;
12473 + /* If we can't find the data in the cache, then load the cache */
12474 + cache = yaffs_find_chunk_cache(in, chunk);
12475
12476 + if (!cache
12477 + && yaffs_check_alloc_available(dev, 1)) {
12478 + cache = yaffs_grab_chunk_cache(dev);
12479 + cache->object = in;
12480 + cache->chunk_id = chunk;
12481 + cache->dirty = 0;
12482 + cache->locked = 0;
12483 + yaffs_rd_data_obj(in, chunk,
12484 + cache->data);
12485 + } else if (cache &&
12486 + !cache->dirty &&
12487 + !yaffs_check_alloc_available(dev, 1)) {
12488 + /* Drop the cache if it was a read cache item and
12489 + * no space check has been made for it.
12490 + */
12491 + cache = NULL;
12492 }
12493
12494 - if (in && in->valid) {
12495 - /* We have already filled this one. We have a duplicate and need to resolve it. */
12496 + if (cache) {
12497 + yaffs_use_cache(dev, cache, 1);
12498 + cache->locked = 1;
12499
12500 - unsigned existingSerial = in->serial;
12501 - unsigned newSerial = tags.serialNumber;
12502
12503 - if (((existingSerial + 1) & 3) == newSerial) {
12504 - /* Use new one - destroy the exisiting one */
12505 - yaffs_DeleteChunk(dev,
12506 - in->hdrChunk,
12507 - 1, __LINE__);
12508 - in->valid = 0;
12509 - } else {
12510 - /* Use existing - destroy this one. */
12511 - yaffs_DeleteChunk(dev, chunk, 1,
12512 - __LINE__);
12513 + memcpy(&cache->data[start], buffer,
12514 + nToCopy);
12515 +
12516 +
12517 + cache->locked = 0;
12518 + cache->n_bytes = nToWriteBack;
12519 +
12520 + if (write_trhrough) {
12521 + chunkWritten =
12522 + yaffs_wr_data_obj
12523 + (cache->object,
12524 + cache->chunk_id,
12525 + cache->data, cache->n_bytes,
12526 + 1);
12527 + cache->dirty = 0;
12528 }
12529 +
12530 + } else {
12531 + chunkWritten = -1; /* fail the write */
12532 }
12533 + } else {
12534 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12535 + * Read into the local buffer then copy, then copy over and write back.
12536 + */
12537
12538 - if (in && !in->valid &&
12539 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12540 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
12541 - /* We only load some info, don't fiddle with directory structure */
12542 - in->valid = 1;
12543 - in->variantType = oh->type;
12544 + __u8 *localBuffer =
12545 + yaffs_get_temp_buffer(dev, __LINE__);
12546
12547 - in->yst_mode = oh->yst_mode;
12548 -#ifdef CONFIG_YAFFS_WINCE
12549 - in->win_atime[0] = oh->win_atime[0];
12550 - in->win_ctime[0] = oh->win_ctime[0];
12551 - in->win_mtime[0] = oh->win_mtime[0];
12552 - in->win_atime[1] = oh->win_atime[1];
12553 - in->win_ctime[1] = oh->win_ctime[1];
12554 - in->win_mtime[1] = oh->win_mtime[1];
12555 -#else
12556 - in->yst_uid = oh->yst_uid;
12557 - in->yst_gid = oh->yst_gid;
12558 - in->yst_atime = oh->yst_atime;
12559 - in->yst_mtime = oh->yst_mtime;
12560 - in->yst_ctime = oh->yst_ctime;
12561 - in->yst_rdev = oh->yst_rdev;
12562 -#endif
12563 - in->hdrChunk = chunk;
12564 - in->serial = tags.serialNumber;
12565 + yaffs_rd_data_obj(in, chunk,
12566 + localBuffer);
12567
12568 - } else if (in && !in->valid) {
12569 - /* we need to load this info */
12570
12571 - in->valid = 1;
12572 - in->variantType = oh->type;
12573
12574 - in->yst_mode = oh->yst_mode;
12575 -#ifdef CONFIG_YAFFS_WINCE
12576 - in->win_atime[0] = oh->win_atime[0];
12577 - in->win_ctime[0] = oh->win_ctime[0];
12578 - in->win_mtime[0] = oh->win_mtime[0];
12579 - in->win_atime[1] = oh->win_atime[1];
12580 - in->win_ctime[1] = oh->win_ctime[1];
12581 - in->win_mtime[1] = oh->win_mtime[1];
12582 -#else
12583 - in->yst_uid = oh->yst_uid;
12584 - in->yst_gid = oh->yst_gid;
12585 - in->yst_atime = oh->yst_atime;
12586 - in->yst_mtime = oh->yst_mtime;
12587 - in->yst_ctime = oh->yst_ctime;
12588 - in->yst_rdev = oh->yst_rdev;
12589 -#endif
12590 - in->hdrChunk = chunk;
12591 - in->serial = tags.serialNumber;
12592 + memcpy(&localBuffer[start], buffer, nToCopy);
12593
12594 - yaffs_SetObjectName(in, oh->name);
12595 - in->dirty = 0;
12596 + chunkWritten =
12597 + yaffs_wr_data_obj(in, chunk,
12598 + localBuffer,
12599 + nToWriteBack,
12600 + 0);
12601
12602 - /* directory stuff...
12603 - * hook up to parent
12604 - */
12605 + yaffs_release_temp_buffer(dev, localBuffer,
12606 + __LINE__);
12607
12608 - parent =
12609 - yaffs_FindOrCreateObjectByNumber
12610 - (dev, oh->parentObjectId,
12611 - YAFFS_OBJECT_TYPE_DIRECTORY);
12612 - if (!parent)
12613 - alloc_failed = 1;
12614 - if (parent && parent->variantType ==
12615 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12616 - /* Set up as a directory */
12617 - parent->variantType =
12618 - YAFFS_OBJECT_TYPE_DIRECTORY;
12619 - YINIT_LIST_HEAD(&parent->variant.
12620 - directoryVariant.
12621 - children);
12622 - } else if (!parent || parent->variantType !=
12623 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12624 - /* Hoosterman, another problem....
12625 - * We're trying to use a non-directory as a directory
12626 - */
12627 + }
12628
12629 - T(YAFFS_TRACE_ERROR,
12630 - (TSTR
12631 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12632 - TENDSTR)));
12633 - parent = dev->lostNFoundDir;
12634 - }
12635 + } else {
12636 + /* A full chunk. Write directly from the supplied buffer. */
12637
12638 - yaffs_AddObjectToDirectory(parent, in);
12639
12640 - if (0 && (parent == dev->deletedDir ||
12641 - parent == dev->unlinkedDir)) {
12642 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12643 - dev->nDeletedFiles++;
12644 - }
12645 - /* Note re hardlinks.
12646 - * Since we might scan a hardlink before its equivalent object is scanned
12647 - * we put them all in a list.
12648 - * After scanning is complete, we should have all the objects, so we run through this
12649 - * list and fix up all the chains.
12650 - */
12651
12652 - switch (in->variantType) {
12653 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12654 - /* Todo got a problem */
12655 - break;
12656 - case YAFFS_OBJECT_TYPE_FILE:
12657 - if (dev->useHeaderFileSize)
12658 -
12659 - in->variant.fileVariant.
12660 - fileSize =
12661 - oh->fileSize;
12662 -
12663 - break;
12664 - case YAFFS_OBJECT_TYPE_HARDLINK:
12665 - in->variant.hardLinkVariant.
12666 - equivalentObjectId =
12667 - oh->equivalentObjectId;
12668 - in->hardLinks.next =
12669 - (struct ylist_head *)
12670 - hardList;
12671 - hardList = in;
12672 - break;
12673 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12674 - /* Do nothing */
12675 - break;
12676 - case YAFFS_OBJECT_TYPE_SPECIAL:
12677 - /* Do nothing */
12678 - break;
12679 - case YAFFS_OBJECT_TYPE_SYMLINK:
12680 - in->variant.symLinkVariant.alias =
12681 - yaffs_CloneString(oh->alias);
12682 - if (!in->variant.symLinkVariant.alias)
12683 - alloc_failed = 1;
12684 - break;
12685 - }
12686 + chunkWritten =
12687 + yaffs_wr_data_obj(in, chunk, buffer,
12688 + dev->data_bytes_per_chunk,
12689 + 0);
12690
12691 -/*
12692 - if (parent == dev->deletedDir) {
12693 - yaffs_DestroyObject(in);
12694 - bi->hasShrinkHeader = 1;
12695 - }
12696 -*/
12697 - }
12698 - }
12699 + /* Since we've overwritten the cached data, we better invalidate it. */
12700 + yaffs_invalidate_chunk_cache(in, chunk);
12701 }
12702
12703 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12704 - /* If we got this far while scanning, then the block is fully allocated.*/
12705 - state = YAFFS_BLOCK_STATE_FULL;
12706 + if (chunkWritten >= 0) {
12707 + n -= nToCopy;
12708 + offset += nToCopy;
12709 + buffer += nToCopy;
12710 + nDone += nToCopy;
12711 }
12712
12713 - bi->blockState = state;
12714 + }
12715
12716 - /* Now let's see if it was dirty */
12717 - if (bi->pagesInUse == 0 &&
12718 - !bi->hasShrinkHeader &&
12719 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12720 - yaffs_BlockBecameDirty(dev, blk);
12721 - }
12722 + /* Update file object */
12723
12724 - }
12725 + if ((startOfWrite + nDone) > in->variant.file_variant.file_size)
12726 + in->variant.file_variant.file_size = (startOfWrite + nDone);
12727
12728 + in->dirty = 1;
12729
12730 - /* Ok, we've done all the scanning.
12731 - * Fix up the hard link chains.
12732 - * We should now have scanned all the objects, now it's time to add these
12733 - * hardlinks.
12734 - */
12735 + return nDone;
12736 +}
12737
12738 - yaffs_HardlinkFixup(dev, hardList);
12739 +int yaffs_wr_file(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
12740 + int n_bytes, int write_trhrough)
12741 +{
12742 + yaffs2_handle_hole(in,offset);
12743 + return yaffs_do_file_wr(in,buffer,offset,n_bytes,write_trhrough);
12744 +}
12745
12746 - /* Fix up any shadowed objects */
12747 - {
12748 - struct yaffs_ShadowFixerStruct *fixer;
12749 - yaffs_Object *obj;
12750 -
12751 - while (shadowFixerList) {
12752 - fixer = shadowFixerList;
12753 - shadowFixerList = fixer->next;
12754 - /* Complete the rename transaction by deleting the shadowed object
12755 - * then setting the object header to unshadowed.
12756 - */
12757 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12758 - if (obj)
12759 - yaffs_DeleteObject(obj);
12760
12761 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12762
12763 - if (obj)
12764 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12765 +/* ---------------------- File resizing stuff ------------------ */
12766
12767 - YFREE(fixer);
12768 - }
12769 - }
12770 +static void yaffs_prune_chunks(yaffs_obj_t *in, int new_size)
12771 +{
12772
12773 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12774 + yaffs_dev_t *dev = in->my_dev;
12775 + int oldFileSize = in->variant.file_variant.file_size;
12776
12777 - if (alloc_failed)
12778 - return YAFFS_FAIL;
12779 + int lastDel = 1 + (oldFileSize - 1) / dev->data_bytes_per_chunk;
12780 +
12781 + int startDel = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
12782 + dev->data_bytes_per_chunk;
12783 + int i;
12784 + int chunk_id;
12785
12786 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12787 + /* Delete backwards so that we don't end up with holes if
12788 + * power is lost part-way through the operation.
12789 + */
12790 + for (i = lastDel; i >= startDel; i--) {
12791 + /* NB this could be optimised somewhat,
12792 + * eg. could retrieve the tags and write them without
12793 + * using yaffs_chunk_del
12794 + */
12795
12796 + chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
12797 + if (chunk_id > 0) {
12798 + if (chunk_id <
12799 + (dev->internal_start_block * dev->param.chunks_per_block)
12800 + || chunk_id >=
12801 + ((dev->internal_end_block +
12802 + 1) * dev->param.chunks_per_block)) {
12803 + T(YAFFS_TRACE_ALWAYS,
12804 + (TSTR("Found daft chunk_id %d for %d" TENDSTR),
12805 + chunk_id, i));
12806 + } else {
12807 + in->n_data_chunks--;
12808 + yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
12809 + }
12810 + }
12811 + }
12812
12813 - return YAFFS_OK;
12814 }
12815
12816 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12817 -{
12818 - __u8 *chunkData;
12819 - yaffs_ObjectHeader *oh;
12820 - yaffs_Device *dev;
12821 - yaffs_ExtendedTags tags;
12822 - int result;
12823 - int alloc_failed = 0;
12824
12825 - if (!in)
12826 - return;
12827 +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size)
12828 +{
12829 + int newFullChunks;
12830 + __u32 new_sizeOfPartialChunk;
12831 + yaffs_dev_t *dev = obj->my_dev;
12832
12833 - dev = in->myDev;
12834 + yaffs_addr_to_chunk(dev, new_size, &newFullChunks, &new_sizeOfPartialChunk);
12835
12836 -#if 0
12837 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12838 - in->objectId,
12839 - in->lazyLoaded ? "not yet" : "already"));
12840 -#endif
12841 + yaffs_prune_chunks(obj, new_size);
12842
12843 - if (in->lazyLoaded && in->hdrChunk > 0) {
12844 - in->lazyLoaded = 0;
12845 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12846 + if (new_sizeOfPartialChunk != 0) {
12847 + int lastChunk = 1 + newFullChunks;
12848 + __u8 *localBuffer = yaffs_get_temp_buffer(dev, __LINE__);
12849
12850 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12851 - oh = (yaffs_ObjectHeader *) chunkData;
12852 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12853 + yaffs_rd_data_obj(obj, lastChunk, localBuffer);
12854 + memset(localBuffer + new_sizeOfPartialChunk, 0,
12855 + dev->data_bytes_per_chunk - new_sizeOfPartialChunk);
12856
12857 - in->yst_mode = oh->yst_mode;
12858 -#ifdef CONFIG_YAFFS_WINCE
12859 - in->win_atime[0] = oh->win_atime[0];
12860 - in->win_ctime[0] = oh->win_ctime[0];
12861 - in->win_mtime[0] = oh->win_mtime[0];
12862 - in->win_atime[1] = oh->win_atime[1];
12863 - in->win_ctime[1] = oh->win_ctime[1];
12864 - in->win_mtime[1] = oh->win_mtime[1];
12865 -#else
12866 - in->yst_uid = oh->yst_uid;
12867 - in->yst_gid = oh->yst_gid;
12868 - in->yst_atime = oh->yst_atime;
12869 - in->yst_mtime = oh->yst_mtime;
12870 - in->yst_ctime = oh->yst_ctime;
12871 - in->yst_rdev = oh->yst_rdev;
12872 + yaffs_wr_data_obj(obj, lastChunk, localBuffer,
12873 + new_sizeOfPartialChunk, 1);
12874
12875 -#endif
12876 - yaffs_SetObjectName(in, oh->name);
12877 + yaffs_release_temp_buffer(dev, localBuffer, __LINE__);
12878 + }
12879
12880 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12881 - in->variant.symLinkVariant.alias =
12882 - yaffs_CloneString(oh->alias);
12883 - if (!in->variant.symLinkVariant.alias)
12884 - alloc_failed = 1; /* Not returned to caller */
12885 - }
12886 + obj->variant.file_variant.file_size = new_size;
12887
12888 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12889 - }
12890 + yaffs_prune_tree(dev, &obj->variant.file_variant);
12891 }
12892
12893 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12894 -{
12895 - yaffs_ExtendedTags tags;
12896 - int blk;
12897 - int blockIterator;
12898 - int startIterator;
12899 - int endIterator;
12900 - int nBlocksToScan = 0;
12901 -
12902 - int chunk;
12903 - int result;
12904 - int c;
12905 - int deleted;
12906 - yaffs_BlockState state;
12907 - yaffs_Object *hardList = NULL;
12908 - yaffs_BlockInfo *bi;
12909 - __u32 sequenceNumber;
12910 - yaffs_ObjectHeader *oh;
12911 - yaffs_Object *in;
12912 - yaffs_Object *parent;
12913 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12914 - int itsUnlinked;
12915 - __u8 *chunkData;
12916
12917 - int fileSize;
12918 - int isShrink;
12919 - int foundChunksInBlock;
12920 - int equivalentObjectId;
12921 - int alloc_failed = 0;
12922 +int yaffs_resize_file(yaffs_obj_t *in, loff_t new_size)
12923 +{
12924 + yaffs_dev_t *dev = in->my_dev;
12925 + int oldFileSize = in->variant.file_variant.file_size;
12926
12927 + yaffs_flush_file_cache(in);
12928 + yaffs_invalidate_whole_cache(in);
12929
12930 - yaffs_BlockIndex *blockIndex = NULL;
12931 - int altBlockIndex = 0;
12932 + yaffs_check_gc(dev,0);
12933
12934 - if (!dev->isYaffs2) {
12935 - T(YAFFS_TRACE_SCAN,
12936 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12937 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
12938 return YAFFS_FAIL;
12939 - }
12940
12941 - T(YAFFS_TRACE_SCAN,
12942 - (TSTR
12943 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12944 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12945 + if (new_size == oldFileSize)
12946 + return YAFFS_OK;
12947 +
12948 + if(new_size > oldFileSize){
12949 + yaffs2_handle_hole(in,new_size);
12950 + in->variant.file_variant.file_size = new_size;
12951 + } else {
12952 + /* new_size < oldFileSize */
12953 + yaffs_resize_file_down(in, new_size);
12954 + }
12955
12956 + /* Write a new object header to reflect the resize.
12957 + * show we've shrunk the file, if need be
12958 + * Do this only if the file is not in the deleted directories
12959 + * and is not shadowed.
12960 + */
12961 + if (in->parent &&
12962 + !in->is_shadowed &&
12963 + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
12964 + in->parent->obj_id != YAFFS_OBJECTID_DELETED)
12965 + yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
12966
12967 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12968
12969 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12970 + return YAFFS_OK;
12971 +}
12972
12973 - if (!blockIndex) {
12974 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12975 - altBlockIndex = 1;
12976 - }
12977 +loff_t yaffs_get_file_size(yaffs_obj_t *obj)
12978 +{
12979 + YCHAR *alias = NULL;
12980 + obj = yaffs_get_equivalent_obj(obj);
12981
12982 - if (!blockIndex) {
12983 - T(YAFFS_TRACE_SCAN,
12984 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
12985 - return YAFFS_FAIL;
12986 + switch (obj->variant_type) {
12987 + case YAFFS_OBJECT_TYPE_FILE:
12988 + return obj->variant.file_variant.file_size;
12989 + case YAFFS_OBJECT_TYPE_SYMLINK:
12990 + alias = obj->variant.symlink_variant.alias;
12991 + if(!alias)
12992 + return 0;
12993 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
12994 + default:
12995 + return 0;
12996 }
12997 +}
12998
12999 - dev->blocksInCheckpoint = 0;
13000 -
13001 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13002 -
13003 - /* Scan all the blocks to determine their state */
13004 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
13005 - bi = yaffs_GetBlockInfo(dev, blk);
13006 - yaffs_ClearChunkBits(dev, blk);
13007 - bi->pagesInUse = 0;
13008 - bi->softDeletions = 0;
13009 -
13010 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
13011
13012 - bi->blockState = state;
13013 - bi->sequenceNumber = sequenceNumber;
13014
13015 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
13016 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
13017 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
13018 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
13019 +int yaffs_flush_file(yaffs_obj_t *in, int update_time, int data_sync)
13020 +{
13021 + int retVal;
13022 + if (in->dirty) {
13023 + yaffs_flush_file_cache(in);
13024 + if(data_sync) /* Only sync data */
13025 + retVal=YAFFS_OK;
13026 + else {
13027 + if (update_time) {
13028 +#ifdef CONFIG_YAFFS_WINCE
13029 + yfsd_win_file_time_now(in->win_mtime);
13030 +#else
13031
13032 - T(YAFFS_TRACE_SCAN_DEBUG,
13033 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
13034 - state, sequenceNumber));
13035 + in->yst_mtime = Y_CURRENT_TIME;
13036
13037 +#endif
13038 + }
13039
13040 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
13041 - dev->blocksInCheckpoint++;
13042 + retVal = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >=
13043 + 0) ? YAFFS_OK : YAFFS_FAIL;
13044 + }
13045 + } else {
13046 + retVal = YAFFS_OK;
13047 + }
13048
13049 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
13050 - T(YAFFS_TRACE_BAD_BLOCKS,
13051 - (TSTR("block %d is bad" TENDSTR), blk));
13052 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
13053 - T(YAFFS_TRACE_SCAN_DEBUG,
13054 - (TSTR("Block empty " TENDSTR)));
13055 - dev->nErasedBlocks++;
13056 - dev->nFreeChunks += dev->nChunksPerBlock;
13057 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13058 + return retVal;
13059
13060 - /* Determine the highest sequence number */
13061 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
13062 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
13063 +}
13064
13065 - blockIndex[nBlocksToScan].seq = sequenceNumber;
13066 - blockIndex[nBlocksToScan].block = blk;
13067 +static int yaffs_generic_obj_del(yaffs_obj_t *in)
13068 +{
13069
13070 - nBlocksToScan++;
13071 + /* First off, invalidate the file's data in the cache, without flushing. */
13072 + yaffs_invalidate_whole_cache(in);
13073
13074 - if (sequenceNumber >= dev->sequenceNumber)
13075 - dev->sequenceNumber = sequenceNumber;
13076 - } else {
13077 - /* TODO: Nasty sequence number! */
13078 - T(YAFFS_TRACE_SCAN,
13079 - (TSTR
13080 - ("Block scanning block %d has bad sequence number %d"
13081 - TENDSTR), blk, sequenceNumber));
13082 + if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) {
13083 + /* Move to the unlinked directory so we have a record that it was deleted. */
13084 + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, 0);
13085
13086 - }
13087 - }
13088 }
13089
13090 - T(YAFFS_TRACE_SCAN,
13091 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
13092 + yaffs_remove_obj_from_dir(in);
13093 + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
13094 + in->hdr_chunk = 0;
13095
13096 + yaffs_free_obj(in);
13097 + return YAFFS_OK;
13098
13099 +}
13100
13101 - YYIELD();
13102 +/* yaffs_del_file deletes the whole file data
13103 + * and the inode associated with the file.
13104 + * It does not delete the links associated with the file.
13105 + */
13106 +static int yaffs_unlink_file_if_needed(yaffs_obj_t *in)
13107 +{
13108
13109 - /* Sort the blocks */
13110 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
13111 - {
13112 - /* Use qsort now. */
13113 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
13114 - }
13115 -#else
13116 - {
13117 - /* Dungy old bubble sort... */
13118 + int retVal;
13119 + int immediateDeletion = 0;
13120 + yaffs_dev_t *dev = in->my_dev;
13121
13122 - yaffs_BlockIndex temp;
13123 - int i;
13124 - int j;
13125 + if (!in->my_inode)
13126 + immediateDeletion = 1;
13127
13128 - for (i = 0; i < nBlocksToScan; i++)
13129 - for (j = i + 1; j < nBlocksToScan; j++)
13130 - if (blockIndex[i].seq > blockIndex[j].seq) {
13131 - temp = blockIndex[j];
13132 - blockIndex[j] = blockIndex[i];
13133 - blockIndex[i] = temp;
13134 - }
13135 + if (immediateDeletion) {
13136 + retVal =
13137 + yaffs_change_obj_name(in, in->my_dev->del_dir,
13138 + _Y("deleted"), 0, 0);
13139 + T(YAFFS_TRACE_TRACING,
13140 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
13141 + in->obj_id));
13142 + in->deleted = 1;
13143 + in->my_dev->n_deleted_files++;
13144 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
13145 + yaffs_resize_file(in, 0);
13146 + yaffs_soft_del_file(in);
13147 + } else {
13148 + retVal =
13149 + yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
13150 + _Y("unlinked"), 0, 0);
13151 }
13152 -#endif
13153
13154 - YYIELD();
13155
13156 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
13157 + return retVal;
13158 +}
13159
13160 - /* Now scan the blocks looking at the data. */
13161 - startIterator = 0;
13162 - endIterator = nBlocksToScan - 1;
13163 - T(YAFFS_TRACE_SCAN_DEBUG,
13164 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
13165 +int yaffs_del_file(yaffs_obj_t *in)
13166 +{
13167 + int retVal = YAFFS_OK;
13168 + int deleted; /* Need to cache value on stack if in is freed */
13169 + yaffs_dev_t *dev = in->my_dev;
13170
13171 - /* For each block.... backwards */
13172 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
13173 - blockIterator--) {
13174 - /* Cooperative multitasking! This loop can run for so
13175 - long that watchdog timers expire. */
13176 - YYIELD();
13177 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
13178 + yaffs_resize_file(in, 0);
13179
13180 - /* get the block to scan in the correct order */
13181 - blk = blockIndex[blockIterator].block;
13182 + if (in->n_data_chunks > 0) {
13183 + /* Use soft deletion if there is data in the file.
13184 + * That won't be the case if it has been resized to zero.
13185 + */
13186 + if (!in->unlinked)
13187 + retVal = yaffs_unlink_file_if_needed(in);
13188
13189 - bi = yaffs_GetBlockInfo(dev, blk);
13190 + deleted = in->deleted;
13191
13192 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
13193 + in->deleted = 1;
13194 + deleted = 1;
13195 + in->my_dev->n_deleted_files++;
13196 + yaffs_soft_del_file(in);
13197 + }
13198 + return deleted ? YAFFS_OK : YAFFS_FAIL;
13199 + } else {
13200 + /* The file has no data chunks so we toss it immediately */
13201 + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
13202 + in->variant.file_variant.top = NULL;
13203 + yaffs_generic_obj_del(in);
13204
13205 - state = bi->blockState;
13206 + return YAFFS_OK;
13207 + }
13208 +}
13209
13210 - deleted = 0;
13211 +static int yaffs_is_non_empty_dir(yaffs_obj_t *obj)
13212 +{
13213 + return (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
13214 + !(ylist_empty(&obj->variant.dir_variant.children));
13215 +}
13216
13217 - /* For each chunk in each block that needs scanning.... */
13218 - foundChunksInBlock = 0;
13219 - for (c = dev->nChunksPerBlock - 1;
13220 - !alloc_failed && c >= 0 &&
13221 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
13222 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
13223 - /* Scan backwards...
13224 - * Read the tags and decide what to do
13225 - */
13226 +static int yaffs_del_dir(yaffs_obj_t *obj)
13227 +{
13228 + /* First check that the directory is empty. */
13229 + if (yaffs_is_non_empty_dir(obj))
13230 + return YAFFS_FAIL;
13231
13232 - chunk = blk * dev->nChunksPerBlock + c;
13233 + return yaffs_generic_obj_del(obj);
13234 +}
13235
13236 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
13237 - &tags);
13238 +static int yaffs_del_symlink(yaffs_obj_t *in)
13239 +{
13240 + if(in->variant.symlink_variant.alias)
13241 + YFREE(in->variant.symlink_variant.alias);
13242 + in->variant.symlink_variant.alias=NULL;
13243
13244 - /* Let's have a good look at this chunk... */
13245 + return yaffs_generic_obj_del(in);
13246 +}
13247
13248 - if (!tags.chunkUsed) {
13249 - /* An unassigned chunk in the block.
13250 - * If there are used chunks after this one, then
13251 - * it is a chunk that was skipped due to failing the erased
13252 - * check. Just skip it so that it can be deleted.
13253 - * But, more typically, We get here when this is an unallocated
13254 - * chunk and his means that either the block is empty or
13255 - * this is the one being allocated from
13256 - */
13257 +static int yaffs_del_link(yaffs_obj_t *in)
13258 +{
13259 + /* remove this hardlink from the list assocaited with the equivalent
13260 + * object
13261 + */
13262 + ylist_del_init(&in->hard_links);
13263 + return yaffs_generic_obj_del(in);
13264 +}
13265
13266 - if (foundChunksInBlock) {
13267 - /* This is a chunk that was skipped due to failing the erased check */
13268 - } else if (c == 0) {
13269 - /* We're looking at the first chunk in the block so the block is unused */
13270 - state = YAFFS_BLOCK_STATE_EMPTY;
13271 - dev->nErasedBlocks++;
13272 - } else {
13273 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
13274 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
13275 - if (dev->sequenceNumber == bi->sequenceNumber) {
13276 - /* this is the block being allocated from */
13277 -
13278 - T(YAFFS_TRACE_SCAN,
13279 - (TSTR
13280 - (" Allocating from %d %d"
13281 - TENDSTR), blk, c));
13282 -
13283 - state = YAFFS_BLOCK_STATE_ALLOCATING;
13284 - dev->allocationBlock = blk;
13285 - dev->allocationPage = c;
13286 - dev->allocationBlockFinder = blk;
13287 - } else {
13288 - /* This is a partially written block that is not
13289 - * the current allocation block. This block must have
13290 - * had a write failure, so set up for retirement.
13291 - */
13292 -
13293 - /* bi->needsRetiring = 1; ??? TODO */
13294 - bi->gcPrioritise = 1;
13295 -
13296 - T(YAFFS_TRACE_ALWAYS,
13297 - (TSTR("Partially written block %d detected" TENDSTR),
13298 - blk));
13299 - }
13300 - }
13301 - }
13302 +int yaffs_del_obj(yaffs_obj_t *obj)
13303 +{
13304 +int retVal = -1;
13305 + switch (obj->variant_type) {
13306 + case YAFFS_OBJECT_TYPE_FILE:
13307 + retVal = yaffs_del_file(obj);
13308 + break;
13309 + case YAFFS_OBJECT_TYPE_DIRECTORY:
13310 + if(!ylist_empty(&obj->variant.dir_variant.dirty)){
13311 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->obj_id));
13312 + ylist_del_init(&obj->variant.dir_variant.dirty);
13313 + }
13314 + return yaffs_del_dir(obj);
13315 + break;
13316 + case YAFFS_OBJECT_TYPE_SYMLINK:
13317 + retVal = yaffs_del_symlink(obj);
13318 + break;
13319 + case YAFFS_OBJECT_TYPE_HARDLINK:
13320 + retVal = yaffs_del_link(obj);
13321 + break;
13322 + case YAFFS_OBJECT_TYPE_SPECIAL:
13323 + retVal = yaffs_generic_obj_del(obj);
13324 + break;
13325 + case YAFFS_OBJECT_TYPE_UNKNOWN:
13326 + retVal = 0;
13327 + break; /* should not happen. */
13328 + }
13329
13330 - dev->nFreeChunks++;
13331 + return retVal;
13332 +}
13333
13334 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
13335 - T(YAFFS_TRACE_SCAN,
13336 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
13337 - blk, c));
13338 -
13339 - dev->nFreeChunks++;
13340 -
13341 - } else if (tags.chunkId > 0) {
13342 - /* chunkId > 0 so it is a data chunk... */
13343 - unsigned int endpos;
13344 - __u32 chunkBase =
13345 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
13346 -
13347 - foundChunksInBlock = 1;
13348 -
13349 -
13350 - yaffs_SetChunkBit(dev, blk, c);
13351 - bi->pagesInUse++;
13352 -
13353 - in = yaffs_FindOrCreateObjectByNumber(dev,
13354 - tags.
13355 - objectId,
13356 - YAFFS_OBJECT_TYPE_FILE);
13357 - if (!in) {
13358 - /* Out of memory */
13359 - alloc_failed = 1;
13360 - }
13361 +static int yaffs_unlink_worker(yaffs_obj_t *obj)
13362 +{
13363
13364 - if (in &&
13365 - in->variantType == YAFFS_OBJECT_TYPE_FILE
13366 - && chunkBase <
13367 - in->variant.fileVariant.shrinkSize) {
13368 - /* This has not been invalidated by a resize */
13369 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
13370 - chunk, -1)) {
13371 - alloc_failed = 1;
13372 - }
13373 + int immediateDeletion = 0;
13374
13375 - /* File size is calculated by looking at the data chunks if we have not
13376 - * seen an object header yet. Stop this practice once we find an object header.
13377 - */
13378 - endpos =
13379 - (tags.chunkId -
13380 - 1) * dev->nDataBytesPerChunk +
13381 - tags.byteCount;
13382 -
13383 - if (!in->valid && /* have not got an object header yet */
13384 - in->variant.fileVariant.
13385 - scannedFileSize < endpos) {
13386 - in->variant.fileVariant.
13387 - scannedFileSize = endpos;
13388 - in->variant.fileVariant.
13389 - fileSize =
13390 - in->variant.fileVariant.
13391 - scannedFileSize;
13392 - }
13393 + if (!obj->my_inode)
13394 + immediateDeletion = 1;
13395
13396 - } else if (in) {
13397 - /* This chunk has been invalidated by a resize, so delete */
13398 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13399 + if(obj)
13400 + yaffs_update_parent(obj->parent);
13401
13402 - }
13403 - } else {
13404 - /* chunkId == 0, so it is an ObjectHeader.
13405 - * Thus, we read in the object header and make the object
13406 - */
13407 - foundChunksInBlock = 1;
13408 + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
13409 + return yaffs_del_link(obj);
13410 + } else if (!ylist_empty(&obj->hard_links)) {
13411 + /* Curve ball: We're unlinking an object that has a hardlink.
13412 + *
13413 + * This problem arises because we are not strictly following
13414 + * The Linux link/inode model.
13415 + *
13416 + * We can't really delete the object.
13417 + * Instead, we do the following:
13418 + * - Select a hardlink.
13419 + * - Unhook it from the hard links
13420 + * - Move it from its parent directory (so that the rename can work)
13421 + * - Rename the object to the hardlink's name.
13422 + * - Delete the hardlink
13423 + */
13424
13425 - yaffs_SetChunkBit(dev, blk, c);
13426 - bi->pagesInUse++;
13427 + yaffs_obj_t *hl;
13428 + yaffs_obj_t *parent;
13429 + int retVal;
13430 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
13431
13432 - oh = NULL;
13433 - in = NULL;
13434 + hl = ylist_entry(obj->hard_links.next, yaffs_obj_t, hard_links);
13435
13436 - if (tags.extraHeaderInfoAvailable) {
13437 - in = yaffs_FindOrCreateObjectByNumber
13438 - (dev, tags.objectId,
13439 - tags.extraObjectType);
13440 - if (!in)
13441 - alloc_failed = 1;
13442 - }
13443 + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
13444 + parent = hl->parent;
13445
13446 - if (!in ||
13447 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
13448 - !in->valid ||
13449 -#endif
13450 - tags.extraShadows ||
13451 - (!in->valid &&
13452 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13453 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
13454 -
13455 - /* If we don't have valid info then we need to read the chunk
13456 - * TODO In future we can probably defer reading the chunk and
13457 - * living with invalid data until needed.
13458 - */
13459 + ylist_del_init(&hl->hard_links);
13460
13461 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
13462 - chunk,
13463 - chunkData,
13464 - NULL);
13465 -
13466 - oh = (yaffs_ObjectHeader *) chunkData;
13467 -
13468 - if (dev->inbandTags) {
13469 - /* Fix up the header if they got corrupted by inband tags */
13470 - oh->shadowsObject = oh->inbandShadowsObject;
13471 - oh->isShrink = oh->inbandIsShrink;
13472 - }
13473 + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
13474
13475 - if (!in) {
13476 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
13477 - if (!in)
13478 - alloc_failed = 1;
13479 - }
13480 + retVal = yaffs_change_obj_name(obj,parent, name, 0, 0);
13481
13482 - }
13483 + if (retVal == YAFFS_OK)
13484 + retVal = yaffs_generic_obj_del(hl);
13485
13486 - if (!in) {
13487 - /* TODO Hoosterman we have a problem! */
13488 - T(YAFFS_TRACE_ERROR,
13489 - (TSTR
13490 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
13491 - TENDSTR), tags.objectId, chunk));
13492 - continue;
13493 - }
13494 + return retVal;
13495
13496 - if (in->valid) {
13497 - /* We have already filled this one.
13498 - * We have a duplicate that will be discarded, but
13499 - * we first have to suck out resize info if it is a file.
13500 - */
13501 + } else if (immediateDeletion) {
13502 + switch (obj->variant_type) {
13503 + case YAFFS_OBJECT_TYPE_FILE:
13504 + return yaffs_del_file(obj);
13505 + break;
13506 + case YAFFS_OBJECT_TYPE_DIRECTORY:
13507 + ylist_del_init(&obj->variant.dir_variant.dirty);
13508 + return yaffs_del_dir(obj);
13509 + break;
13510 + case YAFFS_OBJECT_TYPE_SYMLINK:
13511 + return yaffs_del_symlink(obj);
13512 + break;
13513 + case YAFFS_OBJECT_TYPE_SPECIAL:
13514 + return yaffs_generic_obj_del(obj);
13515 + break;
13516 + case YAFFS_OBJECT_TYPE_HARDLINK:
13517 + case YAFFS_OBJECT_TYPE_UNKNOWN:
13518 + default:
13519 + return YAFFS_FAIL;
13520 + }
13521 + } else if(yaffs_is_non_empty_dir(obj))
13522 + return YAFFS_FAIL;
13523 + else
13524 + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
13525 + _Y("unlinked"), 0, 0);
13526 +}
13527
13528 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
13529 - ((oh &&
13530 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
13531 - (tags.extraHeaderInfoAvailable &&
13532 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
13533 - __u32 thisSize =
13534 - (oh) ? oh->fileSize : tags.
13535 - extraFileLength;
13536 - __u32 parentObjectId =
13537 - (oh) ? oh->
13538 - parentObjectId : tags.
13539 - extraParentObjectId;
13540 -
13541 -
13542 - isShrink =
13543 - (oh) ? oh->isShrink : tags.
13544 - extraIsShrinkHeader;
13545
13546 - /* If it is deleted (unlinked at start also means deleted)
13547 - * we treat the file size as being zeroed at this point.
13548 - */
13549 - if (parentObjectId ==
13550 - YAFFS_OBJECTID_DELETED
13551 - || parentObjectId ==
13552 - YAFFS_OBJECTID_UNLINKED) {
13553 - thisSize = 0;
13554 - isShrink = 1;
13555 - }
13556 +static int yaffs_unlink_obj(yaffs_obj_t *obj)
13557 +{
13558
13559 - if (isShrink &&
13560 - in->variant.fileVariant.
13561 - shrinkSize > thisSize) {
13562 - in->variant.fileVariant.
13563 - shrinkSize =
13564 - thisSize;
13565 - }
13566 + if (obj && obj->unlink_allowed)
13567 + return yaffs_unlink_worker(obj);
13568
13569 - if (isShrink)
13570 - bi->hasShrinkHeader = 1;
13571 + return YAFFS_FAIL;
13572
13573 - }
13574 - /* Use existing - destroy this one. */
13575 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13576 +}
13577 +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name)
13578 +{
13579 + yaffs_obj_t *obj;
13580
13581 - }
13582 + obj = yaffs_find_by_name(dir, name);
13583 + return yaffs_unlink_obj(obj);
13584 +}
13585
13586 - if (!in->valid && in->variantType !=
13587 - (oh ? oh->type : tags.extraObjectType))
13588 - T(YAFFS_TRACE_ERROR, (
13589 - TSTR("yaffs tragedy: Bad object type, "
13590 - TCONT("%d != %d, for object %d at chunk ")
13591 - TCONT("%d during scan")
13592 - TENDSTR), oh ?
13593 - oh->type : tags.extraObjectType,
13594 - in->variantType, tags.objectId,
13595 - chunk));
13596 -
13597 - if (!in->valid &&
13598 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13599 - tags.objectId ==
13600 - YAFFS_OBJECTID_LOSTNFOUND)) {
13601 - /* We only load some info, don't fiddle with directory structure */
13602 - in->valid = 1;
13603 +/*----------------------- Initialisation Scanning ---------------------- */
13604
13605 - if (oh) {
13606 - in->variantType = oh->type;
13607 +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
13608 + int backward_scanning)
13609 +{
13610 + yaffs_obj_t *obj;
13611
13612 - in->yst_mode = oh->yst_mode;
13613 -#ifdef CONFIG_YAFFS_WINCE
13614 - in->win_atime[0] = oh->win_atime[0];
13615 - in->win_ctime[0] = oh->win_ctime[0];
13616 - in->win_mtime[0] = oh->win_mtime[0];
13617 - in->win_atime[1] = oh->win_atime[1];
13618 - in->win_ctime[1] = oh->win_ctime[1];
13619 - in->win_mtime[1] = oh->win_mtime[1];
13620 -#else
13621 - in->yst_uid = oh->yst_uid;
13622 - in->yst_gid = oh->yst_gid;
13623 - in->yst_atime = oh->yst_atime;
13624 - in->yst_mtime = oh->yst_mtime;
13625 - in->yst_ctime = oh->yst_ctime;
13626 - in->yst_rdev = oh->yst_rdev;
13627 + if (!backward_scanning) {
13628 + /* Handle YAFFS1 forward scanning case
13629 + * For YAFFS1 we always do the deletion
13630 + */
13631
13632 -#endif
13633 - } else {
13634 - in->variantType = tags.extraObjectType;
13635 - in->lazyLoaded = 1;
13636 - }
13637 + } else {
13638 + /* Handle YAFFS2 case (backward scanning)
13639 + * If the shadowed object exists then ignore.
13640 + */
13641 + obj = yaffs_find_by_number(dev, obj_id);
13642 + if(obj)
13643 + return;
13644 + }
13645
13646 - in->hdrChunk = chunk;
13647 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13648 + * We put it in unlinked dir to be cleaned up after the scanning
13649 + */
13650 + obj =
13651 + yaffs_find_or_create_by_number(dev, obj_id,
13652 + YAFFS_OBJECT_TYPE_FILE);
13653 + if (!obj)
13654 + return;
13655 + obj->is_shadowed = 1;
13656 + yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
13657 + obj->variant.file_variant.shrink_size = 0;
13658 + obj->valid = 1; /* So that we don't read any other info for this file */
13659
13660 - } else if (!in->valid) {
13661 - /* we need to load this info */
13662 +}
13663
13664 - in->valid = 1;
13665 - in->hdrChunk = chunk;
13666
13667 - if (oh) {
13668 - in->variantType = oh->type;
13669 +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list)
13670 +{
13671 + yaffs_obj_t *hl;
13672 + yaffs_obj_t *in;
13673
13674 - in->yst_mode = oh->yst_mode;
13675 -#ifdef CONFIG_YAFFS_WINCE
13676 - in->win_atime[0] = oh->win_atime[0];
13677 - in->win_ctime[0] = oh->win_ctime[0];
13678 - in->win_mtime[0] = oh->win_mtime[0];
13679 - in->win_atime[1] = oh->win_atime[1];
13680 - in->win_ctime[1] = oh->win_ctime[1];
13681 - in->win_mtime[1] = oh->win_mtime[1];
13682 -#else
13683 - in->yst_uid = oh->yst_uid;
13684 - in->yst_gid = oh->yst_gid;
13685 - in->yst_atime = oh->yst_atime;
13686 - in->yst_mtime = oh->yst_mtime;
13687 - in->yst_ctime = oh->yst_ctime;
13688 - in->yst_rdev = oh->yst_rdev;
13689 -#endif
13690 + while (hard_list) {
13691 + hl = hard_list;
13692 + hard_list = (yaffs_obj_t *) (hard_list->hard_links.next);
13693 +
13694 + in = yaffs_find_by_number(dev,
13695 + hl->variant.hardlink_variant.
13696 + equiv_id);
13697
13698 - if (oh->shadowsObject > 0)
13699 - yaffs_HandleShadowedObject(dev,
13700 - oh->
13701 - shadowsObject,
13702 - 1);
13703 -
13704 -
13705 - yaffs_SetObjectName(in, oh->name);
13706 - parent =
13707 - yaffs_FindOrCreateObjectByNumber
13708 - (dev, oh->parentObjectId,
13709 - YAFFS_OBJECT_TYPE_DIRECTORY);
13710 -
13711 - fileSize = oh->fileSize;
13712 - isShrink = oh->isShrink;
13713 - equivalentObjectId = oh->equivalentObjectId;
13714 + if (in) {
13715 + /* Add the hardlink pointers */
13716 + hl->variant.hardlink_variant.equiv_obj = in;
13717 + ylist_add(&hl->hard_links, &in->hard_links);
13718 + } else {
13719 + /* Todo Need to report/handle this better.
13720 + * Got a problem... hardlink to a non-existant object
13721 + */
13722 + hl->variant.hardlink_variant.equiv_obj = NULL;
13723 + YINIT_LIST_HEAD(&hl->hard_links);
13724
13725 - } else {
13726 - in->variantType = tags.extraObjectType;
13727 - parent =
13728 - yaffs_FindOrCreateObjectByNumber
13729 - (dev, tags.extraParentObjectId,
13730 - YAFFS_OBJECT_TYPE_DIRECTORY);
13731 - fileSize = tags.extraFileLength;
13732 - isShrink = tags.extraIsShrinkHeader;
13733 - equivalentObjectId = tags.extraEquivalentObjectId;
13734 - in->lazyLoaded = 1;
13735 + }
13736 + }
13737 +}
13738
13739 - }
13740 - in->dirty = 0;
13741
13742 - if (!parent)
13743 - alloc_failed = 1;
13744 +static void yaffs_strip_deleted_objs(yaffs_dev_t *dev)
13745 +{
13746 + /*
13747 + * Sort out state of unlinked and deleted objects after scanning.
13748 + */
13749 + struct ylist_head *i;
13750 + struct ylist_head *n;
13751 + yaffs_obj_t *l;
13752
13753 - /* directory stuff...
13754 - * hook up to parent
13755 - */
13756 + if (dev->read_only)
13757 + return;
13758
13759 - if (parent && parent->variantType ==
13760 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13761 - /* Set up as a directory */
13762 - parent->variantType =
13763 - YAFFS_OBJECT_TYPE_DIRECTORY;
13764 - YINIT_LIST_HEAD(&parent->variant.
13765 - directoryVariant.
13766 - children);
13767 - } else if (!parent || parent->variantType !=
13768 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13769 - /* Hoosterman, another problem....
13770 - * We're trying to use a non-directory as a directory
13771 - */
13772 + /* Soft delete all the unlinked files */
13773 + ylist_for_each_safe(i, n,
13774 + &dev->unlinked_dir->variant.dir_variant.children) {
13775 + if (i) {
13776 + l = ylist_entry(i, yaffs_obj_t, siblings);
13777 + yaffs_del_obj(l);
13778 + }
13779 + }
13780
13781 - T(YAFFS_TRACE_ERROR,
13782 - (TSTR
13783 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13784 - TENDSTR)));
13785 - parent = dev->lostNFoundDir;
13786 - }
13787 + ylist_for_each_safe(i, n,
13788 + &dev->del_dir->variant.dir_variant.children) {
13789 + if (i) {
13790 + l = ylist_entry(i, yaffs_obj_t, siblings);
13791 + yaffs_del_obj(l);
13792 + }
13793 + }
13794
13795 - yaffs_AddObjectToDirectory(parent, in);
13796 +}
13797
13798 - itsUnlinked = (parent == dev->deletedDir) ||
13799 - (parent == dev->unlinkedDir);
13800 +/*
13801 + * This code iterates through all the objects making sure that they are rooted.
13802 + * Any unrooted objects are re-rooted in lost+found.
13803 + * An object needs to be in one of:
13804 + * - Directly under deleted, unlinked
13805 + * - Directly or indirectly under root.
13806 + *
13807 + * Note:
13808 + * This code assumes that we don't ever change the current relationships between
13809 + * directories:
13810 + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
13811 + * lostNfound->parent == root_dir
13812 + *
13813 + * This fixes the problem where directories might have inadvertently been deleted
13814 + * leaving the object "hanging" without being rooted in the directory tree.
13815 + */
13816 +
13817 +static int yaffs_has_null_parent(yaffs_dev_t *dev, yaffs_obj_t *obj)
13818 +{
13819 + return (obj == dev->del_dir ||
13820 + obj == dev->unlinked_dir||
13821 + obj == dev->root_dir);
13822 +}
13823
13824 - if (isShrink) {
13825 - /* Mark the block as having a shrinkHeader */
13826 - bi->hasShrinkHeader = 1;
13827 - }
13828 +static void yaffs_fix_hanging_objs(yaffs_dev_t *dev)
13829 +{
13830 + yaffs_obj_t *obj;
13831 + yaffs_obj_t *parent;
13832 + int i;
13833 + struct ylist_head *lh;
13834 + struct ylist_head *n;
13835 + int depthLimit;
13836 + int hanging;
13837
13838 - /* Note re hardlinks.
13839 - * Since we might scan a hardlink before its equivalent object is scanned
13840 - * we put them all in a list.
13841 - * After scanning is complete, we should have all the objects, so we run
13842 - * through this list and fix up all the chains.
13843 - */
13844 + if (dev->read_only)
13845 + return;
13846
13847 - switch (in->variantType) {
13848 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13849 - /* Todo got a problem */
13850 - break;
13851 - case YAFFS_OBJECT_TYPE_FILE:
13852 -
13853 - if (in->variant.fileVariant.
13854 - scannedFileSize < fileSize) {
13855 - /* This covers the case where the file size is greater
13856 - * than where the data is
13857 - * This will happen if the file is resized to be larger
13858 - * than its current data extents.
13859 - */
13860 - in->variant.fileVariant.fileSize = fileSize;
13861 - in->variant.fileVariant.scannedFileSize =
13862 - in->variant.fileVariant.fileSize;
13863 - }
13864 + /* Iterate through the objects in each hash entry,
13865 + * looking at each object.
13866 + * Make sure it is rooted.
13867 + */
13868
13869 - if (isShrink &&
13870 - in->variant.fileVariant.shrinkSize > fileSize) {
13871 - in->variant.fileVariant.shrinkSize = fileSize;
13872 - }
13873 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13874 + ylist_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
13875 + if (lh) {
13876 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
13877 + parent= obj->parent;
13878 +
13879 + if(yaffs_has_null_parent(dev,obj)){
13880 + /* These directories are not hanging */
13881 + hanging = 0;
13882 + }
13883 + else if(!parent || parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
13884 + hanging = 1;
13885 + else if(yaffs_has_null_parent(dev,parent))
13886 + hanging = 0;
13887 + else {
13888 + /*
13889 + * Need to follow the parent chain to see if it is hanging.
13890 + */
13891 + hanging = 0;
13892 + depthLimit=100;
13893
13894 - break;
13895 - case YAFFS_OBJECT_TYPE_HARDLINK:
13896 - if (!itsUnlinked) {
13897 - in->variant.hardLinkVariant.equivalentObjectId =
13898 - equivalentObjectId;
13899 - in->hardLinks.next =
13900 - (struct ylist_head *) hardList;
13901 - hardList = in;
13902 - }
13903 - break;
13904 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13905 - /* Do nothing */
13906 - break;
13907 - case YAFFS_OBJECT_TYPE_SPECIAL:
13908 - /* Do nothing */
13909 - break;
13910 - case YAFFS_OBJECT_TYPE_SYMLINK:
13911 - if (oh) {
13912 - in->variant.symLinkVariant.alias =
13913 - yaffs_CloneString(oh->alias);
13914 - if (!in->variant.symLinkVariant.alias)
13915 - alloc_failed = 1;
13916 - }
13917 - break;
13918 + while(parent != dev->root_dir &&
13919 + parent->parent &&
13920 + parent->parent->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
13921 + depthLimit > 0){
13922 + parent = parent->parent;
13923 + depthLimit--;
13924 }
13925 -
13926 + if(parent != dev->root_dir)
13927 + hanging = 1;
13928 + }
13929 + if(hanging){
13930 + T(YAFFS_TRACE_SCAN,
13931 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13932 + obj->obj_id));
13933 + yaffs_add_obj_to_dir(dev->lost_n_found,obj);
13934 }
13935 -
13936 }
13937 + }
13938 + }
13939 +}
13940
13941 - } /* End of scanning for each chunk */
13942
13943 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13944 - /* If we got this far while scanning, then the block is fully allocated. */
13945 - state = YAFFS_BLOCK_STATE_FULL;
13946 - }
13947 +/*
13948 + * Delete directory contents for cleaning up lost and found.
13949 + */
13950 +static void yaffs_del_dir_contents(yaffs_obj_t *dir)
13951 +{
13952 + yaffs_obj_t *obj;
13953 + struct ylist_head *lh;
13954 + struct ylist_head *n;
13955
13956 - bi->blockState = state;
13957 + if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
13958 + YBUG();
13959 +
13960 + ylist_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
13961 + if (lh) {
13962 + obj = ylist_entry(lh, yaffs_obj_t, siblings);
13963 + if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
13964 + yaffs_del_dir_contents(obj);
13965 +
13966 + T(YAFFS_TRACE_SCAN,
13967 + (TSTR("Deleting lost_found object %d" TENDSTR),
13968 + obj->obj_id));
13969
13970 - /* Now let's see if it was dirty */
13971 - if (bi->pagesInUse == 0 &&
13972 - !bi->hasShrinkHeader &&
13973 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13974 - yaffs_BlockBecameDirty(dev, blk);
13975 + /* Need to use UnlinkObject since Delete would not handle
13976 + * hardlinked objects correctly.
13977 + */
13978 + yaffs_unlink_obj(obj);
13979 }
13980 -
13981 }
13982 +
13983 +}
13984
13985 - if (altBlockIndex)
13986 - YFREE_ALT(blockIndex);
13987 - else
13988 - YFREE(blockIndex);
13989 +static void yaffs_empty_l_n_f(yaffs_dev_t *dev)
13990 +{
13991 + yaffs_del_dir_contents(dev->lost_n_found);
13992 +}
13993
13994 - /* Ok, we've done all the scanning.
13995 - * Fix up the hard link chains.
13996 - * We should now have scanned all the objects, now it's time to add these
13997 - * hardlinks.
13998 - */
13999 - yaffs_HardlinkFixup(dev, hardList);
14000 +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in)
14001 +{
14002 + __u8 *chunkData;
14003 + yaffs_obj_header *oh;
14004 + yaffs_dev_t *dev;
14005 + yaffs_ext_tags tags;
14006 + int result;
14007 + int alloc_failed = 0;
14008
14009 + if (!in)
14010 + return;
14011
14012 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
14013 + dev = in->my_dev;
14014
14015 - if (alloc_failed)
14016 - return YAFFS_FAIL;
14017 +#if 0
14018 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
14019 + in->obj_id,
14020 + in->lazy_loaded ? "not yet" : "already"));
14021 +#endif
14022
14023 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
14024 + if (in->lazy_loaded && in->hdr_chunk > 0) {
14025 + in->lazy_loaded = 0;
14026 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
14027
14028 - return YAFFS_OK;
14029 -}
14030 + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunkData, &tags);
14031 + oh = (yaffs_obj_header *) chunkData;
14032
14033 -/*------------------------------ Directory Functions ----------------------------- */
14034 + in->yst_mode = oh->yst_mode;
14035 +#ifdef CONFIG_YAFFS_WINCE
14036 + in->win_atime[0] = oh->win_atime[0];
14037 + in->win_ctime[0] = oh->win_ctime[0];
14038 + in->win_mtime[0] = oh->win_mtime[0];
14039 + in->win_atime[1] = oh->win_atime[1];
14040 + in->win_ctime[1] = oh->win_ctime[1];
14041 + in->win_mtime[1] = oh->win_mtime[1];
14042 +#else
14043 + in->yst_uid = oh->yst_uid;
14044 + in->yst_gid = oh->yst_gid;
14045 + in->yst_atime = oh->yst_atime;
14046 + in->yst_mtime = oh->yst_mtime;
14047 + in->yst_ctime = oh->yst_ctime;
14048 + in->yst_rdev = oh->yst_rdev;
14049
14050 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
14051 -{
14052 - struct ylist_head *lh;
14053 - yaffs_Object *listObj;
14054 +#endif
14055 + yaffs_set_obj_name_from_oh(in, oh);
14056
14057 - int count = 0;
14058 + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
14059 + in->variant.symlink_variant.alias =
14060 + yaffs_clone_str(oh->alias);
14061 + if (!in->variant.symlink_variant.alias)
14062 + alloc_failed = 1; /* Not returned to caller */
14063 + }
14064
14065 - if (!obj) {
14066 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
14067 - YBUG();
14068 - return;
14069 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
14070 }
14071 +}
14072
14073 - if (yaffs_SkipVerification(obj->myDev))
14074 - return;
14075 +/*------------------------------ Directory Functions ----------------------------- */
14076
14077 - if (!obj->parent) {
14078 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
14079 - YBUG();
14080 +/*
14081 + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
14082 + * link (ie. name) is created or deleted in the directory.
14083 + *
14084 + * ie.
14085 + * create dir/a : update dir's mtime/ctime
14086 + * rm dir/a: update dir's mtime/ctime
14087 + * modify dir/a: don't update dir's mtimme/ctime
14088 + *
14089 + * This can be handled immediately or defered. Defering helps reduce the number
14090 + * of updates when many files in a directory are changed within a brief period.
14091 + *
14092 + * If the directory updating is defered then yaffs_update_dirty_dirs must be
14093 + * called periodically.
14094 + */
14095 +
14096 +static void yaffs_update_parent(yaffs_obj_t *obj)
14097 +{
14098 + yaffs_dev_t *dev;
14099 + if(!obj)
14100 return;
14101 - }
14102 -
14103 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14104 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
14105 - YBUG();
14106 - }
14107 -
14108 - /* Iterate through the objects in each hash entry */
14109 +#ifndef CONFIG_YAFFS_WINCE
14110
14111 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
14112 - if (lh) {
14113 - listObj = ylist_entry(lh, yaffs_Object, siblings);
14114 - yaffs_VerifyObject(listObj);
14115 - if (obj == listObj)
14116 - count++;
14117 + dev = obj->my_dev;
14118 + obj->dirty = 1;
14119 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
14120 + if(dev->param.defered_dir_update){
14121 + struct ylist_head *link = &obj->variant.dir_variant.dirty;
14122 +
14123 + if(ylist_empty(link)){
14124 + ylist_add(link,&dev->dirty_dirs);
14125 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->obj_id));
14126 }
14127 - }
14128
14129 - if (count != 1) {
14130 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
14131 - YBUG();
14132 - }
14133 + } else
14134 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
14135 +#endif
14136 }
14137
14138 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
14139 +void yaffs_update_dirty_dirs(yaffs_dev_t *dev)
14140 {
14141 - struct ylist_head *lh;
14142 - yaffs_Object *listObj;
14143 -
14144 - if (!directory) {
14145 - YBUG();
14146 - return;
14147 - }
14148 + struct ylist_head *link;
14149 + yaffs_obj_t *obj;
14150 + yaffs_dir_s *dS;
14151 + yaffs_obj_variant *oV;
14152
14153 - if (yaffs_SkipFullVerification(directory->myDev))
14154 - return;
14155 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
14156
14157 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14158 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
14159 - YBUG();
14160 - }
14161 + while(!ylist_empty(&dev->dirty_dirs)){
14162 + link = dev->dirty_dirs.next;
14163 + ylist_del_init(link);
14164 +
14165 + dS=ylist_entry(link,yaffs_dir_s,dirty);
14166 + oV = ylist_entry(dS,yaffs_obj_variant,dir_variant);
14167 + obj = ylist_entry(oV,yaffs_obj_t,variant);
14168
14169 - /* Iterate through the objects in each hash entry */
14170 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->obj_id));
14171
14172 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
14173 - if (lh) {
14174 - listObj = ylist_entry(lh, yaffs_Object, siblings);
14175 - if (listObj->parent != directory) {
14176 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
14177 - YBUG();
14178 - }
14179 - yaffs_VerifyObjectInDirectory(listObj);
14180 - }
14181 + if(obj->dirty)
14182 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
14183 }
14184 }
14185
14186 -
14187 -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
14188 +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj)
14189 {
14190 - yaffs_Device *dev = obj->myDev;
14191 - yaffs_Object *parent;
14192 + yaffs_dev_t *dev = obj->my_dev;
14193 + yaffs_obj_t *parent;
14194
14195 - yaffs_VerifyObjectInDirectory(obj);
14196 + yaffs_verify_obj_in_dir(obj);
14197 parent = obj->parent;
14198
14199 - yaffs_VerifyDirectory(parent);
14200 + yaffs_verify_dir(parent);
14201
14202 - if (dev && dev->removeObjectCallback)
14203 - dev->removeObjectCallback(obj);
14204 + if (dev && dev->param.remove_obj_fn)
14205 + dev->param.remove_obj_fn(obj);
14206
14207
14208 ylist_del_init(&obj->siblings);
14209 obj->parent = NULL;
14210 -
14211 - yaffs_VerifyDirectory(parent);
14212 +
14213 + yaffs_verify_dir(parent);
14214 }
14215
14216 -
14217 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14218 - yaffs_Object *obj)
14219 +void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
14220 + yaffs_obj_t *obj)
14221 {
14222 if (!directory) {
14223 T(YAFFS_TRACE_ALWAYS,
14224 @@ -6699,7 +4495,7 @@ static void yaffs_AddObjectToDirectory(y
14225 YBUG();
14226 return;
14227 }
14228 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14229 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14230 T(YAFFS_TRACE_ALWAYS,
14231 (TSTR
14232 ("tragedy: Trying to add an object to a non-directory"
14233 @@ -6713,27 +4509,27 @@ static void yaffs_AddObjectToDirectory(y
14234 }
14235
14236
14237 - yaffs_VerifyDirectory(directory);
14238 + yaffs_verify_dir(directory);
14239
14240 - yaffs_RemoveObjectFromDirectory(obj);
14241 + yaffs_remove_obj_from_dir(obj);
14242
14243
14244 /* Now add it */
14245 - ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
14246 + ylist_add(&obj->siblings, &directory->variant.dir_variant.children);
14247 obj->parent = directory;
14248
14249 - if (directory == obj->myDev->unlinkedDir
14250 - || directory == obj->myDev->deletedDir) {
14251 + if (directory == obj->my_dev->unlinked_dir
14252 + || directory == obj->my_dev->del_dir) {
14253 obj->unlinked = 1;
14254 - obj->myDev->nUnlinkedFiles++;
14255 - obj->renameAllowed = 0;
14256 + obj->my_dev->n_unlinked_files++;
14257 + obj->rename_allowed = 0;
14258 }
14259
14260 - yaffs_VerifyDirectory(directory);
14261 - yaffs_VerifyObjectInDirectory(obj);
14262 + yaffs_verify_dir(directory);
14263 + yaffs_verify_obj_in_dir(obj);
14264 }
14265
14266 -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,
14267 +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *directory,
14268 const YCHAR *name)
14269 {
14270 int sum;
14271 @@ -6741,7 +4537,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14272 struct ylist_head *i;
14273 YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
14274
14275 - yaffs_Object *l;
14276 + yaffs_obj_t *l;
14277
14278 if (!name)
14279 return NULL;
14280 @@ -6749,39 +4545,39 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14281 if (!directory) {
14282 T(YAFFS_TRACE_ALWAYS,
14283 (TSTR
14284 - ("tragedy: yaffs_FindObjectByName: null pointer directory"
14285 + ("tragedy: yaffs_find_by_name: null pointer directory"
14286 TENDSTR)));
14287 YBUG();
14288 return NULL;
14289 }
14290 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14291 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14292 T(YAFFS_TRACE_ALWAYS,
14293 (TSTR
14294 - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
14295 + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
14296 YBUG();
14297 }
14298
14299 - sum = yaffs_CalcNameSum(name);
14300 + sum = yaffs_calc_name_sum(name);
14301
14302 - ylist_for_each(i, &directory->variant.directoryVariant.children) {
14303 + ylist_for_each(i, &directory->variant.dir_variant.children) {
14304 if (i) {
14305 - l = ylist_entry(i, yaffs_Object, siblings);
14306 + l = ylist_entry(i, yaffs_obj_t, siblings);
14307
14308 if (l->parent != directory)
14309 YBUG();
14310
14311 - yaffs_CheckObjectDetailsLoaded(l);
14312 + yaffs_check_obj_details_loaded(l);
14313
14314 /* Special case for lost-n-found */
14315 - if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
14316 + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
14317 if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
14318 return l;
14319 - } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {
14320 + } else if (yaffs_sum_cmp(l->sum, sum) || l->hdr_chunk <= 0) {
14321 /* LostnFound chunk called Objxxx
14322 * Do a real check
14323 */
14324 - yaffs_GetObjectName(l, buffer,
14325 - YAFFS_MAX_NAME_LENGTH);
14326 + yaffs_get_obj_name(l, buffer,
14327 + YAFFS_MAX_NAME_LENGTH + 1);
14328 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
14329 return l;
14330 }
14331 @@ -6793,31 +4589,31 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14332
14333
14334 #if 0
14335 -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
14336 - int (*fn) (yaffs_Object *))
14337 +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
14338 + int (*fn) (yaffs_obj_t *))
14339 {
14340 struct ylist_head *i;
14341 - yaffs_Object *l;
14342 + yaffs_obj_t *l;
14343
14344 - if (!theDir) {
14345 + if (!the_dir) {
14346 T(YAFFS_TRACE_ALWAYS,
14347 (TSTR
14348 - ("tragedy: yaffs_FindObjectByName: null pointer directory"
14349 + ("tragedy: yaffs_find_by_name: null pointer directory"
14350 TENDSTR)));
14351 YBUG();
14352 return YAFFS_FAIL;
14353 }
14354 - if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14355 + if (the_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14356 T(YAFFS_TRACE_ALWAYS,
14357 (TSTR
14358 - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
14359 + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
14360 YBUG();
14361 return YAFFS_FAIL;
14362 }
14363
14364 - ylist_for_each(i, &theDir->variant.directoryVariant.children) {
14365 + ylist_for_each(i, &the_dir->variant.dir_variant.children) {
14366 if (i) {
14367 - l = ylist_entry(i, yaffs_Object, siblings);
14368 + l = ylist_entry(i, yaffs_obj_t, siblings);
14369 if (l && !fn(l))
14370 return YAFFS_FAIL;
14371 }
14372 @@ -6832,82 +4628,175 @@ int yaffs_ApplyToDirectoryChildren(yaffs
14373 * actual object.
14374 */
14375
14376 -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
14377 +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj)
14378 {
14379 - if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
14380 + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
14381 /* We want the object id of the equivalent object, not this one */
14382 - obj = obj->variant.hardLinkVariant.equivalentObject;
14383 - yaffs_CheckObjectDetailsLoaded(obj);
14384 + obj = obj->variant.hardlink_variant.equiv_obj;
14385 + yaffs_check_obj_details_loaded(obj);
14386 }
14387 return obj;
14388 }
14389
14390 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
14391 -{
14392 - memset(name, 0, buffSize * sizeof(YCHAR));
14393 -
14394 - yaffs_CheckObjectDetailsLoaded(obj);
14395 +/*
14396 + * A note or two on object names.
14397 + * * If the object name is missing, we then make one up in the form objnnn
14398 + *
14399 + * * ASCII names are stored in the object header's name field from byte zero
14400 + * * Unicode names are historically stored starting from byte zero.
14401 + *
14402 + * Then there are automatic Unicode names...
14403 + * The purpose of these is to save names in a way that can be read as
14404 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
14405 + * system to share files.
14406 + *
14407 + * These automatic unicode are stored slightly differently...
14408 + * - If the name can fit in the ASCII character space then they are saved as
14409 + * ascii names as per above.
14410 + * - If the name needs Unicode then the name is saved in Unicode
14411 + * starting at oh->name[1].
14412
14413 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
14414 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
14415 - } else if (obj->hdrChunk <= 0) {
14416 + */
14417 +static void yaffs_fix_null_name(yaffs_obj_t * obj,YCHAR * name, int buffer_size)
14418 +{
14419 + /* Create an object name if we could not find one. */
14420 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
14421 YCHAR locName[20];
14422 YCHAR numString[20];
14423 YCHAR *x = &numString[19];
14424 - unsigned v = obj->objectId;
14425 + unsigned v = obj->obj_id;
14426 numString[19] = 0;
14427 - while (v > 0) {
14428 + while(v>0){
14429 x--;
14430 *x = '0' + (v % 10);
14431 v /= 10;
14432 }
14433 /* make up a name */
14434 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
14435 - yaffs_strcat(locName, x);
14436 - yaffs_strncpy(name, locName, buffSize - 1);
14437 + yaffs_strcat(locName,x);
14438 + yaffs_strncpy(name, locName, buffer_size - 1);
14439 + }
14440 +}
14441 +
14442 +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
14443 +{
14444 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14445 + if(dev->param.auto_unicode){
14446 + if(*ohName){
14447 + /* It is an ASCII name, so do an ASCII to unicode conversion */
14448 + const char *asciiOhName = (const char *)ohName;
14449 + int n = bufferSize - 1;
14450 + while(n > 0 && *asciiOhName){
14451 + *name = *asciiOhName;
14452 + name++;
14453 + asciiOhName++;
14454 + n--;
14455 + }
14456 + } else
14457 + yaffs_strncpy(name,ohName+1, bufferSize -1);
14458 + } else
14459 +#endif
14460 + yaffs_strncpy(name, ohName, bufferSize - 1);
14461 +}
14462 +
14463 +
14464 +static void yaffs_load_oh_from_name(yaffs_dev_t *dev, YCHAR *ohName, const YCHAR *name)
14465 +{
14466 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14467 +
14468 + int isAscii;
14469 + YCHAR *w;
14470 +
14471 + if(dev->param.auto_unicode){
14472 +
14473 + isAscii = 1;
14474 + w = name;
14475 +
14476 + /* Figure out if the name will fit in ascii character set */
14477 + while(isAscii && *w){
14478 + if((*w) & 0xff00)
14479 + isAscii = 0;
14480 + w++;
14481 + }
14482
14483 + if(isAscii){
14484 + /* It is an ASCII name, so do a unicode to ascii conversion */
14485 + char *asciiOhName = (char *)ohName;
14486 + int n = YAFFS_MAX_NAME_LENGTH - 1;
14487 + while(n > 0 && *name){
14488 + *asciiOhName= *name;
14489 + name++;
14490 + asciiOhName++;
14491 + n--;
14492 + }
14493 + } else{
14494 + /* It is a unicode name, so save starting at the second YCHAR */
14495 + *ohName = 0;
14496 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
14497 + }
14498 }
14499 + else
14500 +#endif
14501 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
14502 +
14503 +}
14504 +
14505 +int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size)
14506 +{
14507 + memset(name, 0, buffer_size * sizeof(YCHAR));
14508 +
14509 + yaffs_check_obj_details_loaded(obj);
14510 +
14511 + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
14512 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
14513 + }
14514 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
14515 - else if (obj->shortName[0])
14516 - yaffs_strcpy(name, obj->shortName);
14517 + else if (obj->short_name[0]) {
14518 + yaffs_strcpy(name, obj->short_name);
14519 + }
14520 #endif
14521 - else {
14522 + else if(obj->hdr_chunk > 0) {
14523 int result;
14524 - __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
14525 + __u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__);
14526
14527 - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
14528 + yaffs_obj_header *oh = (yaffs_obj_header *) buffer;
14529
14530 - memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
14531 + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
14532
14533 - if (obj->hdrChunk > 0) {
14534 - result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
14535 - obj->hdrChunk, buffer,
14536 + if (obj->hdr_chunk > 0) {
14537 + result = yaffs_rd_chunk_tags_nand(obj->my_dev,
14538 + obj->hdr_chunk, buffer,
14539 NULL);
14540 }
14541 - yaffs_strncpy(name, oh->name, buffSize - 1);
14542 + yaffs_load_name_from_oh(obj->my_dev,name,oh->name,buffer_size);
14543
14544 - yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
14545 + yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__);
14546 }
14547
14548 - return yaffs_strlen(name);
14549 + yaffs_fix_null_name(obj,name,buffer_size);
14550 +
14551 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
14552 }
14553
14554 -int yaffs_GetObjectFileLength(yaffs_Object *obj)
14555 +
14556 +int yaffs_get_obj_length(yaffs_obj_t *obj)
14557 {
14558 /* Dereference any hard linking */
14559 - obj = yaffs_GetEquivalentObject(obj);
14560 + obj = yaffs_get_equivalent_obj(obj);
14561
14562 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
14563 - return obj->variant.fileVariant.fileSize;
14564 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
14565 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
14566 - else {
14567 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
14568 + return obj->variant.file_variant.file_size;
14569 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
14570 + if(!obj->variant.symlink_variant.alias)
14571 + return 0;
14572 + return yaffs_strnlen(obj->variant.symlink_variant.alias,YAFFS_MAX_ALIAS_LENGTH);
14573 + } else {
14574 /* Only a directory should drop through to here */
14575 - return obj->myDev->nDataBytesPerChunk;
14576 + return obj->my_dev->data_bytes_per_chunk;
14577 }
14578 }
14579
14580 -int yaffs_GetObjectLinkCount(yaffs_Object *obj)
14581 +int yaffs_get_obj_link_count(yaffs_obj_t *obj)
14582 {
14583 int count = 0;
14584 struct ylist_head *i;
14585 @@ -6915,24 +4804,24 @@ int yaffs_GetObjectLinkCount(yaffs_Objec
14586 if (!obj->unlinked)
14587 count++; /* the object itself */
14588
14589 - ylist_for_each(i, &obj->hardLinks)
14590 + ylist_for_each(i, &obj->hard_links)
14591 count++; /* add the hard links; */
14592
14593 return count;
14594 }
14595
14596 -int yaffs_GetObjectInode(yaffs_Object *obj)
14597 +int yaffs_get_obj_inode(yaffs_obj_t *obj)
14598 {
14599 - obj = yaffs_GetEquivalentObject(obj);
14600 + obj = yaffs_get_equivalent_obj(obj);
14601
14602 - return obj->objectId;
14603 + return obj->obj_id;
14604 }
14605
14606 -unsigned yaffs_GetObjectType(yaffs_Object *obj)
14607 +unsigned yaffs_get_obj_type(yaffs_obj_t *obj)
14608 {
14609 - obj = yaffs_GetEquivalentObject(obj);
14610 + obj = yaffs_get_equivalent_obj(obj);
14611
14612 - switch (obj->variantType) {
14613 + switch (obj->variant_type) {
14614 case YAFFS_OBJECT_TYPE_FILE:
14615 return DT_REG;
14616 break;
14617 @@ -6960,18 +4849,18 @@ unsigned yaffs_GetObjectType(yaffs_Objec
14618 }
14619 }
14620
14621 -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
14622 +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj)
14623 {
14624 - obj = yaffs_GetEquivalentObject(obj);
14625 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
14626 - return yaffs_CloneString(obj->variant.symLinkVariant.alias);
14627 + obj = yaffs_get_equivalent_obj(obj);
14628 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
14629 + return yaffs_clone_str(obj->variant.symlink_variant.alias);
14630 else
14631 - return yaffs_CloneString(_Y(""));
14632 + return yaffs_clone_str(_Y(""));
14633 }
14634
14635 #ifndef CONFIG_YAFFS_WINCE
14636
14637 -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
14638 +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr)
14639 {
14640 unsigned int valid = attr->ia_valid;
14641
14642 @@ -6990,14 +4879,14 @@ int yaffs_SetAttributes(yaffs_Object *ob
14643 obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
14644
14645 if (valid & ATTR_SIZE)
14646 - yaffs_ResizeFile(obj, attr->ia_size);
14647 + yaffs_resize_file(obj, attr->ia_size);
14648
14649 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
14650 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
14651
14652 return YAFFS_OK;
14653
14654 }
14655 -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
14656 +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr)
14657 {
14658 unsigned int valid = 0;
14659
14660 @@ -7015,7 +4904,7 @@ int yaffs_GetAttributes(yaffs_Object *ob
14661 Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
14662 valid |= ATTR_MTIME;
14663
14664 - attr->ia_size = yaffs_GetFileSize(obj);
14665 + attr->ia_size = yaffs_get_file_size(obj);
14666 valid |= ATTR_SIZE;
14667
14668 attr->ia_valid = valid;
14669 @@ -7025,20 +4914,137 @@ int yaffs_GetAttributes(yaffs_Object *ob
14670
14671 #endif
14672
14673 +
14674 +static int yaffs_do_xattrib_mod(yaffs_obj_t *obj, int set, const YCHAR *name, const void *value, int size, int flags)
14675 +{
14676 + yaffs_xattr_mod xmod;
14677 +
14678 + int result;
14679 +
14680 + xmod.set = set;
14681 + xmod.name = name;
14682 + xmod.data = value;
14683 + xmod.size = size;
14684 + xmod.flags = flags;
14685 + xmod.result = -ENOSPC;
14686 +
14687 + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
14688 +
14689 + if(result > 0)
14690 + return xmod.result;
14691 + else
14692 + return -ENOSPC;
14693 +}
14694 +
14695 +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod)
14696 +{
14697 + int retval = 0;
14698 + int x_offs = sizeof(yaffs_obj_header);
14699 + yaffs_dev_t *dev = obj->my_dev;
14700 + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
14701 +
14702 + char * x_buffer = buffer + x_offs;
14703 +
14704 + if(xmod->set)
14705 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
14706 + else
14707 + retval = nval_del(x_buffer, x_size, xmod->name);
14708 +
14709 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
14710 + obj->xattr_known = 1;
14711 +
14712 + xmod->result = retval;
14713 +
14714 + return retval;
14715 +}
14716 +
14717 +static int yaffs_do_xattrib_fetch(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
14718 +{
14719 + char *buffer = NULL;
14720 + int result;
14721 + yaffs_ext_tags tags;
14722 + yaffs_dev_t *dev = obj->my_dev;
14723 + int x_offs = sizeof(yaffs_obj_header);
14724 + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
14725 +
14726 + char * x_buffer;
14727 +
14728 + int retval = 0;
14729 +
14730 + if(obj->hdr_chunk < 1)
14731 + return -ENODATA;
14732 +
14733 + /* If we know that the object has no xattribs then don't do all the
14734 + * reading and parsing.
14735 + */
14736 + if(obj->xattr_known && !obj->has_xattr){
14737 + if(name)
14738 + return -ENODATA;
14739 + else
14740 + return 0;
14741 + }
14742 +
14743 + buffer = (char *) yaffs_get_temp_buffer(dev, __LINE__);
14744 + if(!buffer)
14745 + return -ENOMEM;
14746 +
14747 + result = yaffs_rd_chunk_tags_nand(dev,obj->hdr_chunk, (__u8 *)buffer, &tags);
14748 +
14749 + if(result != YAFFS_OK)
14750 + retval = -ENOENT;
14751 + else{
14752 + x_buffer = buffer + x_offs;
14753 +
14754 + if (!obj->xattr_known){
14755 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
14756 + obj->xattr_known = 1;
14757 + }
14758 +
14759 + if(name)
14760 + retval = nval_get(x_buffer, x_size, name, value, size);
14761 + else
14762 + retval = nval_list(x_buffer, x_size, value,size);
14763 + }
14764 + yaffs_release_temp_buffer(dev,(__u8 *)buffer,__LINE__);
14765 + return retval;
14766 +}
14767 +
14768 +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags)
14769 +{
14770 + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
14771 +}
14772 +
14773 +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name)
14774 +{
14775 + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
14776 +}
14777 +
14778 +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
14779 +{
14780 + return yaffs_do_xattrib_fetch(obj, name, value, size);
14781 +}
14782 +
14783 +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size)
14784 +{
14785 + return yaffs_do_xattrib_fetch(obj, NULL, buffer,size);
14786 +}
14787 +
14788 +
14789 +
14790 #if 0
14791 -int yaffs_DumpObject(yaffs_Object *obj)
14792 +int yaffs_dump_obj(yaffs_obj_t *obj)
14793 {
14794 YCHAR name[257];
14795
14796 - yaffs_GetObjectName(obj, name, 256);
14797 + yaffs_get_obj_name(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
14798
14799 T(YAFFS_TRACE_ALWAYS,
14800 (TSTR
14801 ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
14802 " chunk %d type %d size %d\n"
14803 - TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
14804 - obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
14805 - yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
14806 + TENDSTR), obj->obj_id, yaffs_get_obj_inode(obj), name,
14807 + obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdr_chunk,
14808 + yaffs_get_obj_type(obj), yaffs_get_obj_length(obj)));
14809
14810 return YAFFS_OK;
14811 }
14812 @@ -7046,72 +5052,74 @@ int yaffs_DumpObject(yaffs_Object *obj)
14813
14814 /*---------------------------- Initialisation code -------------------------------------- */
14815
14816 -static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
14817 +static int yaffs_cehck_dev_fns(const yaffs_dev_t *dev)
14818 {
14819
14820 /* Common functions, gotta have */
14821 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
14822 + if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
14823 return 0;
14824
14825 #ifdef CONFIG_YAFFS_YAFFS2
14826
14827 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
14828 - if (dev->writeChunkWithTagsToNAND &&
14829 - dev->readChunkWithTagsFromNAND &&
14830 - !dev->writeChunkToNAND &&
14831 - !dev->readChunkFromNAND &&
14832 - dev->markNANDBlockBad && dev->queryNANDBlock)
14833 + if (dev->param.write_chunk_tags_fn &&
14834 + dev->param.read_chunk_tags_fn &&
14835 + !dev->param.write_chunk_fn &&
14836 + !dev->param.read_chunk_fn &&
14837 + dev->param.bad_block_fn &&
14838 + dev->param.query_block_fn)
14839 return 1;
14840 #endif
14841
14842 /* Can use the "spare" style interface for yaffs1 */
14843 - if (!dev->isYaffs2 &&
14844 - !dev->writeChunkWithTagsToNAND &&
14845 - !dev->readChunkWithTagsFromNAND &&
14846 - dev->writeChunkToNAND &&
14847 - dev->readChunkFromNAND &&
14848 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
14849 + if (!dev->param.is_yaffs2 &&
14850 + !dev->param.write_chunk_tags_fn &&
14851 + !dev->param.read_chunk_tags_fn &&
14852 + dev->param.write_chunk_fn &&
14853 + dev->param.read_chunk_fn &&
14854 + !dev->param.bad_block_fn &&
14855 + !dev->param.query_block_fn)
14856 return 1;
14857
14858 - return 0; /* bad */
14859 + return 0; /* bad */
14860 }
14861
14862
14863 -static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
14864 +static int yaffs_create_initial_dir(yaffs_dev_t *dev)
14865 {
14866 /* Initialise the unlinked, deleted, root and lost and found directories */
14867
14868 - dev->lostNFoundDir = dev->rootDir = NULL;
14869 - dev->unlinkedDir = dev->deletedDir = NULL;
14870 + dev->lost_n_found = dev->root_dir = NULL;
14871 + dev->unlinked_dir = dev->del_dir = NULL;
14872
14873 - dev->unlinkedDir =
14874 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
14875 + dev->unlinked_dir =
14876 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
14877
14878 - dev->deletedDir =
14879 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
14880 + dev->del_dir =
14881 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
14882
14883 - dev->rootDir =
14884 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
14885 + dev->root_dir =
14886 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
14887 YAFFS_ROOT_MODE | S_IFDIR);
14888 - dev->lostNFoundDir =
14889 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
14890 + dev->lost_n_found =
14891 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
14892 YAFFS_LOSTNFOUND_MODE | S_IFDIR);
14893
14894 - if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) {
14895 - yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
14896 + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir && dev->del_dir) {
14897 + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
14898 return YAFFS_OK;
14899 }
14900
14901 return YAFFS_FAIL;
14902 }
14903
14904 -int yaffs_GutsInitialise(yaffs_Device *dev)
14905 +int yaffs_guts_initialise(yaffs_dev_t *dev)
14906 {
14907 int init_failed = 0;
14908 unsigned x;
14909 int bits;
14910
14911 - T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
14912 + T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR)));
14913
14914 /* Check stuff that must be set */
14915
14916 @@ -7120,52 +5128,52 @@ int yaffs_GutsInitialise(yaffs_Device *d
14917 return YAFFS_FAIL;
14918 }
14919
14920 - dev->internalStartBlock = dev->startBlock;
14921 - dev->internalEndBlock = dev->endBlock;
14922 - dev->blockOffset = 0;
14923 - dev->chunkOffset = 0;
14924 - dev->nFreeChunks = 0;
14925 -
14926 - dev->gcBlock = -1;
14927 -
14928 - if (dev->startBlock == 0) {
14929 - dev->internalStartBlock = dev->startBlock + 1;
14930 - dev->internalEndBlock = dev->endBlock + 1;
14931 - dev->blockOffset = 1;
14932 - dev->chunkOffset = dev->nChunksPerBlock;
14933 + dev->internal_start_block = dev->param.start_block;
14934 + dev->internal_end_block = dev->param.end_block;
14935 + dev->block_offset = 0;
14936 + dev->chunk_offset = 0;
14937 + dev->n_free_chunks = 0;
14938 +
14939 + dev->gc_block = 0;
14940 +
14941 + if (dev->param.start_block == 0) {
14942 + dev->internal_start_block = dev->param.start_block + 1;
14943 + dev->internal_end_block = dev->param.end_block + 1;
14944 + dev->block_offset = 1;
14945 + dev->chunk_offset = dev->param.chunks_per_block;
14946 }
14947
14948 /* Check geometry parameters. */
14949
14950 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14951 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14952 - (dev->inbandTags && !dev->isYaffs2) ||
14953 - dev->nChunksPerBlock < 2 ||
14954 - dev->nReservedBlocks < 2 ||
14955 - dev->internalStartBlock <= 0 ||
14956 - dev->internalEndBlock <= 0 ||
14957 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14958 + if ((!dev->param.inband_tags && dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 1024) ||
14959 + (!dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 512) ||
14960 + (dev->param.inband_tags && !dev->param.is_yaffs2) ||
14961 + dev->param.chunks_per_block < 2 ||
14962 + dev->param.n_reserved_blocks < 2 ||
14963 + dev->internal_start_block <= 0 ||
14964 + dev->internal_end_block <= 0 ||
14965 + dev->internal_end_block <= (dev->internal_start_block + dev->param.n_reserved_blocks + 2)) { /* otherwise it is too small */
14966 T(YAFFS_TRACE_ALWAYS,
14967 (TSTR
14968 - ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14969 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14970 + ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d "
14971 + TENDSTR), dev->param.total_bytes_per_chunk, dev->param.is_yaffs2 ? "2" : "", dev->param.inband_tags));
14972 return YAFFS_FAIL;
14973 }
14974
14975 - if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
14976 + if (yaffs_init_nand(dev) != YAFFS_OK) {
14977 T(YAFFS_TRACE_ALWAYS,
14978 (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
14979 return YAFFS_FAIL;
14980 }
14981
14982 /* Sort out space for inband tags, if required */
14983 - if (dev->inbandTags)
14984 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
14985 + if (dev->param.inband_tags)
14986 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk - sizeof(yaffs_PackedTags2TagsPart);
14987 else
14988 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
14989 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
14990
14991 /* Got the right mix of functions? */
14992 - if (!yaffs_CheckDevFunctions(dev)) {
14993 + if (!yaffs_cehck_dev_fns(dev)) {
14994 /* Function missing */
14995 T(YAFFS_TRACE_ALWAYS,
14996 (TSTR
14997 @@ -7175,13 +5183,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
14998 }
14999
15000 /* This is really a compilation check. */
15001 - if (!yaffs_CheckStructures()) {
15002 + if (!yaffs_check_structures()) {
15003 T(YAFFS_TRACE_ALWAYS,
15004 - (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
15005 + (TSTR("yaffs_check_structures failed\n" TENDSTR)));
15006 return YAFFS_FAIL;
15007 }
15008
15009 - if (dev->isMounted) {
15010 + if (dev->is_mounted) {
15011 T(YAFFS_TRACE_ALWAYS,
15012 (TSTR("yaffs: device already mounted\n" TENDSTR)));
15013 return YAFFS_FAIL;
15014 @@ -7189,59 +5197,62 @@ int yaffs_GutsInitialise(yaffs_Device *d
15015
15016 /* Finished with most checks. One or two more checks happen later on too. */
15017
15018 - dev->isMounted = 1;
15019 + dev->is_mounted = 1;
15020
15021 /* OK now calculate a few things for the device */
15022
15023 /*
15024 * Calculate all the chunk size manipulation numbers:
15025 */
15026 - x = dev->nDataBytesPerChunk;
15027 - /* We always use dev->chunkShift and dev->chunkDiv */
15028 - dev->chunkShift = Shifts(x);
15029 - x >>= dev->chunkShift;
15030 - dev->chunkDiv = x;
15031 - /* We only use chunk mask if chunkDiv is 1 */
15032 - dev->chunkMask = (1<<dev->chunkShift) - 1;
15033 + x = dev->data_bytes_per_chunk;
15034 + /* We always use dev->chunk_shift and dev->chunk_div */
15035 + dev->chunk_shift = Shifts(x);
15036 + x >>= dev->chunk_shift;
15037 + dev->chunk_div = x;
15038 + /* We only use chunk mask if chunk_div is 1 */
15039 + dev->chunk_mask = (1<<dev->chunk_shift) - 1;
15040
15041 /*
15042 - * Calculate chunkGroupBits.
15043 - * We need to find the next power of 2 > than internalEndBlock
15044 + * Calculate chunk_grp_bits.
15045 + * We need to find the next power of 2 > than internal_end_block
15046 */
15047
15048 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
15049 + x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
15050
15051 bits = ShiftsGE(x);
15052
15053 /* Set up tnode width if wide tnodes are enabled. */
15054 - if (!dev->wideTnodesDisabled) {
15055 + if (!dev->param.wide_tnodes_disabled) {
15056 /* bits must be even so that we end up with 32-bit words */
15057 if (bits & 1)
15058 bits++;
15059 if (bits < 16)
15060 - dev->tnodeWidth = 16;
15061 + dev->tnode_width = 16;
15062 else
15063 - dev->tnodeWidth = bits;
15064 + dev->tnode_width = bits;
15065 } else
15066 - dev->tnodeWidth = 16;
15067 + dev->tnode_width = 16;
15068
15069 - dev->tnodeMask = (1<<dev->tnodeWidth)-1;
15070 + dev->tnode_mask = (1<<dev->tnode_width)-1;
15071
15072 /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
15073 * so if the bitwidth of the
15074 * chunk range we're using is greater than 16 we need
15075 - * to figure out chunk shift and chunkGroupSize
15076 + * to figure out chunk shift and chunk_grp_size
15077 */
15078
15079 - if (bits <= dev->tnodeWidth)
15080 - dev->chunkGroupBits = 0;
15081 + if (bits <= dev->tnode_width)
15082 + dev->chunk_grp_bits = 0;
15083 else
15084 - dev->chunkGroupBits = bits - dev->tnodeWidth;
15085 + dev->chunk_grp_bits = bits - dev->tnode_width;
15086
15087 + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8;
15088 + if(dev->tnode_size < sizeof(yaffs_tnode_t))
15089 + dev->tnode_size = sizeof(yaffs_tnode_t);
15090
15091 - dev->chunkGroupSize = 1 << dev->chunkGroupBits;
15092 + dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
15093
15094 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
15095 + if (dev->param.chunks_per_block < dev->chunk_grp_size) {
15096 /* We have a problem because the soft delete won't work if
15097 * the chunk group size > chunks per block.
15098 * This can be remedied by using larger "virtual blocks".
15099 @@ -7255,85 +5266,89 @@ int yaffs_GutsInitialise(yaffs_Device *d
15100 /* OK, we've finished verifying the device, lets continue with initialisation */
15101
15102 /* More device initialisation */
15103 - dev->garbageCollections = 0;
15104 - dev->passiveGarbageCollections = 0;
15105 - dev->currentDirtyChecker = 0;
15106 - dev->bufferedBlock = -1;
15107 - dev->doingBufferedBlockRewrite = 0;
15108 - dev->nDeletedFiles = 0;
15109 - dev->nBackgroundDeletions = 0;
15110 - dev->nUnlinkedFiles = 0;
15111 - dev->eccFixed = 0;
15112 - dev->eccUnfixed = 0;
15113 - dev->tagsEccFixed = 0;
15114 - dev->tagsEccUnfixed = 0;
15115 - dev->nErasureFailures = 0;
15116 - dev->nErasedBlocks = 0;
15117 - dev->isDoingGC = 0;
15118 - dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
15119 + dev->all_gcs = 0;
15120 + dev->passive_gc_count = 0;
15121 + dev->oldest_dirty_gc_count = 0;
15122 + dev->bg_gcs = 0;
15123 + dev->gc_block_finder = 0;
15124 + dev->buffered_block = -1;
15125 + dev->doing_buffered_block_rewrite = 0;
15126 + dev->n_deleted_files = 0;
15127 + dev->n_bg_deletions = 0;
15128 + dev->n_unlinked_files = 0;
15129 + dev->n_ecc_fixed = 0;
15130 + dev->n_ecc_unfixed = 0;
15131 + dev->n_tags_ecc_fixed = 0;
15132 + dev->n_tags_ecc_unfixed = 0;
15133 + dev->n_erase_failures = 0;
15134 + dev->n_erased_blocks = 0;
15135 + dev->gc_disable= 0;
15136 + dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */
15137 + YINIT_LIST_HEAD(&dev->dirty_dirs);
15138 + dev->oldest_dirty_seq = 0;
15139 + dev->oldest_dirty_block = 0;
15140
15141 /* Initialise temporary buffers and caches. */
15142 - if (!yaffs_InitialiseTempBuffers(dev))
15143 + if (!yaffs_init_tmp_buffers(dev))
15144 init_failed = 1;
15145
15146 - dev->srCache = NULL;
15147 - dev->gcCleanupList = NULL;
15148 + dev->cache = NULL;
15149 + dev->gc_cleanup_list = NULL;
15150
15151
15152 if (!init_failed &&
15153 - dev->nShortOpCaches > 0) {
15154 + dev->param.n_caches > 0) {
15155 int i;
15156 void *buf;
15157 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
15158 + int cacheBytes = dev->param.n_caches * sizeof(yaffs_cache_t);
15159
15160 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
15161 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
15162 + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
15163 + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
15164
15165 - dev->srCache = YMALLOC(srCacheBytes);
15166 + dev->cache = YMALLOC(cacheBytes);
15167
15168 - buf = (__u8 *) dev->srCache;
15169 + buf = (__u8 *) dev->cache;
15170
15171 - if (dev->srCache)
15172 - memset(dev->srCache, 0, srCacheBytes);
15173 + if (dev->cache)
15174 + memset(dev->cache, 0, cacheBytes);
15175
15176 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
15177 - dev->srCache[i].object = NULL;
15178 - dev->srCache[i].lastUse = 0;
15179 - dev->srCache[i].dirty = 0;
15180 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
15181 + for (i = 0; i < dev->param.n_caches && buf; i++) {
15182 + dev->cache[i].object = NULL;
15183 + dev->cache[i].last_use = 0;
15184 + dev->cache[i].dirty = 0;
15185 + dev->cache[i].data = buf = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
15186 }
15187 if (!buf)
15188 init_failed = 1;
15189
15190 - dev->srLastUse = 0;
15191 + dev->cache_last_use = 0;
15192 }
15193
15194 - dev->cacheHits = 0;
15195 + dev->cache_hits = 0;
15196
15197 if (!init_failed) {
15198 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
15199 - if (!dev->gcCleanupList)
15200 + dev->gc_cleanup_list = YMALLOC(dev->param.chunks_per_block * sizeof(__u32));
15201 + if (!dev->gc_cleanup_list)
15202 init_failed = 1;
15203 }
15204
15205 - if (dev->isYaffs2)
15206 - dev->useHeaderFileSize = 1;
15207 + if (dev->param.is_yaffs2)
15208 + dev->param.use_header_file_size = 1;
15209
15210 - if (!init_failed && !yaffs_InitialiseBlocks(dev))
15211 + if (!init_failed && !yaffs_init_blocks(dev))
15212 init_failed = 1;
15213
15214 - yaffs_InitialiseTnodes(dev);
15215 - yaffs_InitialiseObjects(dev);
15216 + yaffs_init_tnodes_and_objs(dev);
15217
15218 - if (!init_failed && !yaffs_CreateInitialDirectories(dev))
15219 + if (!init_failed && !yaffs_create_initial_dir(dev))
15220 init_failed = 1;
15221
15222
15223 if (!init_failed) {
15224 /* Now scan the flash. */
15225 - if (dev->isYaffs2) {
15226 - if (yaffs_CheckpointRestore(dev)) {
15227 - yaffs_CheckObjectDetailsLoaded(dev->rootDir);
15228 + if (dev->param.is_yaffs2) {
15229 + if (yaffs2_checkpt_restore(dev)) {
15230 + yaffs_check_obj_details_loaded(dev->root_dir);
15231 T(YAFFS_TRACE_ALWAYS,
15232 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
15233 } else {
15234 @@ -7341,128 +5356,129 @@ int yaffs_GutsInitialise(yaffs_Device *d
15235 /* Clean up the mess caused by an aborted checkpoint load
15236 * and scan backwards.
15237 */
15238 - yaffs_DeinitialiseBlocks(dev);
15239 - yaffs_DeinitialiseTnodes(dev);
15240 - yaffs_DeinitialiseObjects(dev);
15241 + yaffs_deinit_blocks(dev);
15242
15243 + yaffs_deinit_tnodes_and_objs(dev);
15244
15245 - dev->nErasedBlocks = 0;
15246 - dev->nFreeChunks = 0;
15247 - dev->allocationBlock = -1;
15248 - dev->allocationPage = -1;
15249 - dev->nDeletedFiles = 0;
15250 - dev->nUnlinkedFiles = 0;
15251 - dev->nBackgroundDeletions = 0;
15252 - dev->oldestDirtySequence = 0;
15253 + dev->n_erased_blocks = 0;
15254 + dev->n_free_chunks = 0;
15255 + dev->alloc_block = -1;
15256 + dev->alloc_page = -1;
15257 + dev->n_deleted_files = 0;
15258 + dev->n_unlinked_files = 0;
15259 + dev->n_bg_deletions = 0;
15260
15261 - if (!init_failed && !yaffs_InitialiseBlocks(dev))
15262 + if (!init_failed && !yaffs_init_blocks(dev))
15263 init_failed = 1;
15264
15265 - yaffs_InitialiseTnodes(dev);
15266 - yaffs_InitialiseObjects(dev);
15267 + yaffs_init_tnodes_and_objs(dev);
15268
15269 - if (!init_failed && !yaffs_CreateInitialDirectories(dev))
15270 + if (!init_failed && !yaffs_create_initial_dir(dev))
15271 init_failed = 1;
15272
15273 - if (!init_failed && !yaffs_ScanBackwards(dev))
15274 + if (!init_failed && !yaffs2_scan_backwards(dev))
15275 init_failed = 1;
15276 }
15277 - } else if (!yaffs_Scan(dev))
15278 + } else if (!yaffs1_scan(dev))
15279 init_failed = 1;
15280
15281 - yaffs_StripDeletedObjects(dev);
15282 + yaffs_strip_deleted_objs(dev);
15283 + yaffs_fix_hanging_objs(dev);
15284 + if(dev->param.empty_lost_n_found)
15285 + yaffs_empty_l_n_f(dev);
15286 }
15287
15288 if (init_failed) {
15289 /* Clean up the mess */
15290 T(YAFFS_TRACE_TRACING,
15291 - (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
15292 + (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR)));
15293
15294 - yaffs_Deinitialise(dev);
15295 + yaffs_deinitialise(dev);
15296 return YAFFS_FAIL;
15297 }
15298
15299 /* Zero out stats */
15300 - dev->nPageReads = 0;
15301 - dev->nPageWrites = 0;
15302 - dev->nBlockErasures = 0;
15303 - dev->nGCCopies = 0;
15304 - dev->nRetriedWrites = 0;
15305 -
15306 - dev->nRetiredBlocks = 0;
15307 -
15308 - yaffs_VerifyFreeChunks(dev);
15309 - yaffs_VerifyBlocks(dev);
15310 -
15311 + dev->n_page_reads = 0;
15312 + dev->n_page_writes = 0;
15313 + dev->n_erasures = 0;
15314 + dev->n_gc_copies = 0;
15315 + dev->n_retired_writes = 0;
15316 +
15317 + dev->n_retired_blocks = 0;
15318 +
15319 + yaffs_verify_free_chunks(dev);
15320 + yaffs_verify_blocks(dev);
15321 +
15322 + /* Clean up any aborted checkpoint data */
15323 + if(!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
15324 + yaffs2_checkpt_invalidate(dev);
15325
15326 T(YAFFS_TRACE_TRACING,
15327 - (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
15328 + (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR)));
15329 return YAFFS_OK;
15330
15331 }
15332
15333 -void yaffs_Deinitialise(yaffs_Device *dev)
15334 +void yaffs_deinitialise(yaffs_dev_t *dev)
15335 {
15336 - if (dev->isMounted) {
15337 + if (dev->is_mounted) {
15338 int i;
15339
15340 - yaffs_DeinitialiseBlocks(dev);
15341 - yaffs_DeinitialiseTnodes(dev);
15342 - yaffs_DeinitialiseObjects(dev);
15343 - if (dev->nShortOpCaches > 0 &&
15344 - dev->srCache) {
15345 + yaffs_deinit_blocks(dev);
15346 + yaffs_deinit_tnodes_and_objs(dev);
15347 + if (dev->param.n_caches > 0 &&
15348 + dev->cache) {
15349
15350 - for (i = 0; i < dev->nShortOpCaches; i++) {
15351 - if (dev->srCache[i].data)
15352 - YFREE(dev->srCache[i].data);
15353 - dev->srCache[i].data = NULL;
15354 + for (i = 0; i < dev->param.n_caches; i++) {
15355 + if (dev->cache[i].data)
15356 + YFREE(dev->cache[i].data);
15357 + dev->cache[i].data = NULL;
15358 }
15359
15360 - YFREE(dev->srCache);
15361 - dev->srCache = NULL;
15362 + YFREE(dev->cache);
15363 + dev->cache = NULL;
15364 }
15365
15366 - YFREE(dev->gcCleanupList);
15367 + YFREE(dev->gc_cleanup_list);
15368
15369 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
15370 - YFREE(dev->tempBuffer[i].buffer);
15371 + YFREE(dev->temp_buffer[i].buffer);
15372
15373 - dev->isMounted = 0;
15374 + dev->is_mounted = 0;
15375
15376 - if (dev->deinitialiseNAND)
15377 - dev->deinitialiseNAND(dev);
15378 + if (dev->param.deinitialise_flash_fn)
15379 + dev->param.deinitialise_flash_fn(dev);
15380 }
15381 }
15382
15383 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
15384 +int yaffs_count_free_chunks(yaffs_dev_t *dev)
15385 {
15386 - int nFree;
15387 + int nFree=0;
15388 int b;
15389
15390 - yaffs_BlockInfo *blk;
15391 -
15392 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
15393 - b++) {
15394 - blk = yaffs_GetBlockInfo(dev, b);
15395 + yaffs_block_info_t *blk;
15396
15397 - switch (blk->blockState) {
15398 + blk = dev->block_info;
15399 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
15400 + switch (blk->block_state) {
15401 case YAFFS_BLOCK_STATE_EMPTY:
15402 case YAFFS_BLOCK_STATE_ALLOCATING:
15403 case YAFFS_BLOCK_STATE_COLLECTING:
15404 case YAFFS_BLOCK_STATE_FULL:
15405 nFree +=
15406 - (dev->nChunksPerBlock - blk->pagesInUse +
15407 - blk->softDeletions);
15408 + (dev->param.chunks_per_block - blk->pages_in_use +
15409 + blk->soft_del_pages);
15410 break;
15411 default:
15412 break;
15413 }
15414 + blk++;
15415 }
15416
15417 return nFree;
15418 }
15419
15420 -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
15421 +int yaffs_get_n_free_chunks(yaffs_dev_t *dev)
15422 {
15423 /* This is what we report to the outside world */
15424
15425 @@ -7472,30 +5488,28 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
15426 int i;
15427
15428 #if 1
15429 - nFree = dev->nFreeChunks;
15430 + nFree = dev->n_free_chunks;
15431 #else
15432 - nFree = yaffs_CountFreeChunks(dev);
15433 + nFree = yaffs_count_free_chunks(dev);
15434 #endif
15435
15436 - nFree += dev->nDeletedFiles;
15437 + nFree += dev->n_deleted_files;
15438
15439 /* Now count the number of dirty chunks in the cache and subtract those */
15440
15441 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
15442 - if (dev->srCache[i].dirty)
15443 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.n_caches; i++) {
15444 + if (dev->cache[i].dirty)
15445 nDirtyCacheChunks++;
15446 }
15447
15448 nFree -= nDirtyCacheChunks;
15449
15450 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
15451 + nFree -= ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
15452
15453 /* Now we figure out how much to reserve for the checkpoint and report that... */
15454 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
15455 - if (blocksForCheckpoint < 0)
15456 - blocksForCheckpoint = 0;
15457 + blocksForCheckpoint = yaffs_calc_checkpt_blocks_required(dev);
15458
15459 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
15460 + nFree -= (blocksForCheckpoint * dev->param.chunks_per_block);
15461
15462 if (nFree < 0)
15463 nFree = 0;
15464 @@ -7504,49 +5518,27 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
15465
15466 }
15467
15468 -static int yaffs_freeVerificationFailures;
15469 -
15470 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
15471 -{
15472 - int counted;
15473 - int difference;
15474 -
15475 - if (yaffs_SkipVerification(dev))
15476 - return;
15477 -
15478 - counted = yaffs_CountFreeChunks(dev);
15479 -
15480 - difference = dev->nFreeChunks - counted;
15481 -
15482 - if (difference) {
15483 - T(YAFFS_TRACE_ALWAYS,
15484 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
15485 - dev->nFreeChunks, counted, difference));
15486 - yaffs_freeVerificationFailures++;
15487 - }
15488 -}
15489
15490 /*---------------------------------------- YAFFS test code ----------------------*/
15491
15492 -#define yaffs_CheckStruct(structure, syze, name) \
15493 +#define yaffs_check_struct(structure, syze, name) \
15494 do { \
15495 if (sizeof(structure) != syze) { \
15496 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
15497 - name, syze, sizeof(structure))); \
15498 + name, syze, (int) sizeof(structure))); \
15499 return YAFFS_FAIL; \
15500 } \
15501 } while (0)
15502
15503 -static int yaffs_CheckStructures(void)
15504 +static int yaffs_check_structures(void)
15505 {
15506 -/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
15507 -/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
15508 -/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
15509 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
15510 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
15511 -#endif
15512 +/* yaffs_check_struct(yaffs_tags_t,8,"yaffs_tags_t"); */
15513 +/* yaffs_check_struct(yaffs_tags_union_t,8,"yaffs_tags_union_t"); */
15514 +/* yaffs_check_struct(yaffs_spare,16,"yaffs_spare"); */
15515 +/* yaffs_check_struct(yaffs_tnode_t, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_tnode_t"); */
15516 +
15517 #ifndef CONFIG_YAFFS_WINCE
15518 - yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
15519 + yaffs_check_struct(yaffs_obj_header, 512, "yaffs_obj_header");
15520 #endif
15521 return YAFFS_OK;
15522 }
15523 --- a/fs/yaffs2/yaffs_guts.h
15524 +++ b/fs/yaffs2/yaffs_guts.h
15525 @@ -1,7 +1,7 @@
15526 /*
15527 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15528 *
15529 - * Copyright (C) 2002-2007 Aleph One Ltd.
15530 + * Copyright (C) 2002-2010 Aleph One Ltd.
15531 * for Toby Churchill Ltd and Brightstar Engineering
15532 *
15533 * Created by Charles Manning <charles@aleph1.co.uk>
15534 @@ -16,8 +16,9 @@
15535 #ifndef __YAFFS_GUTS_H__
15536 #define __YAFFS_GUTS_H__
15537
15538 -#include "devextras.h"
15539 #include "yportenv.h"
15540 +#include "devextras.h"
15541 +#include "yaffs_list.h"
15542
15543 #define YAFFS_OK 1
15544 #define YAFFS_FAIL 0
15545 @@ -52,7 +53,6 @@
15546
15547 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
15548
15549 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
15550
15551 #define YAFFS_ALLOCATION_NOBJECTS 100
15552 #define YAFFS_ALLOCATION_NTNODES 100
15553 @@ -62,8 +62,9 @@
15554
15555
15556 #define YAFFS_OBJECT_SPACE 0x40000
15557 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
15558
15559 -#define YAFFS_CHECKPOINT_VERSION 3
15560 +#define YAFFS_CHECKPOINT_VERSION 4
15561
15562 #ifdef CONFIG_YAFFS_UNICODE
15563 #define YAFFS_MAX_NAME_LENGTH 127
15564 @@ -81,12 +82,11 @@
15565 #define YAFFS_OBJECTID_UNLINKED 3
15566 #define YAFFS_OBJECTID_DELETED 4
15567
15568 -/* Sseudo object ids for checkpointing */
15569 +/* Pseudo object ids for checkpointing */
15570 #define YAFFS_OBJECTID_SB_HEADER 0x10
15571 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
15572 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
15573
15574 -/* */
15575
15576 #define YAFFS_MAX_SHORT_OP_CACHES 20
15577
15578 @@ -113,18 +113,14 @@
15579
15580 /* ChunkCache is used for short read/write operations.*/
15581 typedef struct {
15582 - struct yaffs_ObjectStruct *object;
15583 - int chunkId;
15584 - int lastUse;
15585 + struct yaffs_obj_s *object;
15586 + int chunk_id;
15587 + int last_use;
15588 int dirty;
15589 - int nBytes; /* Only valid if the cache is dirty */
15590 + int n_bytes; /* Only valid if the cache is dirty */
15591 int locked; /* Can't push out or flush while locked. */
15592 -#ifdef CONFIG_YAFFS_YAFFS2
15593 __u8 *data;
15594 -#else
15595 - __u8 data[YAFFS_BYTES_PER_CHUNK];
15596 -#endif
15597 -} yaffs_ChunkCache;
15598 +} yaffs_cache_t;
15599
15600
15601
15602 @@ -135,18 +131,18 @@ typedef struct {
15603
15604 #ifndef CONFIG_YAFFS_NO_YAFFS1
15605 typedef struct {
15606 - unsigned chunkId:20;
15607 - unsigned serialNumber:2;
15608 - unsigned byteCountLSB:10;
15609 - unsigned objectId:18;
15610 + unsigned chunk_id:20;
15611 + unsigned serial_number:2;
15612 + unsigned n_bytes_lsb:10;
15613 + unsigned obj_id:18;
15614 unsigned ecc:12;
15615 - unsigned byteCountMSB:2;
15616 -} yaffs_Tags;
15617 + unsigned n_bytes_msb:2;
15618 +} yaffs_tags_t;
15619
15620 typedef union {
15621 - yaffs_Tags asTags;
15622 - __u8 asBytes[8];
15623 -} yaffs_TagsUnion;
15624 + yaffs_tags_t as_tags;
15625 + __u8 as_bytes[8];
15626 +} yaffs_tags_union_t;
15627
15628 #endif
15629
15630 @@ -157,7 +153,7 @@ typedef enum {
15631 YAFFS_ECC_RESULT_NO_ERROR,
15632 YAFFS_ECC_RESULT_FIXED,
15633 YAFFS_ECC_RESULT_UNFIXED
15634 -} yaffs_ECCResult;
15635 +} yaffs_ecc_result;
15636
15637 typedef enum {
15638 YAFFS_OBJECT_TYPE_UNKNOWN,
15639 @@ -166,64 +162,64 @@ typedef enum {
15640 YAFFS_OBJECT_TYPE_DIRECTORY,
15641 YAFFS_OBJECT_TYPE_HARDLINK,
15642 YAFFS_OBJECT_TYPE_SPECIAL
15643 -} yaffs_ObjectType;
15644 +} yaffs_obj_type;
15645
15646 #define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
15647
15648 typedef struct {
15649
15650 - unsigned validMarker0;
15651 - unsigned chunkUsed; /* Status of the chunk: used or unused */
15652 - unsigned objectId; /* If 0 then this is not part of an object (unused) */
15653 - unsigned chunkId; /* If 0 then this is a header, else a data chunk */
15654 - unsigned byteCount; /* Only valid for data chunks */
15655 + unsigned validity1;
15656 + unsigned chunk_used; /* Status of the chunk: used or unused */
15657 + unsigned obj_id; /* If 0 then this is not part of an object (unused) */
15658 + unsigned chunk_id; /* If 0 then this is a header, else a data chunk */
15659 + unsigned n_bytes; /* Only valid for data chunks */
15660
15661 /* The following stuff only has meaning when we read */
15662 - yaffs_ECCResult eccResult;
15663 - unsigned blockBad;
15664 + yaffs_ecc_result ecc_result;
15665 + unsigned block_bad;
15666
15667 /* YAFFS 1 stuff */
15668 - unsigned chunkDeleted; /* The chunk is marked deleted */
15669 - unsigned serialNumber; /* Yaffs1 2-bit serial number */
15670 + unsigned is_deleted; /* The chunk is marked deleted */
15671 + unsigned serial_number; /* Yaffs1 2-bit serial number */
15672
15673 /* YAFFS2 stuff */
15674 - unsigned sequenceNumber; /* The sequence number of this block */
15675 + unsigned seq_number; /* The sequence number of this block */
15676
15677 /* Extra info if this is an object header (YAFFS2 only) */
15678
15679 - unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
15680 - unsigned extraParentObjectId; /* The parent object */
15681 - unsigned extraIsShrinkHeader; /* Is it a shrink header? */
15682 - unsigned extraShadows; /* Does this shadow another object? */
15683 + unsigned extra_available; /* There is extra info available if this is not zero */
15684 + unsigned extra_parent_id; /* The parent object */
15685 + unsigned extra_is_shrink; /* Is it a shrink header? */
15686 + unsigned extra_shadows; /* Does this shadow another object? */
15687
15688 - yaffs_ObjectType extraObjectType; /* What object type? */
15689 + yaffs_obj_type extra_obj_type; /* What object type? */
15690
15691 - unsigned extraFileLength; /* Length if it is a file */
15692 - unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
15693 + unsigned extra_length; /* Length if it is a file */
15694 + unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */
15695
15696 - unsigned validMarker1;
15697 + unsigned validty1;
15698
15699 -} yaffs_ExtendedTags;
15700 +} yaffs_ext_tags;
15701
15702 /* Spare structure for YAFFS1 */
15703 typedef struct {
15704 - __u8 tagByte0;
15705 - __u8 tagByte1;
15706 - __u8 tagByte2;
15707 - __u8 tagByte3;
15708 - __u8 pageStatus; /* set to 0 to delete the chunk */
15709 - __u8 blockStatus;
15710 - __u8 tagByte4;
15711 - __u8 tagByte5;
15712 + __u8 tb0;
15713 + __u8 tb1;
15714 + __u8 tb2;
15715 + __u8 tb3;
15716 + __u8 page_status; /* set to 0 to delete the chunk */
15717 + __u8 block_status;
15718 + __u8 tb4;
15719 + __u8 tb5;
15720 __u8 ecc1[3];
15721 - __u8 tagByte6;
15722 - __u8 tagByte7;
15723 + __u8 tb6;
15724 + __u8 tb7;
15725 __u8 ecc2[3];
15726 -} yaffs_Spare;
15727 +} yaffs_spare;
15728
15729 /*Special structure for passing through to mtd */
15730 -struct yaffs_NANDSpare {
15731 - yaffs_Spare spare;
15732 +struct yaffs_nand_spare {
15733 + yaffs_spare spare;
15734 int eccres1;
15735 int eccres2;
15736 };
15737 @@ -234,6 +230,8 @@ typedef enum {
15738 YAFFS_BLOCK_STATE_UNKNOWN = 0,
15739
15740 YAFFS_BLOCK_STATE_SCANNING,
15741 + /* Being scanned */
15742 +
15743 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
15744 /* The block might have something on it (ie it is allocating or full, perhaps empty)
15745 * but it needs to be scanned to determine its true state.
15746 @@ -249,67 +247,69 @@ typedef enum {
15747 /* This block is partially allocated.
15748 * At least one page holds valid data.
15749 * This is the one currently being used for page
15750 - * allocation. Should never be more than one of these
15751 + * allocation. Should never be more than one of these.
15752 + * If a block is only partially allocated at mount it is treated as full.
15753 */
15754
15755 YAFFS_BLOCK_STATE_FULL,
15756 /* All the pages in this block have been allocated.
15757 + * If a block was only partially allocated when mounted we treat
15758 + * it as fully allocated.
15759 */
15760
15761 YAFFS_BLOCK_STATE_DIRTY,
15762 - /* All pages have been allocated and deleted.
15763 + /* The block was full and now all chunks have been deleted.
15764 * Erase me, reuse me.
15765 */
15766
15767 YAFFS_BLOCK_STATE_CHECKPOINT,
15768 - /* This block is assigned to holding checkpoint data.
15769 - */
15770 + /* This block is assigned to holding checkpoint data. */
15771
15772 YAFFS_BLOCK_STATE_COLLECTING,
15773 /* This block is being garbage collected */
15774
15775 YAFFS_BLOCK_STATE_DEAD
15776 /* This block has failed and is not in use */
15777 -} yaffs_BlockState;
15778 +} yaffs_block_state_t;
15779
15780 #define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
15781
15782
15783 typedef struct {
15784
15785 - int softDeletions:10; /* number of soft deleted pages */
15786 - int pagesInUse:10; /* number of pages in use */
15787 - unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
15788 - __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
15789 + int soft_del_pages:10; /* number of soft deleted pages */
15790 + int pages_in_use:10; /* number of pages in use */
15791 + unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
15792 + __u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */
15793 /* and retire the block. */
15794 - __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */
15795 - __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block.
15796 + __u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */
15797 + __u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block.
15798 It should be prioritised for GC */
15799 - __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
15800 + __u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
15801
15802 #ifdef CONFIG_YAFFS_YAFFS2
15803 - __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
15804 - __u32 sequenceNumber; /* block sequence number for yaffs2 */
15805 + __u32 has_shrink_hdr:1; /* This block has at least one shrink object header */
15806 + __u32 seq_number; /* block sequence number for yaffs2 */
15807 #endif
15808
15809 -} yaffs_BlockInfo;
15810 +} yaffs_block_info_t;
15811
15812 /* -------------------------- Object structure -------------------------------*/
15813 /* This is the object structure as stored on NAND */
15814
15815 typedef struct {
15816 - yaffs_ObjectType type;
15817 + yaffs_obj_type type;
15818
15819 /* Apply to everything */
15820 - int parentObjectId;
15821 - __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
15822 + int parent_obj_id;
15823 + __u16 sum_no_longer_used; /* checksum of name. No longer used */
15824 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
15825
15826 /* The following apply to directories, files, symlinks - not hard links */
15827 __u32 yst_mode; /* protection */
15828
15829 #ifdef CONFIG_YAFFS_WINCE
15830 - __u32 notForWinCE[5];
15831 + __u32 not_for_wince[5];
15832 #else
15833 __u32 yst_uid;
15834 __u32 yst_gid;
15835 @@ -319,10 +319,10 @@ typedef struct {
15836 #endif
15837
15838 /* File size applies to files only */
15839 - int fileSize;
15840 + int file_size;
15841
15842 /* Equivalent object id applies to hard links only. */
15843 - int equivalentObjectId;
15844 + int equiv_id;
15845
15846 /* Alias is for symlinks only. */
15847 YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
15848 @@ -334,40 +334,29 @@ typedef struct {
15849 __u32 win_atime[2];
15850 __u32 win_mtime[2];
15851 #else
15852 - __u32 roomToGrow[6];
15853 + __u32 room_to_grow[6];
15854
15855 #endif
15856 - __u32 inbandShadowsObject;
15857 - __u32 inbandIsShrink;
15858 + __u32 inband_shadowed_obj_id;
15859 + __u32 inband_is_shrink;
15860
15861 - __u32 reservedSpace[2];
15862 - int shadowsObject; /* This object header shadows the specified object if > 0 */
15863 + __u32 reserved[2];
15864 + int shadows_obj; /* This object header shadows the specified object if > 0 */
15865
15866 - /* isShrink applies to object headers written when we shrink the file (ie resize) */
15867 - __u32 isShrink;
15868 + /* is_shrink applies to object headers written when we shrink the file (ie resize) */
15869 + __u32 is_shrink;
15870
15871 -} yaffs_ObjectHeader;
15872 +} yaffs_obj_header;
15873
15874 /*--------------------------- Tnode -------------------------- */
15875
15876 -union yaffs_Tnode_union {
15877 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
15878 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
15879 -#else
15880 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
15881 -#endif
15882 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
15883 +union yaffs_tnode_union {
15884 + union yaffs_tnode_union *internal[YAFFS_NTNODES_INTERNAL];
15885
15886 };
15887
15888 -typedef union yaffs_Tnode_union yaffs_Tnode;
15889 +typedef union yaffs_tnode_union yaffs_tnode_t;
15890
15891 -struct yaffs_TnodeList_struct {
15892 - struct yaffs_TnodeList_struct *next;
15893 - yaffs_Tnode *tnodes;
15894 -};
15895 -
15896 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
15897
15898 /*------------------------ Object -----------------------------*/
15899 /* An object can be one of:
15900 @@ -378,82 +367,85 @@ typedef struct yaffs_TnodeList_struct ya
15901 */
15902
15903 typedef struct {
15904 - __u32 fileSize;
15905 - __u32 scannedFileSize;
15906 - __u32 shrinkSize;
15907 - int topLevel;
15908 - yaffs_Tnode *top;
15909 -} yaffs_FileStructure;
15910 + __u32 file_size;
15911 + __u32 scanned_size;
15912 + __u32 shrink_size;
15913 + int top_level;
15914 + yaffs_tnode_t *top;
15915 +} yaffs_file_s;
15916
15917 typedef struct {
15918 struct ylist_head children; /* list of child links */
15919 -} yaffs_DirectoryStructure;
15920 + struct ylist_head dirty; /* Entry for list of dirty directories */
15921 +} yaffs_dir_s;
15922
15923 typedef struct {
15924 YCHAR *alias;
15925 -} yaffs_SymLinkStructure;
15926 +} yaffs_symlink_t;
15927
15928 typedef struct {
15929 - struct yaffs_ObjectStruct *equivalentObject;
15930 - __u32 equivalentObjectId;
15931 -} yaffs_HardLinkStructure;
15932 + struct yaffs_obj_s *equiv_obj;
15933 + __u32 equiv_id;
15934 +} yaffs_hard_link_s;
15935
15936 typedef union {
15937 - yaffs_FileStructure fileVariant;
15938 - yaffs_DirectoryStructure directoryVariant;
15939 - yaffs_SymLinkStructure symLinkVariant;
15940 - yaffs_HardLinkStructure hardLinkVariant;
15941 -} yaffs_ObjectVariant;
15942 + yaffs_file_s file_variant;
15943 + yaffs_dir_s dir_variant;
15944 + yaffs_symlink_t symlink_variant;
15945 + yaffs_hard_link_s hardlink_variant;
15946 +} yaffs_obj_variant;
15947 +
15948 +
15949
15950 -struct yaffs_ObjectStruct {
15951 +struct yaffs_obj_s {
15952 __u8 deleted:1; /* This should only apply to unlinked files. */
15953 - __u8 softDeleted:1; /* it has also been soft deleted */
15954 + __u8 soft_del:1; /* it has also been soft deleted */
15955 __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
15956 __u8 fake:1; /* A fake object has no presence on NAND. */
15957 - __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
15958 - __u8 unlinkAllowed:1;
15959 + __u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */
15960 + __u8 unlink_allowed:1;
15961 __u8 dirty:1; /* the object needs to be written to flash */
15962 __u8 valid:1; /* When the file system is being loaded up, this
15963 * object might be created before the data
15964 * is available (ie. file data records appear before the header).
15965 */
15966 - __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
15967 + __u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */
15968
15969 - __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
15970 + __u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is
15971 * still in the inode cache. Free of object is defered.
15972 * until the inode is released.
15973 */
15974 - __u8 beingCreated:1; /* This object is still being created so skip some checks. */
15975 + __u8 being_created:1; /* This object is still being created so skip some checks. */
15976 + __u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */
15977 +
15978 + __u8 xattr_known:1; /* We know if this has object has xattribs or not. */
15979 + __u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */
15980
15981 __u8 serial; /* serial number of chunk in NAND. Cached here */
15982 __u16 sum; /* sum of the name to speed searching */
15983
15984 - struct yaffs_DeviceStruct *myDev; /* The device I'm on */
15985 + struct yaffs_dev_s *my_dev; /* The device I'm on */
15986
15987 - struct ylist_head hashLink; /* list of objects in this hash bucket */
15988 + struct ylist_head hash_link; /* list of objects in this hash bucket */
15989
15990 - struct ylist_head hardLinks; /* all the equivalent hard linked objects */
15991 + struct ylist_head hard_links; /* all the equivalent hard linked objects */
15992
15993 /* directory structure stuff */
15994 /* also used for linking up the free list */
15995 - struct yaffs_ObjectStruct *parent;
15996 + struct yaffs_obj_s *parent;
15997 struct ylist_head siblings;
15998
15999 /* Where's my object header in NAND? */
16000 - int hdrChunk;
16001 + int hdr_chunk;
16002
16003 - int nDataChunks; /* Number of data chunks attached to the file. */
16004 + int n_data_chunks; /* Number of data chunks attached to the file. */
16005
16006 - __u32 objectId; /* the object id value */
16007 + __u32 obj_id; /* the object id value */
16008
16009 __u32 yst_mode;
16010
16011 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
16012 - YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
16013 -#endif
16014 -
16015 -#ifndef __KERNEL__
16016 - __u32 inUse;
16017 + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
16018 #endif
16019
16020 #ifdef CONFIG_YAFFS_WINCE
16021 @@ -470,53 +462,43 @@ struct yaffs_ObjectStruct {
16022
16023 __u32 yst_rdev;
16024
16025 -#ifdef __KERNEL__
16026 - struct inode *myInode;
16027 + void *my_inode;
16028
16029 -#endif
16030 + yaffs_obj_type variant_type;
16031
16032 - yaffs_ObjectType variantType;
16033 + yaffs_obj_variant variant;
16034
16035 - yaffs_ObjectVariant variant;
16036 -
16037 -};
16038 -
16039 -typedef struct yaffs_ObjectStruct yaffs_Object;
16040 -
16041 -struct yaffs_ObjectList_struct {
16042 - yaffs_Object *objects;
16043 - struct yaffs_ObjectList_struct *next;
16044 };
16045
16046 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
16047 +typedef struct yaffs_obj_s yaffs_obj_t;
16048
16049 typedef struct {
16050 struct ylist_head list;
16051 int count;
16052 -} yaffs_ObjectBucket;
16053 +} yaffs_obj_bucket;
16054
16055
16056 -/* yaffs_CheckpointObject holds the definition of an object as dumped
16057 +/* yaffs_checkpt_obj_t holds the definition of an object as dumped
16058 * by checkpointing.
16059 */
16060
16061 typedef struct {
16062 - int structType;
16063 - __u32 objectId;
16064 - __u32 parentId;
16065 - int hdrChunk;
16066 - yaffs_ObjectType variantType:3;
16067 + int struct_type;
16068 + __u32 obj_id;
16069 + __u32 parent_id;
16070 + int hdr_chunk;
16071 + yaffs_obj_type variant_type:3;
16072 __u8 deleted:1;
16073 - __u8 softDeleted:1;
16074 + __u8 soft_del:1;
16075 __u8 unlinked:1;
16076 __u8 fake:1;
16077 - __u8 renameAllowed:1;
16078 - __u8 unlinkAllowed:1;
16079 + __u8 rename_allowed:1;
16080 + __u8 unlink_allowed:1;
16081 __u8 serial;
16082
16083 - int nDataChunks;
16084 - __u32 fileSizeOrEquivalentObjectId;
16085 -} yaffs_CheckpointObject;
16086 + int n_data_chunks;
16087 + __u32 size_or_equiv_obj;
16088 +} yaffs_checkpt_obj_t;
16089
16090 /*--------------------- Temporary buffers ----------------
16091 *
16092 @@ -526,379 +508,462 @@ typedef struct {
16093 typedef struct {
16094 __u8 *buffer;
16095 int line; /* track from whence this buffer was allocated */
16096 - int maxLine;
16097 -} yaffs_TempBuffer;
16098 + int max_line;
16099 +} yaffs_buffer_t;
16100
16101 /*----------------- Device ---------------------------------*/
16102
16103 -struct yaffs_DeviceStruct {
16104 - struct ylist_head devList;
16105 - const char *name;
16106 -
16107 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
16108 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
16109 - int nChunksPerBlock; /* does not need to be a power of 2 */
16110 - int spareBytesPerChunk; /* spare area size */
16111 - int startBlock; /* Start block we're allowed to use */
16112 - int endBlock; /* End block we're allowed to use */
16113 - int nReservedBlocks; /* We want this tuneable so that we can reduce */
16114 - /* reserved blocks on NOR and RAM. */
16115 -
16116
16117 - /* Stuff used by the shared space checkpointing mechanism */
16118 - /* If this value is zero, then this mechanism is disabled */
16119 +struct yaffs_param_s {
16120 + const YCHAR *name;
16121
16122 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
16123 + /*
16124 + * Entry parameters set up way early. Yaffs sets up the rest.
16125 + * The structure should be zeroed out before use so that unused
16126 + * and defualt values are zero.
16127 + */
16128 +
16129 + int inband_tags; /* Use unband tags */
16130 + __u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */
16131 + int chunks_per_block; /* does not need to be a power of 2 */
16132 + int spare_bytes_per_chunk; /* spare area size */
16133 + int start_block; /* Start block we're allowed to use */
16134 + int end_block; /* End block we're allowed to use */
16135 + int n_reserved_blocks; /* We want this tuneable so that we can reduce */
16136 + /* reserved blocks on NOR and RAM. */
16137
16138
16139 - int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
16140 - * the number of short op caches (don't use too many)
16141 + int n_caches; /* If <= 0, then short op caching is disabled, else
16142 + * the number of short op caches (don't use too many).
16143 + * 10 to 20 is a good bet.
16144 */
16145 + int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
16146 + int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
16147
16148 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
16149 + int is_yaffs2; /* Use yaffs2 mode on this device */
16150
16151 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
16152 + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
16153
16154 - void *genericDevice; /* Pointer to device context
16155 - * On an mtd this holds the mtd pointer.
16156 - */
16157 - void *superBlock;
16158 + int refresh_period; /* How often we should check to do a block refresh */
16159 +
16160 + /* Checkpoint control. Can be set before or after initialisation */
16161 + __u8 skip_checkpt_rd;
16162 + __u8 skip_checkpt_wr;
16163 +
16164 + int enable_xattr; /* Enable xattribs */
16165
16166 /* NAND access functions (Must be set before calling YAFFS)*/
16167
16168 - int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,
16169 - int chunkInNAND, const __u8 *data,
16170 - const yaffs_Spare *spare);
16171 - int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev,
16172 - int chunkInNAND, __u8 *data,
16173 - yaffs_Spare *spare);
16174 - int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev,
16175 - int blockInNAND);
16176 - int (*initialiseNAND) (struct yaffs_DeviceStruct *dev);
16177 - int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev);
16178 + int (*write_chunk_fn) (struct yaffs_dev_s *dev,
16179 + int nand_chunk, const __u8 *data,
16180 + const yaffs_spare *spare);
16181 + int (*read_chunk_fn) (struct yaffs_dev_s *dev,
16182 + int nand_chunk, __u8 *data,
16183 + yaffs_spare *spare);
16184 + int (*erase_fn) (struct yaffs_dev_s *dev,
16185 + int flash_block);
16186 + int (*initialise_flash_fn) (struct yaffs_dev_s *dev);
16187 + int (*deinitialise_flash_fn) (struct yaffs_dev_s *dev);
16188
16189 #ifdef CONFIG_YAFFS_YAFFS2
16190 - int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev,
16191 - int chunkInNAND, const __u8 *data,
16192 - const yaffs_ExtendedTags *tags);
16193 - int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev,
16194 - int chunkInNAND, __u8 *data,
16195 - yaffs_ExtendedTags *tags);
16196 - int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo);
16197 - int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo,
16198 - yaffs_BlockState *state, __u32 *sequenceNumber);
16199 -#endif
16200 -
16201 - int isYaffs2;
16202 -
16203 - /* The removeObjectCallback function must be supplied by OS flavours that
16204 - * need it. The Linux kernel does not use this, but yaffs direct does use
16205 - * it to implement the faster readdir
16206 + int (*write_chunk_tags_fn) (struct yaffs_dev_s *dev,
16207 + int nand_chunk, const __u8 *data,
16208 + const yaffs_ext_tags *tags);
16209 + int (*read_chunk_tags_fn) (struct yaffs_dev_s *dev,
16210 + int nand_chunk, __u8 *data,
16211 + yaffs_ext_tags *tags);
16212 + int (*bad_block_fn) (struct yaffs_dev_s *dev, int block_no);
16213 + int (*query_block_fn) (struct yaffs_dev_s *dev, int block_no,
16214 + yaffs_block_state_t *state, __u32 *seq_number);
16215 +#endif
16216 +
16217 + /* The remove_obj_fn function must be supplied by OS flavours that
16218 + * need it.
16219 + * yaffs direct uses it to implement the faster readdir.
16220 + * Linux uses it to protect the directory during unlocking.
16221 */
16222 - void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
16223 + void (*remove_obj_fn)(struct yaffs_obj_s *obj);
16224
16225 - /* Callback to mark the superblock dirsty */
16226 - void (*markSuperBlockDirty)(void *superblock);
16227 + /* Callback to mark the superblock dirty */
16228 + void (*sb_dirty_fn)(struct yaffs_dev_s *dev);
16229 +
16230 + /* Callback to control garbage collection. */
16231 + unsigned (*gc_control)(struct yaffs_dev_s *dev);
16232 +
16233 + /* Debug control flags. Don't use unless you know what you're doing */
16234 + int use_header_file_size; /* Flag to determine if we should use file sizes from the header */
16235 + int disable_lazy_load; /* Disable lazy loading on this device */
16236 + int wide_tnodes_disabled; /* Set to disable wide tnodes */
16237 + int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */
16238 +
16239 + int defered_dir_update; /* Set to defer directory updates */
16240
16241 - int wideTnodesDisabled; /* Set to disable wide tnodes */
16242 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
16243 + int auto_unicode;
16244 +#endif
16245 + int always_check_erased; /* Force chunk erased check always on */
16246 +};
16247
16248 - YCHAR *pathDividers; /* String of legal path dividers */
16249 +typedef struct yaffs_param_s yaffs_param_t;
16250
16251 +struct yaffs_dev_s {
16252 + struct yaffs_param_s param;
16253
16254 - /* End of stuff that must be set before initialisation. */
16255 + /* Context storage. Holds extra OS specific data for this device */
16256
16257 - /* Checkpoint control. Can be set before or after initialisation */
16258 - __u8 skipCheckpointRead;
16259 - __u8 skipCheckpointWrite;
16260 + void *os_context;
16261 + void *driver_context;
16262 +
16263 + struct ylist_head dev_list;
16264
16265 /* Runtime parameters. Set up by YAFFS. */
16266 + int data_bytes_per_chunk;
16267
16268 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
16269 - __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
16270 + /* Non-wide tnode stuff */
16271 + __u16 chunk_grp_bits; /* Number of bits that need to be resolved if
16272 + * the tnodes are not wide enough.
16273 + */
16274 + __u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
16275
16276 /* Stuff to support wide tnodes */
16277 - __u32 tnodeWidth;
16278 - __u32 tnodeMask;
16279 + __u32 tnode_width;
16280 + __u32 tnode_mask;
16281 + __u32 tnode_size;
16282
16283 /* Stuff for figuring out file offset to chunk conversions */
16284 - __u32 chunkShift; /* Shift value */
16285 - __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
16286 - __u32 chunkMask; /* Mask to use for power-of-2 case */
16287 -
16288 - /* Stuff to handle inband tags */
16289 - int inbandTags;
16290 - __u32 totalBytesPerChunk;
16291 -
16292 -#ifdef __KERNEL__
16293 -
16294 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
16295 - struct semaphore grossLock; /* Gross locking semaphore */
16296 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
16297 - * at compile time so we have to allocate it.
16298 - */
16299 - void (*putSuperFunc) (struct super_block *sb);
16300 -#endif
16301 + __u32 chunk_shift; /* Shift value */
16302 + __u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */
16303 + __u32 chunk_mask; /* Mask to use for power-of-2 case */
16304
16305 - int isMounted;
16306
16307 - int isCheckpointed;
16308 +
16309 + int is_mounted;
16310 + int read_only;
16311 + int is_checkpointed;
16312
16313
16314 /* Stuff to support block offsetting to support start block zero */
16315 - int internalStartBlock;
16316 - int internalEndBlock;
16317 - int blockOffset;
16318 - int chunkOffset;
16319 + int internal_start_block;
16320 + int internal_end_block;
16321 + int block_offset;
16322 + int chunk_offset;
16323
16324
16325 /* Runtime checkpointing stuff */
16326 - int checkpointPageSequence; /* running sequence number of checkpoint pages */
16327 - int checkpointByteCount;
16328 - int checkpointByteOffset;
16329 - __u8 *checkpointBuffer;
16330 - int checkpointOpenForWrite;
16331 - int blocksInCheckpoint;
16332 - int checkpointCurrentChunk;
16333 - int checkpointCurrentBlock;
16334 - int checkpointNextBlock;
16335 - int *checkpointBlockList;
16336 - int checkpointMaxBlocks;
16337 - __u32 checkpointSum;
16338 - __u32 checkpointXor;
16339 + int checkpt_page_seq; /* running sequence number of checkpoint pages */
16340 + int checkpt_byte_count;
16341 + int checkpt_byte_offs;
16342 + __u8 *checkpt_buffer;
16343 + int checkpt_open_write;
16344 + int blocks_in_checkpt;
16345 + int checkpt_cur_chunk;
16346 + int checkpt_cur_block;
16347 + int checkpt_next_block;
16348 + int *checkpt_block_list;
16349 + int checkpt_max_blocks;
16350 + __u32 checkpt_sum;
16351 + __u32 checkpt_xor;
16352
16353 - int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
16354 + int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */
16355
16356 /* Block Info */
16357 - yaffs_BlockInfo *blockInfo;
16358 - __u8 *chunkBits; /* bitmap of chunks in use */
16359 - unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
16360 - unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
16361 - int chunkBitmapStride; /* Number of bytes of chunkBits per block.
16362 - * Must be consistent with nChunksPerBlock.
16363 + yaffs_block_info_t *block_info;
16364 + __u8 *chunk_bits; /* bitmap of chunks in use */
16365 + unsigned block_info_alt:1; /* was allocated using alternative strategy */
16366 + unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */
16367 + int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
16368 + * Must be consistent with chunks_per_block.
16369 */
16370
16371 - int nErasedBlocks;
16372 - int allocationBlock; /* Current block being allocated off */
16373 - __u32 allocationPage;
16374 - int allocationBlockFinder; /* Used to search for next allocation block */
16375 -
16376 - /* Runtime state */
16377 - int nTnodesCreated;
16378 - yaffs_Tnode *freeTnodes;
16379 - int nFreeTnodes;
16380 - yaffs_TnodeList *allocatedTnodeList;
16381 -
16382 - int isDoingGC;
16383 - int gcBlock;
16384 - int gcChunk;
16385 -
16386 - int nObjectsCreated;
16387 - yaffs_Object *freeObjects;
16388 - int nFreeObjects;
16389 -
16390 - int nHardLinks;
16391 -
16392 - yaffs_ObjectList *allocatedObjectList;
16393 -
16394 - yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
16395 -
16396 - int nFreeChunks;
16397 -
16398 - int currentDirtyChecker; /* Used to find current dirtiest block */
16399 -
16400 - __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
16401 - int nonAggressiveSkip; /* GC state/mode */
16402 -
16403 - /* Statistcs */
16404 - int nPageWrites;
16405 - int nPageReads;
16406 - int nBlockErasures;
16407 - int nErasureFailures;
16408 - int nGCCopies;
16409 - int garbageCollections;
16410 - int passiveGarbageCollections;
16411 - int nRetriedWrites;
16412 - int nRetiredBlocks;
16413 - int eccFixed;
16414 - int eccUnfixed;
16415 - int tagsEccFixed;
16416 - int tagsEccUnfixed;
16417 - int nDeletions;
16418 - int nUnmarkedDeletions;
16419 -
16420 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
16421 + int n_erased_blocks;
16422 + int alloc_block; /* Current block being allocated off */
16423 + __u32 alloc_page;
16424 + int alloc_block_finder; /* Used to search for next allocation block */
16425 +
16426 + /* Object and Tnode memory management */
16427 + void *allocator;
16428 + int n_obj;
16429 + int n_tnodes;
16430 +
16431 + int n_hardlinks;
16432 +
16433 + yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
16434 + __u32 bucket_finder;
16435 +
16436 + int n_free_chunks;
16437 +
16438 + /* Garbage collection control */
16439 + __u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
16440 + __u32 n_clean_ups;
16441 +
16442 + unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */
16443 + unsigned gc_disable;
16444 + unsigned gc_block_finder;
16445 + unsigned gc_dirtiest;
16446 + unsigned gc_pages_in_use;
16447 + unsigned gc_not_done;
16448 + unsigned gc_block;
16449 + unsigned gc_chunk;
16450 + unsigned gc_skip;
16451
16452 /* Special directories */
16453 - yaffs_Object *rootDir;
16454 - yaffs_Object *lostNFoundDir;
16455 + yaffs_obj_t *root_dir;
16456 + yaffs_obj_t *lost_n_found;
16457
16458 /* Buffer areas for storing data to recover from write failures TODO
16459 - * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
16460 - * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
16461 + * __u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
16462 + * yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK];
16463 */
16464
16465 - int bufferedBlock; /* Which block is buffered here? */
16466 - int doingBufferedBlockRewrite;
16467 -
16468 - yaffs_ChunkCache *srCache;
16469 - int srLastUse;
16470 + int buffered_block; /* Which block is buffered here? */
16471 + int doing_buffered_block_rewrite;
16472
16473 - int cacheHits;
16474 + yaffs_cache_t *cache;
16475 + int cache_last_use;
16476
16477 /* Stuff for background deletion and unlinked files.*/
16478 - yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
16479 - yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
16480 - yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
16481 - int nDeletedFiles; /* Count of files awaiting deletion;*/
16482 - int nUnlinkedFiles; /* Count of unlinked files. */
16483 - int nBackgroundDeletions; /* Count of background deletions. */
16484 -
16485 + yaffs_obj_t *unlinked_dir; /* Directory where unlinked and deleted files live. */
16486 + yaffs_obj_t *del_dir; /* Directory where deleted objects are sent to disappear. */
16487 + yaffs_obj_t *unlinked_deletion; /* Current file being background deleted.*/
16488 + int n_deleted_files; /* Count of files awaiting deletion;*/
16489 + int n_unlinked_files; /* Count of unlinked files. */
16490 + int n_bg_deletions; /* Count of background deletions. */
16491
16492 /* Temporary buffer management */
16493 - yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
16494 - int maxTemp;
16495 - int tempInUse;
16496 - int unmanagedTempAllocations;
16497 - int unmanagedTempDeallocations;
16498 + yaffs_buffer_t temp_buffer[YAFFS_N_TEMP_BUFFERS];
16499 + int max_temp;
16500 + int temp_in_use;
16501 + int unmanaged_buffer_allocs;
16502 + int unmanaged_buffer_deallocs;
16503
16504 /* yaffs2 runtime stuff */
16505 - unsigned sequenceNumber; /* Sequence number of currently allocating block */
16506 - unsigned oldestDirtySequence;
16507 + unsigned seq_number; /* Sequence number of currently allocating block */
16508 + unsigned oldest_dirty_seq;
16509 + unsigned oldest_dirty_block;
16510 +
16511 + /* Block refreshing */
16512 + int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */
16513 +
16514 + /* Dirty directory handling */
16515 + struct ylist_head dirty_dirs; /* List of dirty directories */
16516 +
16517 +
16518 + /* Statistcs */
16519 + __u32 n_page_writes;
16520 + __u32 n_page_reads;
16521 + __u32 n_erasures;
16522 + __u32 n_erase_failures;
16523 + __u32 n_gc_copies;
16524 + __u32 all_gcs;
16525 + __u32 passive_gc_count;
16526 + __u32 oldest_dirty_gc_count;
16527 + __u32 n_gc_blocks;
16528 + __u32 bg_gcs;
16529 + __u32 n_retired_writes;
16530 + __u32 n_retired_blocks;
16531 + __u32 n_ecc_fixed;
16532 + __u32 n_ecc_unfixed;
16533 + __u32 n_tags_ecc_fixed;
16534 + __u32 n_tags_ecc_unfixed;
16535 + __u32 n_deletions;
16536 + __u32 n_unmarked_deletions;
16537 + __u32 refresh_count;
16538 + __u32 cache_hits;
16539
16540 };
16541
16542 -typedef struct yaffs_DeviceStruct yaffs_Device;
16543 +typedef struct yaffs_dev_s yaffs_dev_t;
16544
16545 /* The static layout of block usage etc is stored in the super block header */
16546 typedef struct {
16547 int StructType;
16548 int version;
16549 - int checkpointStartBlock;
16550 - int checkpointEndBlock;
16551 - int startBlock;
16552 - int endBlock;
16553 + int checkpt_start_block;
16554 + int checkpt_end_block;
16555 + int start_block;
16556 + int end_block;
16557 int rfu[100];
16558 -} yaffs_SuperBlockHeader;
16559 +} yaffs_sb_header;
16560
16561 /* The CheckpointDevice structure holds the device information that changes at runtime and
16562 * must be preserved over unmount/mount cycles.
16563 */
16564 typedef struct {
16565 - int structType;
16566 - int nErasedBlocks;
16567 - int allocationBlock; /* Current block being allocated off */
16568 - __u32 allocationPage;
16569 - int nFreeChunks;
16570 -
16571 - int nDeletedFiles; /* Count of files awaiting deletion;*/
16572 - int nUnlinkedFiles; /* Count of unlinked files. */
16573 - int nBackgroundDeletions; /* Count of background deletions. */
16574 + int struct_type;
16575 + int n_erased_blocks;
16576 + int alloc_block; /* Current block being allocated off */
16577 + __u32 alloc_page;
16578 + int n_free_chunks;
16579 +
16580 + int n_deleted_files; /* Count of files awaiting deletion;*/
16581 + int n_unlinked_files; /* Count of unlinked files. */
16582 + int n_bg_deletions; /* Count of background deletions. */
16583
16584 /* yaffs2 runtime stuff */
16585 - unsigned sequenceNumber; /* Sequence number of currently allocating block */
16586 - unsigned oldestDirtySequence;
16587 + unsigned seq_number; /* Sequence number of currently allocating block */
16588
16589 -} yaffs_CheckpointDevice;
16590 +} yaffs_checkpt_dev_t;
16591
16592
16593 typedef struct {
16594 - int structType;
16595 + int struct_type;
16596 __u32 magic;
16597 __u32 version;
16598 __u32 head;
16599 -} yaffs_CheckpointValidity;
16600 +} yaffs_checkpt_validty_t;
16601 +
16602 +
16603 +struct yaffs_shadow_fixer_s {
16604 + int obj_id;
16605 + int shadowed_id;
16606 + struct yaffs_shadow_fixer_s *next;
16607 +};
16608 +
16609 +/* Structure for doing xattr modifications */
16610 +typedef struct {
16611 + int set; /* If 0 then this is a deletion */
16612 + const YCHAR *name;
16613 + const void *data;
16614 + int size;
16615 + int flags;
16616 + int result;
16617 +}yaffs_xattr_mod;
16618
16619
16620 /*----------------------- YAFFS Functions -----------------------*/
16621
16622 -int yaffs_GutsInitialise(yaffs_Device *dev);
16623 -void yaffs_Deinitialise(yaffs_Device *dev);
16624 +int yaffs_guts_initialise(yaffs_dev_t *dev);
16625 +void yaffs_deinitialise(yaffs_dev_t *dev);
16626
16627 -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
16628 +int yaffs_get_n_free_chunks(yaffs_dev_t *dev);
16629
16630 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
16631 - yaffs_Object *newDir, const YCHAR *newName);
16632 +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
16633 + yaffs_obj_t *new_dir, const YCHAR *new_name);
16634
16635 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
16636 -int yaffs_DeleteObject(yaffs_Object *obj);
16637 +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name);
16638 +int yaffs_del_obj(yaffs_obj_t *obj);
16639
16640 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize);
16641 -int yaffs_GetObjectFileLength(yaffs_Object *obj);
16642 -int yaffs_GetObjectInode(yaffs_Object *obj);
16643 -unsigned yaffs_GetObjectType(yaffs_Object *obj);
16644 -int yaffs_GetObjectLinkCount(yaffs_Object *obj);
16645 +int yaffs_get_obj_name(yaffs_obj_t *obj, YCHAR *name, int buffer_size);
16646 +int yaffs_get_obj_length(yaffs_obj_t *obj);
16647 +int yaffs_get_obj_inode(yaffs_obj_t *obj);
16648 +unsigned yaffs_get_obj_type(yaffs_obj_t *obj);
16649 +int yaffs_get_obj_link_count(yaffs_obj_t *obj);
16650
16651 -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
16652 -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
16653 +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr);
16654 +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr);
16655
16656 /* File operations */
16657 -int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset,
16658 - int nBytes);
16659 -int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset,
16660 - int nBytes, int writeThrough);
16661 -int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize);
16662 +int yaffs_file_rd(yaffs_obj_t *obj, __u8 *buffer, loff_t offset,
16663 + int n_bytes);
16664 +int yaffs_wr_file(yaffs_obj_t *obj, const __u8 *buffer, loff_t offset,
16665 + int n_bytes, int write_trhrough);
16666 +int yaffs_resize_file(yaffs_obj_t *obj, loff_t new_size);
16667
16668 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
16669 +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
16670 __u32 mode, __u32 uid, __u32 gid);
16671 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
16672 +
16673 +int yaffs_flush_file(yaffs_obj_t *obj, int update_time, int data_sync);
16674
16675 /* Flushing and checkpointing */
16676 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
16677 +void yaffs_flush_whole_cache(yaffs_dev_t *dev);
16678
16679 -int yaffs_CheckpointSave(yaffs_Device *dev);
16680 -int yaffs_CheckpointRestore(yaffs_Device *dev);
16681 +int yaffs_checkpoint_save(yaffs_dev_t *dev);
16682 +int yaffs_checkpoint_restore(yaffs_dev_t *dev);
16683
16684 /* Directory operations */
16685 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
16686 +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
16687 __u32 mode, __u32 uid, __u32 gid);
16688 -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name);
16689 -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
16690 - int (*fn) (yaffs_Object *));
16691 +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *the_dir, const YCHAR *name);
16692 +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
16693 + int (*fn) (yaffs_obj_t *));
16694
16695 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number);
16696 +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number);
16697
16698 /* Link operations */
16699 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
16700 - yaffs_Object *equivalentObject);
16701 +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
16702 + yaffs_obj_t *equiv_obj);
16703
16704 -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
16705 +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj);
16706
16707 /* Symlink operations */
16708 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
16709 +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
16710 __u32 mode, __u32 uid, __u32 gid,
16711 const YCHAR *alias);
16712 -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
16713 +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj);
16714
16715 /* Special inodes (fifos, sockets and devices) */
16716 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
16717 +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
16718 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
16719
16720 +
16721 +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags);
16722 +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size);
16723 +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size);
16724 +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name);
16725 +
16726 /* Special directories */
16727 -yaffs_Object *yaffs_Root(yaffs_Device *dev);
16728 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
16729 +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev);
16730 +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev);
16731
16732 #ifdef CONFIG_YAFFS_WINCE
16733 /* CONFIG_YAFFS_WINCE special stuff */
16734 -void yfsd_WinFileTimeNow(__u32 target[2]);
16735 +void yfsd_win_file_time_now(__u32 target[2]);
16736 #endif
16737
16738 -#ifdef __KERNEL__
16739 +void yaffs_handle_defered_free(yaffs_obj_t *obj);
16740
16741 -void yaffs_HandleDeferedFree(yaffs_Object *obj);
16742 -#endif
16743 +void yaffs_update_dirty_dirs(yaffs_dev_t *dev);
16744 +
16745 +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency);
16746
16747 /* Debug dump */
16748 -int yaffs_DumpObject(yaffs_Object *obj);
16749 +int yaffs_dump_obj(yaffs_obj_t *obj);
16750
16751 -void yaffs_GutsTest(yaffs_Device *dev);
16752 +void yaffs_guts_test(yaffs_dev_t *dev);
16753
16754 -/* A few useful functions */
16755 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
16756 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
16757 -int yaffs_CheckFF(__u8 *buffer, int nBytes);
16758 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
16759 +/* A few useful functions to be used within the core files*/
16760 +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn);
16761 +int yaffs_check_ff(__u8 *buffer, int n_bytes);
16762 +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi);
16763 +
16764 +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no);
16765 +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer, int line_no);
16766 +
16767 +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
16768 + int number,
16769 + yaffs_obj_type type);
16770 +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
16771 + int nand_chunk, int in_scan);
16772 +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name);
16773 +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh);
16774 +void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
16775 + yaffs_obj_t *obj);
16776 +YCHAR *yaffs_clone_str(const YCHAR *str);
16777 +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list);
16778 +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no);
16779 +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name,
16780 + int force, int is_shrink, int shadows,
16781 + yaffs_xattr_mod *xop);
16782 +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
16783 + int backward_scanning);
16784 +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks);
16785 +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev);
16786 +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
16787 + yaffs_file_s *file_struct,
16788 + __u32 chunk_id,
16789 + yaffs_tnode_t *passed_tn);
16790 +
16791 +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
16792 + int n_bytes, int write_trhrough);
16793 +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size);
16794 +void yaffs_skip_rest_of_block(yaffs_dev_t *dev);
16795 +
16796 +int yaffs_count_free_chunks(yaffs_dev_t *dev);
16797 +
16798 +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
16799 + yaffs_file_s *file_struct,
16800 + __u32 chunk_id);
16801
16802 -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
16803 -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
16804 +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos);
16805
16806 #endif
16807 --- a/fs/yaffs2/yaffsinterface.h
16808 +++ b/fs/yaffs2/yaffsinterface.h
16809 @@ -1,7 +1,7 @@
16810 /*
16811 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16812 *
16813 - * Copyright (C) 2002-2007 Aleph One Ltd.
16814 + * Copyright (C) 2002-2010 Aleph One Ltd.
16815 * for Toby Churchill Ltd and Brightstar Engineering
16816 *
16817 * Created by Charles Manning <charles@aleph1.co.uk>
16818 @@ -16,6 +16,6 @@
16819 #ifndef __YAFFSINTERFACE_H__
16820 #define __YAFFSINTERFACE_H__
16821
16822 -int yaffs_Initialise(unsigned nBlocks);
16823 +int yaffs_initialise(unsigned nBlocks);
16824
16825 #endif
16826 --- /dev/null
16827 +++ b/fs/yaffs2/yaffs_linux_allocator.c
16828 @@ -0,0 +1,200 @@
16829 +/*
16830 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16831 + *
16832 + * Copyright (C) 2002-2010 Aleph One Ltd.
16833 + * for Toby Churchill Ltd and Brightstar Engineering
16834 + *
16835 + * Created by Charles Manning <charles@aleph1.co.uk>
16836 + *
16837 + * This program is free software; you can redistribute it and/or modify
16838 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16839 + * published by the Free Software Foundation.
16840 + *
16841 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16842 + *
16843 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
16844 + */
16845 +
16846 +
16847 +#include "yaffs_allocator.h"
16848 +#include "yaffs_guts.h"
16849 +#include "yaffs_trace.h"
16850 +#include "yportenv.h"
16851 +#include "yaffs_linux.h"
16852 +/*
16853 + * Start out with the same allocator as yaffs direct.
16854 + * Todo: Change to Linux slab allocator.
16855 + */
16856 +
16857 +
16858 +
16859 +#define NAMELEN 20
16860 +struct yaffs_AllocatorStruct {
16861 + char tnode_name[NAMELEN+1];
16862 + char object_name[NAMELEN+1];
16863 + struct kmem_cache *tnode_cache;
16864 + struct kmem_cache *object_cache;
16865 +};
16866 +
16867 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
16868 +
16869 +int mount_id;
16870 +
16871 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
16872 +{
16873 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
16874 +
16875 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
16876 +
16877 + if(allocator){
16878 + if(allocator->tnode_cache){
16879 + kmem_cache_destroy(allocator->tnode_cache);
16880 + allocator->tnode_cache = NULL;
16881 + } else {
16882 + T(YAFFS_TRACE_ALWAYS,
16883 + (TSTR("NULL tnode cache\n")));
16884 + YBUG();
16885 + }
16886 +
16887 + if(allocator->object_cache){
16888 + kmem_cache_destroy(allocator->object_cache);
16889 + allocator->object_cache = NULL;
16890 + } else {
16891 + T(YAFFS_TRACE_ALWAYS,
16892 + (TSTR("NULL object cache\n")));
16893 + YBUG();
16894 + }
16895 +
16896 + YFREE(allocator);
16897 +
16898 + } else {
16899 + T(YAFFS_TRACE_ALWAYS,
16900 + (TSTR("Deinitialising NULL allocator\n")));
16901 + YBUG();
16902 + }
16903 + dev->allocator = NULL;
16904 +}
16905 +
16906 +
16907 +static void fake_ctor0(void *data){data = data;}
16908 +static void fake_ctor1(void *data){data = data;}
16909 +static void fake_ctor2(void *data){data = data;}
16910 +static void fake_ctor3(void *data){data = data;}
16911 +static void fake_ctor4(void *data){data = data;}
16912 +static void fake_ctor5(void *data){data = data;}
16913 +static void fake_ctor6(void *data){data = data;}
16914 +static void fake_ctor7(void *data){data = data;}
16915 +static void fake_ctor8(void *data){data = data;}
16916 +static void fake_ctor9(void *data){data = data;}
16917 +
16918 +static void (*fake_ctor_list[10]) (void *) = {
16919 + fake_ctor0,
16920 + fake_ctor1,
16921 + fake_ctor2,
16922 + fake_ctor3,
16923 + fake_ctor4,
16924 + fake_ctor5,
16925 + fake_ctor6,
16926 + fake_ctor7,
16927 + fake_ctor8,
16928 + fake_ctor9,
16929 +};
16930 +
16931 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
16932 +{
16933 + yaffs_Allocator *allocator;
16934 + unsigned mount_id = yaffs_dev_to_lc(dev)->mount_id;
16935 +
16936 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
16937 +
16938 + if(dev->allocator)
16939 + YBUG();
16940 + else if(mount_id >= 10){
16941 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
16942 + } else {
16943 + allocator = YMALLOC(sizeof(yaffs_Allocator));
16944 + memset(allocator,0,sizeof(yaffs_Allocator));
16945 + dev->allocator = allocator;
16946 +
16947 + if(!dev->allocator){
16948 + T(YAFFS_TRACE_ALWAYS,
16949 + (TSTR("yaffs allocator creation failed\n")));
16950 + YBUG();
16951 + return;
16952 +
16953 + }
16954 +
16955 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
16956 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
16957 +
16958 + allocator->tnode_cache =
16959 + kmem_cache_create(allocator->tnode_name,
16960 + dev->tnode_size,
16961 + 0, 0,
16962 + fake_ctor_list[mount_id]);
16963 + if(allocator->tnode_cache)
16964 + T(YAFFS_TRACE_ALLOCATE,
16965 + (TSTR("tnode cache \"%s\" %p\n"),
16966 + allocator->tnode_name,allocator->tnode_cache));
16967 + else {
16968 + T(YAFFS_TRACE_ALWAYS,
16969 + (TSTR("yaffs cache creation failed\n")));
16970 + YBUG();
16971 + }
16972 +
16973 +
16974 + allocator->object_cache =
16975 + kmem_cache_create(allocator->object_name,
16976 + sizeof(yaffs_obj_t),
16977 + 0, 0,
16978 + fake_ctor_list[mount_id]);
16979 +
16980 + if(allocator->object_cache)
16981 + T(YAFFS_TRACE_ALLOCATE,
16982 + (TSTR("object cache \"%s\" %p\n"),
16983 + allocator->object_name,allocator->object_cache));
16984 +
16985 + else {
16986 + T(YAFFS_TRACE_ALWAYS,
16987 + (TSTR("yaffs cache creation failed\n")));
16988 + YBUG();
16989 + }
16990 + }
16991 +}
16992 +
16993 +
16994 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
16995 +{
16996 + yaffs_Allocator *allocator = dev->allocator;
16997 + if(!allocator || !allocator->tnode_cache){
16998 + YBUG();
16999 + return NULL;
17000 + }
17001 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
17002 +}
17003 +
17004 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
17005 +{
17006 + yaffs_Allocator *allocator = dev->allocator;
17007 + kmem_cache_free(allocator->tnode_cache,tn);
17008 +}
17009 +
17010 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
17011 +{
17012 + yaffs_Allocator *allocator = dev->allocator;
17013 + if(!allocator){
17014 + YBUG();
17015 + return NULL;
17016 + }
17017 + if(!allocator->object_cache){
17018 + YBUG();
17019 + return NULL;
17020 + }
17021 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
17022 +}
17023 +
17024 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
17025 +{
17026 + yaffs_Allocator *allocator = dev->allocator;
17027 + kmem_cache_free(allocator->object_cache,obj);
17028 +}
17029 --- /dev/null
17030 +++ b/fs/yaffs2/yaffs_linux.h
17031 @@ -0,0 +1,43 @@
17032 +/*
17033 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17034 + *
17035 + * Copyright (C) 2002-2010 Aleph One Ltd.
17036 + * for Toby Churchill Ltd and Brightstar Engineering
17037 + *
17038 + * Created by Charles Manning <charles@aleph1.co.uk>
17039 + *
17040 + * This program is free software; you can redistribute it and/or modify
17041 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17042 + * published by the Free Software Foundation.
17043 + *
17044 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17045 + */
17046 +
17047 +#ifndef __YAFFS_LINUX_H__
17048 +#define __YAFFS_LINUX_H__
17049 +
17050 +#include "devextras.h"
17051 +#include "yportenv.h"
17052 +
17053 +struct yaffs_LinuxContext {
17054 + struct ylist_head contextList; /* List of these we have mounted */
17055 + struct yaffs_dev_s *dev;
17056 + struct super_block * superBlock;
17057 + struct task_struct *bgThread; /* Background thread for this device */
17058 + int bgRunning;
17059 + struct semaphore grossLock; /* Gross locking semaphore */
17060 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
17061 + * at compile time so we have to allocate it.
17062 + */
17063 + struct ylist_head searchContexts;
17064 + void (*putSuperFunc)(struct super_block *sb);
17065 +
17066 + struct task_struct *readdirProcess;
17067 + unsigned mount_id;
17068 +};
17069 +
17070 +#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
17071 +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
17072 +
17073 +#endif
17074 +
17075 --- /dev/null
17076 +++ b/fs/yaffs2/yaffs_list.h
17077 @@ -0,0 +1,127 @@
17078 +/*
17079 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17080 + *
17081 + * Copyright (C) 2002-2010 Aleph One Ltd.
17082 + * for Toby Churchill Ltd and Brightstar Engineering
17083 + *
17084 + * Created by Charles Manning <charles@aleph1.co.uk>
17085 + *
17086 + * This program is free software; you can redistribute it and/or modify
17087 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17088 + * published by the Free Software Foundation.
17089 + *
17090 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17091 + */
17092 +
17093 +/*
17094 + * This file is just holds extra declarations of macros that would normally
17095 + * be providesd in the Linux kernel. These macros have been written from
17096 + * scratch but are functionally equivalent to the Linux ones.
17097 + *
17098 + */
17099 +
17100 +#ifndef __YAFFS_LIST_H__
17101 +#define __YAFFS_LIST_H__
17102 +
17103 +
17104 +#include "yportenv.h"
17105 +
17106 +/*
17107 + * This is a simple doubly linked list implementation that matches the
17108 + * way the Linux kernel doubly linked list implementation works.
17109 + */
17110 +
17111 +struct ylist_head {
17112 + struct ylist_head *next; /* next in chain */
17113 + struct ylist_head *prev; /* previous in chain */
17114 +};
17115 +
17116 +
17117 +/* Initialise a static list */
17118 +#define YLIST_HEAD(name) \
17119 +struct ylist_head name = { &(name), &(name)}
17120 +
17121 +
17122 +
17123 +/* Initialise a list head to an empty list */
17124 +#define YINIT_LIST_HEAD(p) \
17125 +do { \
17126 + (p)->next = (p);\
17127 + (p)->prev = (p); \
17128 +} while (0)
17129 +
17130 +
17131 +/* Add an element to a list */
17132 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
17133 + struct ylist_head *list)
17134 +{
17135 + struct ylist_head *listNext = list->next;
17136 +
17137 + list->next = newEntry;
17138 + newEntry->prev = list;
17139 + newEntry->next = listNext;
17140 + listNext->prev = newEntry;
17141 +
17142 +}
17143 +
17144 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
17145 + struct ylist_head *list)
17146 +{
17147 + struct ylist_head *listPrev = list->prev;
17148 +
17149 + list->prev = newEntry;
17150 + newEntry->next = list;
17151 + newEntry->prev = listPrev;
17152 + listPrev->next = newEntry;
17153 +
17154 +}
17155 +
17156 +
17157 +/* Take an element out of its current list, with or without
17158 + * reinitialising the links.of the entry*/
17159 +static Y_INLINE void ylist_del(struct ylist_head *entry)
17160 +{
17161 + struct ylist_head *listNext = entry->next;
17162 + struct ylist_head *listPrev = entry->prev;
17163 +
17164 + listNext->prev = listPrev;
17165 + listPrev->next = listNext;
17166 +
17167 +}
17168 +
17169 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
17170 +{
17171 + ylist_del(entry);
17172 + entry->next = entry->prev = entry;
17173 +}
17174 +
17175 +
17176 +/* Test if the list is empty */
17177 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
17178 +{
17179 + return (entry->next == entry);
17180 +}
17181 +
17182 +
17183 +/* ylist_entry takes a pointer to a list entry and offsets it to that
17184 + * we can find a pointer to the object it is embedded in.
17185 + */
17186 +
17187 +
17188 +#define ylist_entry(entry, type, member) \
17189 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
17190 +
17191 +
17192 +/* ylist_for_each and list_for_each_safe iterate over lists.
17193 + * ylist_for_each_safe uses temporary storage to make the list delete safe
17194 + */
17195 +
17196 +#define ylist_for_each(itervar, list) \
17197 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
17198 +
17199 +#define ylist_for_each_safe(itervar, saveVar, list) \
17200 + for (itervar = (list)->next, saveVar = (list)->next->next; \
17201 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
17202 +
17203 +
17204 +#endif
17205 --- a/fs/yaffs2/yaffs_mtdif1.c
17206 +++ b/fs/yaffs2/yaffs_mtdif1.c
17207 @@ -2,7 +2,7 @@
17208 * YAFFS: Yet another FFS. A NAND-flash specific file system.
17209 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
17210 *
17211 - * Copyright (C) 2002 Aleph One Ltd.
17212 + * Copyright (C) 2002-2010 Aleph One Ltd.
17213 * for Toby Churchill Ltd and Brightstar Engineering
17214 *
17215 * This program is free software; you can redistribute it and/or modify
17216 @@ -18,15 +18,17 @@
17217 *
17218 * These functions are invoked via function pointers in yaffs_nand.c.
17219 * This replaces functionality provided by functions in yaffs_mtdif.c
17220 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
17221 + * and the yaffs_tags_tCompatability functions in yaffs_tagscompat.c that are
17222 * called in yaffs_mtdif.c when the function pointers are NULL.
17223 - * We assume the MTD layer is performing ECC (useNANDECC is true).
17224 + * We assume the MTD layer is performing ECC (use_nand_ecc is true).
17225 */
17226
17227 #include "yportenv.h"
17228 +#include "yaffs_trace.h"
17229 #include "yaffs_guts.h"
17230 #include "yaffs_packedtags1.h"
17231 -#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
17232 +#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
17233 +#include "yaffs_linux.h"
17234
17235 #include "linux/kernel.h"
17236 #include "linux/version.h"
17237 @@ -36,8 +38,6 @@
17238 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
17239 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
17240
17241 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
17242 -
17243 #ifndef CONFIG_YAFFS_9BYTE_TAGS
17244 # define YTAG1_SIZE 8
17245 #else
17246 @@ -51,12 +51,12 @@ const char *yaffs_mtdif1_c_version = "$I
17247 * adjust 'oobfree' to match your existing Yaffs data.
17248 *
17249 * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
17250 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
17251 + * page_status byte (at NAND spare offset 4) scattered/gathered from/to
17252 * the 9th byte.
17253 *
17254 * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
17255 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
17256 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
17257 + * We have/need PackedTags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
17258 + * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
17259 * byte and B is the small-page bad-block indicator byte.
17260 */
17261 static struct nand_ecclayout nand_oob_16 = {
17262 @@ -88,42 +88,40 @@ static struct nand_ecclayout nand_oob_16
17263 * Any underlying MTD error results in YAFFS_FAIL.
17264 * Returns YAFFS_OK or YAFFS_FAIL.
17265 */
17266 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
17267 - int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
17268 +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev,
17269 + int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
17270 {
17271 - struct mtd_info *mtd = dev->genericDevice;
17272 - int chunkBytes = dev->nDataBytesPerChunk;
17273 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17274 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17275 + int chunkBytes = dev->data_bytes_per_chunk;
17276 + loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
17277 struct mtd_oob_ops ops;
17278 yaffs_PackedTags1 pt1;
17279 int retval;
17280
17281 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
17282 + /* we assume that PackedTags1 and yaffs_tags_t are compatible */
17283 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
17284 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
17285 -
17286 - dev->nPageWrites++;
17287 + compile_time_assertion(sizeof(yaffs_tags_t) == 8);
17288
17289 yaffs_PackTags1(&pt1, etags);
17290 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
17291 + yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1);
17292
17293 /* When deleting a chunk, the upper layer provides only skeletal
17294 - * etags, one with chunkDeleted set. However, we need to update the
17295 + * etags, one with is_deleted set. However, we need to update the
17296 * tags, not erase them completely. So we use the NAND write property
17297 * that only zeroed-bits stick and set tag bytes to all-ones and
17298 * zero just the (not) deleted bit.
17299 */
17300 #ifndef CONFIG_YAFFS_9BYTE_TAGS
17301 - if (etags->chunkDeleted) {
17302 + if (etags->is_deleted) {
17303 memset(&pt1, 0xff, 8);
17304 /* clear delete status bit to indicate deleted */
17305 pt1.deleted = 0;
17306 }
17307 #else
17308 ((__u8 *)&pt1)[8] = 0xff;
17309 - if (etags->chunkDeleted) {
17310 + if (etags->is_deleted) {
17311 memset(&pt1, 0xff, 8);
17312 - /* zero pageStatus byte to indicate deleted */
17313 + /* zero page_status byte to indicate deleted */
17314 ((__u8 *)&pt1)[8] = 0;
17315 }
17316 #endif
17317 @@ -137,20 +135,20 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
17318
17319 retval = mtd->write_oob(mtd, addr, &ops);
17320 if (retval) {
17321 - yaffs_trace(YAFFS_TRACE_MTD,
17322 - "write_oob failed, chunk %d, mtd error %d\n",
17323 - chunkInNAND, retval);
17324 + T(YAFFS_TRACE_MTD,
17325 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
17326 + nand_chunk, retval));
17327 }
17328 return retval ? YAFFS_FAIL : YAFFS_OK;
17329 }
17330
17331 -/* Return with empty ExtendedTags but add eccResult.
17332 +/* Return with empty ExtendedTags but add ecc_result.
17333 */
17334 -static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
17335 +static int rettags(yaffs_ext_tags *etags, int ecc_result, int retval)
17336 {
17337 if (etags) {
17338 memset(etags, 0, sizeof(*etags));
17339 - etags->eccResult = eccResult;
17340 + etags->ecc_result = ecc_result;
17341 }
17342 return retval;
17343 }
17344 @@ -158,30 +156,28 @@ static int rettags(yaffs_ExtendedTags *e
17345 /* Read a chunk (page) from NAND.
17346 *
17347 * Caller expects ExtendedTags data to be usable even on error; that is,
17348 - * all members except eccResult and blockBad are zeroed.
17349 + * all members except ecc_result and block_bad are zeroed.
17350 *
17351 * - Check ECC results for data (if applicable)
17352 * - Check for blank/erased block (return empty ExtendedTags if blank)
17353 * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
17354 * - Convert PackedTags1 to ExtendedTags
17355 - * - Update eccResult and blockBad members to refect state.
17356 + * - Update ecc_result and block_bad members to refect state.
17357 *
17358 * Returns YAFFS_OK or YAFFS_FAIL.
17359 */
17360 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
17361 - int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
17362 +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev,
17363 + int nand_chunk, __u8 *data, yaffs_ext_tags *etags)
17364 {
17365 - struct mtd_info *mtd = dev->genericDevice;
17366 - int chunkBytes = dev->nDataBytesPerChunk;
17367 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17368 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17369 + int chunkBytes = dev->data_bytes_per_chunk;
17370 + loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
17371 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
17372 struct mtd_oob_ops ops;
17373 yaffs_PackedTags1 pt1;
17374 int retval;
17375 int deleted;
17376
17377 - dev->nPageReads++;
17378 -
17379 memset(&ops, 0, sizeof(ops));
17380 ops.mode = MTD_OOB_AUTO;
17381 ops.len = (data) ? chunkBytes : 0;
17382 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17383 */
17384 retval = mtd->read_oob(mtd, addr, &ops);
17385 if (retval) {
17386 - yaffs_trace(YAFFS_TRACE_MTD,
17387 - "read_oob failed, chunk %d, mtd error %d\n",
17388 - chunkInNAND, retval);
17389 + T(YAFFS_TRACE_MTD,
17390 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
17391 + nand_chunk, retval));
17392 }
17393
17394 switch (retval) {
17395 @@ -213,23 +209,23 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17396 case -EUCLEAN:
17397 /* MTD's ECC fixed the data */
17398 eccres = YAFFS_ECC_RESULT_FIXED;
17399 - dev->eccFixed++;
17400 + dev->n_ecc_fixed++;
17401 break;
17402
17403 case -EBADMSG:
17404 /* MTD's ECC could not fix the data */
17405 - dev->eccUnfixed++;
17406 + dev->n_ecc_unfixed++;
17407 /* fall into... */
17408 default:
17409 rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
17410 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
17411 + etags->block_bad = (mtd->block_isbad)(mtd, addr);
17412 return YAFFS_FAIL;
17413 }
17414
17415 /* Check for a blank/erased chunk.
17416 */
17417 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
17418 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
17419 + if (yaffs_check_ff((__u8 *)&pt1, 8)) {
17420 + /* when blank, upper layers want ecc_result to be <= NO_ERROR */
17421 return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
17422 }
17423
17424 @@ -241,37 +237,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17425 deleted = !pt1.deleted;
17426 pt1.deleted = 1;
17427 #else
17428 - deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
17429 + deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7);
17430 #endif
17431
17432 /* Check the packed tags mini-ECC and correct if necessary/possible.
17433 */
17434 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
17435 + retval = yaffs_check_tags_ecc((yaffs_tags_t *)&pt1);
17436 switch (retval) {
17437 case 0:
17438 /* no tags error, use MTD result */
17439 break;
17440 case 1:
17441 /* recovered tags-ECC error */
17442 - dev->tagsEccFixed++;
17443 + dev->n_tags_ecc_fixed++;
17444 if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
17445 eccres = YAFFS_ECC_RESULT_FIXED;
17446 break;
17447 default:
17448 /* unrecovered tags-ECC error */
17449 - dev->tagsEccUnfixed++;
17450 + dev->n_tags_ecc_unfixed++;
17451 return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
17452 }
17453
17454 /* Unpack the tags to extended form and set ECC result.
17455 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
17456 + * [set shouldBeFF just to keep yaffs_unpack_tags1 happy]
17457 */
17458 pt1.shouldBeFF = 0xFFFFFFFF;
17459 - yaffs_UnpackTags1(etags, &pt1);
17460 - etags->eccResult = eccres;
17461 + yaffs_unpack_tags1(etags, &pt1);
17462 + etags->ecc_result = eccres;
17463
17464 /* Set deleted state */
17465 - etags->chunkDeleted = deleted;
17466 + etags->is_deleted = deleted;
17467 return YAFFS_OK;
17468 }
17469
17470 @@ -282,15 +278,15 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17471 *
17472 * Returns YAFFS_OK or YAFFS_FAIL.
17473 */
17474 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
17475 +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
17476 {
17477 - struct mtd_info *mtd = dev->genericDevice;
17478 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
17479 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17480 + int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
17481 int retval;
17482
17483 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
17484 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
17485
17486 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
17487 + retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
17488 return (retval) ? YAFFS_FAIL : YAFFS_OK;
17489 }
17490
17491 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
17492 int oobavail = mtd->ecclayout->oobavail;
17493
17494 if (oobavail < YTAG1_SIZE) {
17495 - yaffs_trace(YAFFS_TRACE_ERROR,
17496 - "mtd device has only %d bytes for tags, need %d\n",
17497 - oobavail, YTAG1_SIZE);
17498 + T(YAFFS_TRACE_ERROR,
17499 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
17500 + oobavail, YTAG1_SIZE));
17501 return YAFFS_FAIL;
17502 }
17503 return YAFFS_OK;
17504 @@ -322,13 +318,13 @@ static int nandmtd1_TestPrerequists(stru
17505 *
17506 * Always returns YAFFS_OK.
17507 */
17508 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
17509 - yaffs_BlockState *pState, __u32 *pSequenceNumber)
17510 +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
17511 + yaffs_block_state_t *pState, __u32 *pSequenceNumber)
17512 {
17513 - struct mtd_info *mtd = dev->genericDevice;
17514 - int chunkNo = blockNo * dev->nChunksPerBlock;
17515 - loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
17516 - yaffs_ExtendedTags etags;
17517 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17518 + int chunkNo = block_no * dev->param.chunks_per_block;
17519 + loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk;
17520 + yaffs_ext_tags etags;
17521 int state = YAFFS_BLOCK_STATE_DEAD;
17522 int seqnum = 0;
17523 int retval;
17524 @@ -340,17 +336,17 @@ int nandmtd1_QueryNANDBlock(struct yaffs
17525 return YAFFS_FAIL;
17526
17527 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
17528 - etags.blockBad = (mtd->block_isbad)(mtd, addr);
17529 - if (etags.blockBad) {
17530 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
17531 - "block %d is marked bad\n", blockNo);
17532 + etags.block_bad = (mtd->block_isbad)(mtd, addr);
17533 + if (etags.block_bad) {
17534 + T(YAFFS_TRACE_BAD_BLOCKS,
17535 + (TSTR("block %d is marked bad"TENDSTR), block_no));
17536 state = YAFFS_BLOCK_STATE_DEAD;
17537 - } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
17538 + } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
17539 /* bad tags, need to look more closely */
17540 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17541 - } else if (etags.chunkUsed) {
17542 + } else if (etags.chunk_used) {
17543 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17544 - seqnum = etags.sequenceNumber;
17545 + seqnum = etags.seq_number;
17546 } else {
17547 state = YAFFS_BLOCK_STATE_EMPTY;
17548 }
17549 --- a/fs/yaffs2/yaffs_mtdif1-compat.c
17550 +++ /dev/null
17551 @@ -1,434 +0,0 @@
17552 -From ian@brightstareng.com Fri May 18 15:06:49 2007
17553 -From ian@brightstareng.com Fri May 18 15:08:21 2007
17554 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
17555 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
17556 - (envelope-from <ian@brightstareng.com>)
17557 - id 1Hp380-00011e-T6
17558 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
17559 -Received: from localhost (localhost.localdomain [127.0.0.1])
17560 - by zebra.brightstareng.com (Postfix) with ESMTP
17561 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
17562 -Received: from zebra.brightstareng.com ([127.0.0.1])
17563 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
17564 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
17565 -Received: from pippin (unknown [192.168.1.25])
17566 - by zebra.brightstareng.com (Postfix) with ESMTP
17567 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
17568 -From: Ian McDonnell <ian@brightstareng.com>
17569 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
17570 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
17571 -Date: Fri, 18 May 2007 10:06:49 -0400
17572 -User-Agent: KMail/1.9.1
17573 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
17574 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
17575 -Cc: Andrea Conti <alyf@alyf.net>,
17576 - Charles Manning <manningc2@actrix.gen.nz>
17577 -MIME-Version: 1.0
17578 -Content-Type: Multipart/Mixed;
17579 - boundary="Boundary-00=_5LbTGmt62YoutxM"
17580 -Message-Id: <200705181006.49860.ian@brightstareng.com>
17581 -X-Virus-Scanned: by amavisd-new at brightstareng.com
17582 -Status: R
17583 -X-Status: NT
17584 -X-KMail-EncryptionState:
17585 -X-KMail-SignatureState:
17586 -X-KMail-MDN-Sent:
17587 -
17588 ---Boundary-00=_5LbTGmt62YoutxM
17589 -Content-Type: text/plain;
17590 - charset="iso-8859-15"
17591 -Content-Transfer-Encoding: 7bit
17592 -Content-Disposition: inline
17593 -
17594 -David, Andrea,
17595 -
17596 -On Friday 18 May 2007 08:34, you wrote:
17597 -> Yea team. With this fix in place (I put it in the wrong place
17598 -> at first) I can now mount and ls the Yaffs partition without
17599 -> an error messages!
17600 -
17601 -Good news!
17602 -
17603 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
17604 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
17605 -See the LINUX_VERSION_CODE conditional in
17606 -nandmtd1_ReadChunkWithTagsFromNAND.
17607 -
17608 --imcd
17609 -
17610 ---Boundary-00=_5LbTGmt62YoutxM
17611 -Content-Type: text/x-csrc;
17612 - charset="iso-8859-15";
17613 - name="yaffs_mtdif1.c"
17614 -Content-Transfer-Encoding: 7bit
17615 -Content-Disposition: attachment;
17616 - filename="yaffs_mtdif1.c"
17617 -
17618 -/*
17619 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
17620 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
17621 - *
17622 - * Copyright (C) 2002 Aleph One Ltd.
17623 - * for Toby Churchill Ltd and Brightstar Engineering
17624 - *
17625 - * This program is free software; you can redistribute it and/or modify
17626 - * it under the terms of the GNU General Public License version 2 as
17627 - * published by the Free Software Foundation.
17628 - */
17629 -
17630 -/*
17631 - * This module provides the interface between yaffs_nand.c and the
17632 - * MTD API. This version is used when the MTD interface supports the
17633 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
17634 - * and we have small-page NAND device.
17635 - *
17636 - * These functions are invoked via function pointers in yaffs_nand.c.
17637 - * This replaces functionality provided by functions in yaffs_mtdif.c
17638 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
17639 - * called in yaffs_mtdif.c when the function pointers are NULL.
17640 - * We assume the MTD layer is performing ECC (useNANDECC is true).
17641 - */
17642 -
17643 -#include "yportenv.h"
17644 -#include "yaffs_guts.h"
17645 -#include "yaffs_packedtags1.h"
17646 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
17647 -
17648 -#include "linux/kernel.h"
17649 -#include "linux/version.h"
17650 -#include "linux/types.h"
17651 -#include "linux/mtd/mtd.h"
17652 -
17653 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
17654 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
17655 -
17656 -const char *yaffs_mtdif1_c_version = "$Id$";
17657 -
17658 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17659 -# define YTAG1_SIZE 8
17660 -#else
17661 -# define YTAG1_SIZE 9
17662 -#endif
17663 -
17664 -#if 0
17665 -/* Use the following nand_ecclayout with MTD when using
17666 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
17667 - * If you have existing Yaffs images and the byte order differs from this,
17668 - * adjust 'oobfree' to match your existing Yaffs data.
17669 - *
17670 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
17671 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
17672 - * the 9th byte.
17673 - *
17674 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
17675 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
17676 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
17677 - * byte and B is the small-page bad-block indicator byte.
17678 - */
17679 -static struct nand_ecclayout nand_oob_16 = {
17680 - .eccbytes = 6,
17681 - .eccpos = { 8, 9, 10, 13, 14, 15 },
17682 - .oobavail = 9,
17683 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
17684 -};
17685 -#endif
17686 -
17687 -/* Write a chunk (page) of data to NAND.
17688 - *
17689 - * Caller always provides ExtendedTags data which are converted to a more
17690 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
17691 - * contents of the tags meta-data; used to valid the tags when read.
17692 - *
17693 - * - Pack ExtendedTags to PackedTags1 form
17694 - * - Compute mini-ECC for PackedTags1
17695 - * - Write data and packed tags to NAND.
17696 - *
17697 - * Note: Due to the use of the PackedTags1 meta-data which does not include
17698 - * a full sequence number (as found in the larger PackedTags2 form) it is
17699 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
17700 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
17701 - * to be written just once. When Yaffs performs this operation, this
17702 - * function is called with a NULL data pointer -- calling MTD write_oob
17703 - * without data is valid usage (2.6.17).
17704 - *
17705 - * Any underlying MTD error results in YAFFS_FAIL.
17706 - * Returns YAFFS_OK or YAFFS_FAIL.
17707 - */
17708 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
17709 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
17710 -{
17711 - struct mtd_info * mtd = dev->genericDevice;
17712 - int chunkBytes = dev->nDataBytesPerChunk;
17713 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17714 - struct mtd_oob_ops ops;
17715 - yaffs_PackedTags1 pt1;
17716 - int retval;
17717 -
17718 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
17719 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
17720 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
17721 -
17722 - yaffs_PackTags1(&pt1, etags);
17723 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
17724 -
17725 - /* When deleting a chunk, the upper layer provides only skeletal
17726 - * etags, one with chunkDeleted set. However, we need to update the
17727 - * tags, not erase them completely. So we use the NAND write property
17728 - * that only zeroed-bits stick and set tag bytes to all-ones and
17729 - * zero just the (not) deleted bit.
17730 - */
17731 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17732 - if (etags->chunkDeleted) {
17733 - memset(&pt1, 0xff, 8);
17734 - /* clear delete status bit to indicate deleted */
17735 - pt1.deleted = 0;
17736 - }
17737 -#else
17738 - ((__u8 *)&pt1)[8] = 0xff;
17739 - if (etags->chunkDeleted) {
17740 - memset(&pt1, 0xff, 8);
17741 - /* zero pageStatus byte to indicate deleted */
17742 - ((__u8 *)&pt1)[8] = 0;
17743 - }
17744 -#endif
17745 -
17746 - memset(&ops, 0, sizeof(ops));
17747 - ops.mode = MTD_OOB_AUTO;
17748 - ops.len = (data) ? chunkBytes : 0;
17749 - ops.ooblen = YTAG1_SIZE;
17750 - ops.datbuf = (__u8 *)data;
17751 - ops.oobbuf = (__u8 *)&pt1;
17752 -
17753 - retval = mtd->write_oob(mtd, addr, &ops);
17754 - if (retval) {
17755 - yaffs_trace(YAFFS_TRACE_MTD,
17756 - "write_oob failed, chunk %d, mtd error %d\n",
17757 - chunkInNAND, retval);
17758 - }
17759 - return retval ? YAFFS_FAIL : YAFFS_OK;
17760 -}
17761 -
17762 -/* Return with empty ExtendedTags but add eccResult.
17763 - */
17764 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
17765 -{
17766 - if (etags) {
17767 - memset(etags, 0, sizeof(*etags));
17768 - etags->eccResult = eccResult;
17769 - }
17770 - return retval;
17771 -}
17772 -
17773 -/* Read a chunk (page) from NAND.
17774 - *
17775 - * Caller expects ExtendedTags data to be usable even on error; that is,
17776 - * all members except eccResult and blockBad are zeroed.
17777 - *
17778 - * - Check ECC results for data (if applicable)
17779 - * - Check for blank/erased block (return empty ExtendedTags if blank)
17780 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
17781 - * - Convert PackedTags1 to ExtendedTags
17782 - * - Update eccResult and blockBad members to refect state.
17783 - *
17784 - * Returns YAFFS_OK or YAFFS_FAIL.
17785 - */
17786 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
17787 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
17788 -{
17789 - struct mtd_info * mtd = dev->genericDevice;
17790 - int chunkBytes = dev->nDataBytesPerChunk;
17791 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17792 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
17793 - struct mtd_oob_ops ops;
17794 - yaffs_PackedTags1 pt1;
17795 - int retval;
17796 - int deleted;
17797 -
17798 - memset(&ops, 0, sizeof(ops));
17799 - ops.mode = MTD_OOB_AUTO;
17800 - ops.len = (data) ? chunkBytes : 0;
17801 - ops.ooblen = YTAG1_SIZE;
17802 - ops.datbuf = data;
17803 - ops.oobbuf = (__u8 *)&pt1;
17804 -
17805 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
17806 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
17807 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
17808 - */
17809 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
17810 -#endif
17811 - /* Read page and oob using MTD.
17812 - * Check status and determine ECC result.
17813 - */
17814 - retval = mtd->read_oob(mtd, addr, &ops);
17815 - if (retval) {
17816 - yaffs_trace(YAFFS_TRACE_MTD,
17817 - "read_oob failed, chunk %d, mtd error %d\n",
17818 - chunkInNAND, retval);
17819 - }
17820 -
17821 - switch (retval) {
17822 - case 0:
17823 - /* no error */
17824 - break;
17825 -
17826 - case -EUCLEAN:
17827 - /* MTD's ECC fixed the data */
17828 - eccres = YAFFS_ECC_RESULT_FIXED;
17829 - dev->eccFixed++;
17830 - break;
17831 -
17832 - case -EBADMSG:
17833 - /* MTD's ECC could not fix the data */
17834 - dev->eccUnfixed++;
17835 - /* fall into... */
17836 - default:
17837 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
17838 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
17839 - return YAFFS_FAIL;
17840 - }
17841 -
17842 - /* Check for a blank/erased chunk.
17843 - */
17844 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
17845 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
17846 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
17847 - }
17848 -
17849 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17850 - /* Read deleted status (bit) then return it to it's non-deleted
17851 - * state before performing tags mini-ECC check. pt1.deleted is
17852 - * inverted.
17853 - */
17854 - deleted = !pt1.deleted;
17855 - pt1.deleted = 1;
17856 -#else
17857 - (void) deleted; /* not used */
17858 -#endif
17859 -
17860 - /* Check the packed tags mini-ECC and correct if necessary/possible.
17861 - */
17862 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
17863 - switch (retval) {
17864 - case 0:
17865 - /* no tags error, use MTD result */
17866 - break;
17867 - case 1:
17868 - /* recovered tags-ECC error */
17869 - dev->tagsEccFixed++;
17870 - eccres = YAFFS_ECC_RESULT_FIXED;
17871 - break;
17872 - default:
17873 - /* unrecovered tags-ECC error */
17874 - dev->tagsEccUnfixed++;
17875 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
17876 - }
17877 -
17878 - /* Unpack the tags to extended form and set ECC result.
17879 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
17880 - */
17881 - pt1.shouldBeFF = 0xFFFFFFFF;
17882 - yaffs_UnpackTags1(etags, &pt1);
17883 - etags->eccResult = eccres;
17884 -
17885 - /* Set deleted state.
17886 - */
17887 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17888 - etags->chunkDeleted = deleted;
17889 -#else
17890 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
17891 -#endif
17892 - return YAFFS_OK;
17893 -}
17894 -
17895 -/* Mark a block bad.
17896 - *
17897 - * This is a persistant state.
17898 - * Use of this function should be rare.
17899 - *
17900 - * Returns YAFFS_OK or YAFFS_FAIL.
17901 - */
17902 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
17903 -{
17904 - struct mtd_info * mtd = dev->genericDevice;
17905 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
17906 - int retval;
17907 -
17908 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
17909 -
17910 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
17911 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
17912 -}
17913 -
17914 -/* Check any MTD prerequists.
17915 - *
17916 - * Returns YAFFS_OK or YAFFS_FAIL.
17917 - */
17918 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
17919 -{
17920 - /* 2.6.18 has mtd->ecclayout->oobavail */
17921 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
17922 - int oobavail = mtd->ecclayout->oobavail;
17923 -
17924 - if (oobavail < YTAG1_SIZE) {
17925 - yaffs_trace(YAFFS_TRACE_ERROR,
17926 - "mtd device has only %d bytes for tags, need %d",
17927 - oobavail, YTAG1_SIZE);
17928 - return YAFFS_FAIL;
17929 - }
17930 - return YAFFS_OK;
17931 -}
17932 -
17933 -/* Query for the current state of a specific block.
17934 - *
17935 - * Examine the tags of the first chunk of the block and return the state:
17936 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
17937 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
17938 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
17939 - *
17940 - * Always returns YAFFS_OK.
17941 - */
17942 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
17943 - yaffs_BlockState * pState, int *pSequenceNumber)
17944 -{
17945 - struct mtd_info * mtd = dev->genericDevice;
17946 - int chunkNo = blockNo * dev->nChunksPerBlock;
17947 - yaffs_ExtendedTags etags;
17948 - int state = YAFFS_BLOCK_STATE_DEAD;
17949 - int seqnum = 0;
17950 - int retval;
17951 -
17952 - /* We don't yet have a good place to test for MTD config prerequists.
17953 - * Do it here as we are called during the initial scan.
17954 - */
17955 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
17956 - return YAFFS_FAIL;
17957 - }
17958 -
17959 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
17960 - if (etags.blockBad) {
17961 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
17962 - "block %d is marked bad", blockNo);
17963 - state = YAFFS_BLOCK_STATE_DEAD;
17964 - }
17965 - else if (etags.chunkUsed) {
17966 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17967 - seqnum = etags.sequenceNumber;
17968 - }
17969 - else {
17970 - state = YAFFS_BLOCK_STATE_EMPTY;
17971 - }
17972 -
17973 - *pState = state;
17974 - *pSequenceNumber = seqnum;
17975 -
17976 - /* query always succeeds */
17977 - return YAFFS_OK;
17978 -}
17979 -
17980 -#endif /*KERNEL_VERSION*/
17981 -
17982 ---Boundary-00=_5LbTGmt62YoutxM--
17983 -
17984 -
17985 -
17986 --- a/fs/yaffs2/yaffs_mtdif1.h
17987 +++ b/fs/yaffs2/yaffs_mtdif1.h
17988 @@ -1,7 +1,7 @@
17989 /*
17990 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
17991 *
17992 - * Copyright (C) 2002-2007 Aleph One Ltd.
17993 + * Copyright (C) 2002-2010 Aleph One Ltd.
17994 * for Toby Churchill Ltd and Brightstar Engineering
17995 *
17996 * This program is free software; you can redistribute it and/or modify
17997 @@ -14,15 +14,15 @@
17998 #ifndef __YAFFS_MTDIF1_H__
17999 #define __YAFFS_MTDIF1_H__
18000
18001 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18002 - const __u8 *data, const yaffs_ExtendedTags *tags);
18003 +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18004 + const __u8 *data, const yaffs_ext_tags *tags);
18005
18006 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18007 - __u8 *data, yaffs_ExtendedTags *tags);
18008 +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18009 + __u8 *data, yaffs_ext_tags *tags);
18010
18011 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
18012 +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
18013
18014 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18015 - yaffs_BlockState *state, __u32 *sequenceNumber);
18016 +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18017 + yaffs_block_state_t *state, __u32 *seq_number);
18018
18019 #endif
18020 --- a/fs/yaffs2/yaffs_mtdif2.c
18021 +++ b/fs/yaffs2/yaffs_mtdif2.c
18022 @@ -1,7 +1,7 @@
18023 /*
18024 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18025 *
18026 - * Copyright (C) 2002-2007 Aleph One Ltd.
18027 + * Copyright (C) 2002-2010 Aleph One Ltd.
18028 * for Toby Churchill Ltd and Brightstar Engineering
18029 *
18030 * Created by Charles Manning <charles@aleph1.co.uk>
18031 @@ -13,11 +13,8 @@
18032
18033 /* mtd interface for YAFFS2 */
18034
18035 -const char *yaffs_mtdif2_c_version =
18036 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
18037 -
18038 #include "yportenv.h"
18039 -
18040 +#include "yaffs_trace.h"
18041
18042 #include "yaffs_mtdif2.h"
18043
18044 @@ -27,15 +24,17 @@ const char *yaffs_mtdif2_c_version =
18045
18046 #include "yaffs_packedtags2.h"
18047
18048 +#include "yaffs_linux.h"
18049 +
18050 /* NB For use with inband tags....
18051 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
18052 * use it to load the tags.
18053 */
18054 -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18055 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18056 const __u8 *data,
18057 - const yaffs_ExtendedTags *tags)
18058 + const yaffs_ext_tags *tags)
18059 {
18060 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18061 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18062 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18063 struct mtd_oob_ops ops;
18064 #else
18065 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18066
18067 yaffs_PackedTags2 pt;
18068
18069 + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
18070 + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t : (void *)&pt;
18071 +
18072 T(YAFFS_TRACE_MTD,
18073 (TSTR
18074 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
18075 - TENDSTR), chunkInNAND, data, tags));
18076 + TENDSTR), nand_chunk, data, tags));
18077
18078
18079 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
18080 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
18081
18082 /* For yaffs2 writing there must be both data and tags.
18083 * If we're using inband tags, then the tags are stuffed into
18084 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18085 */
18086 if (!data || !tags)
18087 BUG();
18088 - else if (dev->inbandTags) {
18089 + else if (dev->param.inband_tags) {
18090 yaffs_PackedTags2TagsPart *pt2tp;
18091 - pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
18092 + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk);
18093 yaffs_PackTags2TagsPart(pt2tp, tags);
18094 } else
18095 - yaffs_PackTags2(&pt, tags);
18096 + yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
18097
18098 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18099 ops.mode = MTD_OOB_AUTO;
18100 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
18101 - ops.len = dev->totalBytesPerChunk;
18102 + ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
18103 + ops.len = dev->param.total_bytes_per_chunk;
18104 ops.ooboffs = 0;
18105 ops.datbuf = (__u8 *)data;
18106 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
18107 + ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
18108 retval = mtd->write_oob(mtd, addr, &ops);
18109
18110 #else
18111 - if (!dev->inbandTags) {
18112 + if (!dev->param.inband_tags) {
18113 retval =
18114 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18115 - &dummy, data, (__u8 *) &pt, NULL);
18116 + mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
18117 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
18118 } else {
18119 retval =
18120 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
18121 + mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy,
18122 data);
18123 }
18124 #endif
18125 @@ -95,10 +97,10 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18126 return YAFFS_FAIL;
18127 }
18128
18129 -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18130 - __u8 *data, yaffs_ExtendedTags *tags)
18131 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18132 + __u8 *data, yaffs_ext_tags *tags)
18133 {
18134 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18135 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18136 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18137 struct mtd_oob_ops ops;
18138 #endif
18139 @@ -106,20 +108,23 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18140 int retval = 0;
18141 int localData = 0;
18142
18143 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
18144 + loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
18145
18146 yaffs_PackedTags2 pt;
18147
18148 + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
18149 + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t: (void *)&pt;
18150 +
18151 T(YAFFS_TRACE_MTD,
18152 (TSTR
18153 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
18154 - TENDSTR), chunkInNAND, data, tags));
18155 + TENDSTR), nand_chunk, data, tags));
18156
18157 - if (dev->inbandTags) {
18158 + if (dev->param.inband_tags) {
18159
18160 if (!data) {
18161 localData = 1;
18162 - data = yaffs_GetTempBuffer(dev, __LINE__);
18163 + data = yaffs_get_temp_buffer(dev, __LINE__);
18164 }
18165
18166
18167 @@ -127,30 +132,30 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18168
18169
18170 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18171 - if (dev->inbandTags || (data && !tags))
18172 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
18173 + if (dev->param.inband_tags || (data && !tags))
18174 + retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
18175 &dummy, data);
18176 else if (tags) {
18177 ops.mode = MTD_OOB_AUTO;
18178 - ops.ooblen = sizeof(pt);
18179 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
18180 + ops.ooblen = packed_tags_size;
18181 + ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
18182 ops.ooboffs = 0;
18183 ops.datbuf = data;
18184 - ops.oobbuf = dev->spareBuffer;
18185 + ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
18186 retval = mtd->read_oob(mtd, addr, &ops);
18187 }
18188 #else
18189 - if (!dev->inbandTags && data && tags) {
18190 + if (!dev->param.inband_tags && data && tags) {
18191
18192 - retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18193 + retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
18194 &dummy, data, dev->spareBuffer,
18195 NULL);
18196 } else {
18197 if (data)
18198 retval =
18199 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18200 + mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
18201 data);
18202 - if (!dev->inbandTags && tags)
18203 + if (!dev->param.inband_tags && tags)
18204 retval =
18205 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
18206 dev->spareBuffer);
18207 @@ -158,41 +163,47 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18208 #endif
18209
18210
18211 - if (dev->inbandTags) {
18212 + if (dev->param.inband_tags) {
18213 if (tags) {
18214 yaffs_PackedTags2TagsPart *pt2tp;
18215 - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
18216 - yaffs_UnpackTags2TagsPart(tags, pt2tp);
18217 + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk];
18218 + yaffs_unpack_tags2tags_part(tags, pt2tp);
18219 }
18220 } else {
18221 if (tags) {
18222 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
18223 - yaffs_UnpackTags2(tags, &pt);
18224 + memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size);
18225 + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
18226 }
18227 }
18228
18229 if (localData)
18230 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
18231 + yaffs_release_temp_buffer(dev, data, __LINE__);
18232
18233 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
18234 - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
18235 + if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
18236 + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
18237 + dev->n_ecc_unfixed++;
18238 + }
18239 + if(tags && retval == -EUCLEAN && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
18240 + tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
18241 + dev->n_ecc_fixed++;
18242 + }
18243 if (retval == 0)
18244 return YAFFS_OK;
18245 else
18246 return YAFFS_FAIL;
18247 }
18248
18249 -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
18250 +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
18251 {
18252 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18253 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18254 int retval;
18255 T(YAFFS_TRACE_MTD,
18256 - (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
18257 + (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
18258
18259 retval =
18260 mtd->block_markbad(mtd,
18261 - blockNo * dev->nChunksPerBlock *
18262 - dev->totalBytesPerChunk);
18263 + block_no * dev->param.chunks_per_block *
18264 + dev->param.total_bytes_per_chunk);
18265
18266 if (retval == 0)
18267 return YAFFS_OK;
18268 @@ -201,41 +212,41 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
18269
18270 }
18271
18272 -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18273 - yaffs_BlockState *state, __u32 *sequenceNumber)
18274 +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18275 + yaffs_block_state_t *state, __u32 *seq_number)
18276 {
18277 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18278 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18279 int retval;
18280
18281 T(YAFFS_TRACE_MTD,
18282 - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
18283 + (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
18284 retval =
18285 mtd->block_isbad(mtd,
18286 - blockNo * dev->nChunksPerBlock *
18287 - dev->totalBytesPerChunk);
18288 + block_no * dev->param.chunks_per_block *
18289 + dev->param.total_bytes_per_chunk);
18290
18291 if (retval) {
18292 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
18293
18294 *state = YAFFS_BLOCK_STATE_DEAD;
18295 - *sequenceNumber = 0;
18296 + *seq_number = 0;
18297 } else {
18298 - yaffs_ExtendedTags t;
18299 + yaffs_ext_tags t;
18300 nandmtd2_ReadChunkWithTagsFromNAND(dev,
18301 - blockNo *
18302 - dev->nChunksPerBlock, NULL,
18303 + block_no *
18304 + dev->param.chunks_per_block, NULL,
18305 &t);
18306
18307 - if (t.chunkUsed) {
18308 - *sequenceNumber = t.sequenceNumber;
18309 + if (t.chunk_used) {
18310 + *seq_number = t.seq_number;
18311 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
18312 } else {
18313 - *sequenceNumber = 0;
18314 + *seq_number = 0;
18315 *state = YAFFS_BLOCK_STATE_EMPTY;
18316 }
18317 }
18318 T(YAFFS_TRACE_MTD,
18319 - (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
18320 + (TSTR("block is bad seq %d state %d" TENDSTR), *seq_number,
18321 *state));
18322
18323 if (retval == 0)
18324 --- a/fs/yaffs2/yaffs_mtdif2.h
18325 +++ b/fs/yaffs2/yaffs_mtdif2.h
18326 @@ -1,7 +1,7 @@
18327 /*
18328 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18329 *
18330 - * Copyright (C) 2002-2007 Aleph One Ltd.
18331 + * Copyright (C) 2002-2010 Aleph One Ltd.
18332 * for Toby Churchill Ltd and Brightstar Engineering
18333 *
18334 * Created by Charles Manning <charles@aleph1.co.uk>
18335 @@ -17,13 +17,13 @@
18336 #define __YAFFS_MTDIF2_H__
18337
18338 #include "yaffs_guts.h"
18339 -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18340 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18341 const __u8 *data,
18342 - const yaffs_ExtendedTags *tags);
18343 -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18344 - __u8 *data, yaffs_ExtendedTags *tags);
18345 -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
18346 -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18347 - yaffs_BlockState *state, __u32 *sequenceNumber);
18348 + const yaffs_ext_tags *tags);
18349 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18350 + __u8 *data, yaffs_ext_tags *tags);
18351 +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
18352 +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18353 + yaffs_block_state_t *state, __u32 *seq_number);
18354
18355 #endif
18356 --- a/fs/yaffs2/yaffs_mtdif.c
18357 +++ b/fs/yaffs2/yaffs_mtdif.c
18358 @@ -1,7 +1,7 @@
18359 /*
18360 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18361 *
18362 - * Copyright (C) 2002-2007 Aleph One Ltd.
18363 + * Copyright (C) 2002-2010 Aleph One Ltd.
18364 * for Toby Churchill Ltd and Brightstar Engineering
18365 *
18366 * Created by Charles Manning <charles@aleph1.co.uk>
18367 @@ -11,9 +11,6 @@
18368 * published by the Free Software Foundation.
18369 */
18370
18371 -const char *yaffs_mtdif_c_version =
18372 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
18373 -
18374 #include "yportenv.h"
18375
18376
18377 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
18378 #include "linux/time.h"
18379 #include "linux/mtd/nand.h"
18380
18381 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
18382 -static struct nand_oobinfo yaffs_oobinfo = {
18383 - .useecc = 1,
18384 - .eccbytes = 6,
18385 - .eccpos = {8, 9, 10, 13, 14, 15}
18386 -};
18387 -
18388 -static struct nand_oobinfo yaffs_noeccinfo = {
18389 - .useecc = 0,
18390 -};
18391 -#endif
18392 -
18393 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18394 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
18395 -{
18396 - oob[0] = spare->tagByte0;
18397 - oob[1] = spare->tagByte1;
18398 - oob[2] = spare->tagByte2;
18399 - oob[3] = spare->tagByte3;
18400 - oob[4] = spare->tagByte4;
18401 - oob[5] = spare->tagByte5 & 0x3f;
18402 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
18403 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
18404 - oob[6] = spare->tagByte6;
18405 - oob[7] = spare->tagByte7;
18406 -}
18407 -
18408 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
18409 -{
18410 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
18411 - spare->tagByte0 = oob[0];
18412 - spare->tagByte1 = oob[1];
18413 - spare->tagByte2 = oob[2];
18414 - spare->tagByte3 = oob[3];
18415 - spare->tagByte4 = oob[4];
18416 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
18417 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
18418 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
18419 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
18420 - spare->tagByte6 = oob[6];
18421 - spare->tagByte7 = oob[7];
18422 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
18423 -
18424 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
18425 -}
18426 -#endif
18427 -
18428 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
18429 - const __u8 *data, const yaffs_Spare *spare)
18430 -{
18431 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18432 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18433 - struct mtd_oob_ops ops;
18434 -#endif
18435 - size_t dummy;
18436 - int retval = 0;
18437 -
18438 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
18439 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18440 - __u8 spareAsBytes[8]; /* OOB */
18441 -
18442 - if (data && !spare)
18443 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
18444 - &dummy, data);
18445 - else if (spare) {
18446 - if (dev->useNANDECC) {
18447 - translate_spare2oob(spare, spareAsBytes);
18448 - ops.mode = MTD_OOB_AUTO;
18449 - ops.ooblen = 8; /* temp hack */
18450 - } else {
18451 - ops.mode = MTD_OOB_RAW;
18452 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
18453 - }
18454 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
18455 - ops.datbuf = (u8 *)data;
18456 - ops.ooboffs = 0;
18457 - ops.oobbuf = spareAsBytes;
18458 - retval = mtd->write_oob(mtd, addr, &ops);
18459 - }
18460 -#else
18461 - __u8 *spareAsBytes = (__u8 *) spare;
18462 -
18463 - if (data && spare) {
18464 - if (dev->useNANDECC)
18465 - retval =
18466 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18467 - &dummy, data, spareAsBytes,
18468 - &yaffs_oobinfo);
18469 - else
18470 - retval =
18471 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18472 - &dummy, data, spareAsBytes,
18473 - &yaffs_noeccinfo);
18474 - } else {
18475 - if (data)
18476 - retval =
18477 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18478 - data);
18479 - if (spare)
18480 - retval =
18481 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
18482 - &dummy, spareAsBytes);
18483 - }
18484 -#endif
18485 -
18486 - if (retval == 0)
18487 - return YAFFS_OK;
18488 - else
18489 - return YAFFS_FAIL;
18490 -}
18491 -
18492 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
18493 - yaffs_Spare *spare)
18494 -{
18495 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18496 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18497 - struct mtd_oob_ops ops;
18498 -#endif
18499 - size_t dummy;
18500 - int retval = 0;
18501 +#include "yaffs_linux.h"
18502
18503 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
18504 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18505 - __u8 spareAsBytes[8]; /* OOB */
18506 -
18507 - if (data && !spare)
18508 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
18509 - &dummy, data);
18510 - else if (spare) {
18511 - if (dev->useNANDECC) {
18512 - ops.mode = MTD_OOB_AUTO;
18513 - ops.ooblen = 8; /* temp hack */
18514 - } else {
18515 - ops.mode = MTD_OOB_RAW;
18516 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
18517 - }
18518 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
18519 - ops.datbuf = data;
18520 - ops.ooboffs = 0;
18521 - ops.oobbuf = spareAsBytes;
18522 - retval = mtd->read_oob(mtd, addr, &ops);
18523 - if (dev->useNANDECC)
18524 - translate_oob2spare(spare, spareAsBytes);
18525 - }
18526 -#else
18527 - __u8 *spareAsBytes = (__u8 *) spare;
18528 -
18529 - if (data && spare) {
18530 - if (dev->useNANDECC) {
18531 - /* Careful, this call adds 2 ints */
18532 - /* to the end of the spare data. Calling function */
18533 - /* should allocate enough memory for spare, */
18534 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
18535 - retval =
18536 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18537 - &dummy, data, spareAsBytes,
18538 - &yaffs_oobinfo);
18539 - } else {
18540 - retval =
18541 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18542 - &dummy, data, spareAsBytes,
18543 - &yaffs_noeccinfo);
18544 - }
18545 - } else {
18546 - if (data)
18547 - retval =
18548 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18549 - data);
18550 - if (spare)
18551 - retval =
18552 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
18553 - &dummy, spareAsBytes);
18554 - }
18555 -#endif
18556 -
18557 - if (retval == 0)
18558 - return YAFFS_OK;
18559 - else
18560 - return YAFFS_FAIL;
18561 -}
18562 -
18563 -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
18564 +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
18565 {
18566 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18567 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18568 __u32 addr =
18569 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
18570 - * dev->nChunksPerBlock;
18571 + ((loff_t) blockNumber) * dev->param.total_bytes_per_chunk
18572 + * dev->param.chunks_per_block;
18573 struct erase_info ei;
18574 +
18575 int retval = 0;
18576
18577 ei.mtd = mtd;
18578 ei.addr = addr;
18579 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
18580 + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
18581 ei.time = 1000;
18582 ei.retries = 2;
18583 ei.callback = NULL;
18584 ei.priv = (u_long) dev;
18585
18586 - /* Todo finish off the ei if required */
18587 -
18588 - sema_init(&dev->sem, 0);
18589 -
18590 retval = mtd->erase(mtd, &ei);
18591
18592 if (retval == 0)
18593 @@ -234,7 +49,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Devic
18594 return YAFFS_FAIL;
18595 }
18596
18597 -int nandmtd_InitialiseNAND(yaffs_Device *dev)
18598 +int nandmtd_InitialiseNAND(yaffs_dev_t *dev)
18599 {
18600 return YAFFS_OK;
18601 }
18602 --- a/fs/yaffs2/yaffs_mtdif.h
18603 +++ b/fs/yaffs2/yaffs_mtdif.h
18604 @@ -1,7 +1,7 @@
18605 /*
18606 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18607 *
18608 - * Copyright (C) 2002-2007 Aleph One Ltd.
18609 + * Copyright (C) 2002-2010 Aleph One Ltd.
18610 * for Toby Churchill Ltd and Brightstar Engineering
18611 *
18612 * Created by Charles Manning <charles@aleph1.co.uk>
18613 @@ -22,11 +22,6 @@
18614 extern struct nand_oobinfo yaffs_oobinfo;
18615 extern struct nand_oobinfo yaffs_noeccinfo;
18616 #endif
18617 -
18618 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
18619 - const __u8 *data, const yaffs_Spare *spare);
18620 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
18621 - yaffs_Spare *spare);
18622 -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
18623 -int nandmtd_InitialiseNAND(yaffs_Device *dev);
18624 +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
18625 +int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
18626 #endif
18627 --- /dev/null
18628 +++ b/fs/yaffs2/yaffs_nameval.c
18629 @@ -0,0 +1,197 @@
18630 +/*
18631 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18632 + *
18633 + * Copyright (C) 2002-2010 Aleph One Ltd.
18634 + * for Toby Churchill Ltd and Brightstar Engineering
18635 + *
18636 + * Created by Charles Manning <charles@aleph1.co.uk>
18637 + *
18638 + * This program is free software; you can redistribute it and/or modify
18639 + * it under the terms of the GNU General Public License version 2 as
18640 + * published by the Free Software Foundation.
18641 + */
18642 +
18643 +/*
18644 + * This simple implementation of a name-value store assumes a small number of values and fits
18645 + * into a small finite buffer.
18646 + *
18647 + * Each attribute is stored as a record:
18648 + * sizeof(int) bytes record size.
18649 + * strnlen+1 bytes name null terminated.
18650 + * nbytes value.
18651 + * ----------
18652 + * total size stored in record size
18653 + *
18654 + * This code has not been tested with unicode yet.
18655 + */
18656 +
18657 +
18658 +#include "yaffs_nameval.h"
18659 +
18660 +#include "yportenv.h"
18661 +
18662 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
18663 + int *exist_size)
18664 +{
18665 + int pos=0;
18666 + int size;
18667 +
18668 + memcpy(&size,xb,sizeof(int));
18669 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
18670 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
18671 + if(exist_size)
18672 + *exist_size = size;
18673 + return pos;
18674 + }
18675 + pos += size;
18676 + if(pos < xb_size -sizeof(int))
18677 + memcpy(&size,xb + pos,sizeof(int));
18678 + else
18679 + size = 0;
18680 + }
18681 + if(exist_size)
18682 + *exist_size = 0;
18683 + return -1;
18684 +}
18685 +
18686 +static int nval_used(const char *xb, int xb_size)
18687 +{
18688 + int pos=0;
18689 + int size;
18690 +
18691 + memcpy(&size,xb + pos,sizeof(int));
18692 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
18693 + pos += size;
18694 + if(pos < xb_size -sizeof(int))
18695 + memcpy(&size,xb + pos,sizeof(int));
18696 + else
18697 + size = 0;
18698 + }
18699 + return pos;
18700 +}
18701 +
18702 +int nval_del(char *xb, int xb_size, const YCHAR *name)
18703 +{
18704 + int pos = nval_find(xb, xb_size, name, NULL);
18705 + int size;
18706 +
18707 + if(pos >= 0 && pos < xb_size){
18708 + /* Find size, shift rest over this record, then zero out the rest of buffer */
18709 + memcpy(&size,xb+pos,sizeof(int));
18710 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
18711 + memset(xb + (xb_size - size),0,size);
18712 + return 0;
18713 + } else
18714 + return -ENODATA;
18715 +}
18716 +
18717 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
18718 +{
18719 + int pos;
18720 + int namelen = yaffs_strnlen(name,xb_size);
18721 + int reclen;
18722 + int size_exist = 0;
18723 + int space;
18724 + int start;
18725 +
18726 + pos = nval_find(xb,xb_size,name, &size_exist);
18727 +
18728 + if(flags & XATTR_CREATE && pos >= 0)
18729 + return -EEXIST;
18730 + if(flags & XATTR_REPLACE && pos < 0)
18731 + return -ENODATA;
18732 +
18733 + start = nval_used(xb,xb_size);
18734 + space = xb_size - start + size_exist;
18735 +
18736 + reclen = (sizeof(int) + namelen + 1 + bsize);
18737 +
18738 + if(reclen > space)
18739 + return -ENOSPC;
18740 +
18741 + if(pos >= 0){
18742 + nval_del(xb,xb_size,name);
18743 + start = nval_used(xb, xb_size);
18744 + }
18745 +
18746 + pos = start;
18747 +
18748 + memcpy(xb + pos,&reclen,sizeof(int));
18749 + pos +=sizeof(int);
18750 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
18751 + pos+= (namelen+1);
18752 + memcpy(xb + pos,buf,bsize);
18753 + return 0;
18754 +}
18755 +
18756 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
18757 +{
18758 + int pos = nval_find(xb,xb_size,name,NULL);
18759 + int size;
18760 +
18761 + if(pos >= 0 && pos< xb_size){
18762 +
18763 + memcpy(&size,xb +pos,sizeof(int));
18764 + pos+=sizeof(int); /* advance past record length */
18765 + size -= sizeof(int);
18766 +
18767 + /* Advance over name string */
18768 + while(xb[pos] && size > 0 && pos < xb_size){
18769 + pos++;
18770 + size--;
18771 + }
18772 + /*Advance over NUL */
18773 + pos++;
18774 + size--;
18775 +
18776 + if(size <= bsize){
18777 + memcpy(buf,xb + pos,size);
18778 + return size;
18779 + }
18780 +
18781 + }
18782 + if(pos >= 0)
18783 + return -ERANGE;
18784 + else
18785 + return -ENODATA;
18786 +}
18787 +
18788 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
18789 +{
18790 + int pos = 0;
18791 + int size;
18792 + int name_len;
18793 + int ncopied = 0;
18794 + int filled = 0;
18795 +
18796 + memcpy(&size,xb + pos,sizeof(int));
18797 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
18798 + pos+= sizeof(int);
18799 + size-=sizeof(int);
18800 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
18801 + if(ncopied + name_len + 1 < bsize){
18802 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
18803 + buf+= name_len;
18804 + *buf = '\0';
18805 + buf++;
18806 + if(sizeof(YCHAR) > 1){
18807 + *buf = '\0';
18808 + buf++;
18809 + }
18810 + ncopied += (name_len+1);
18811 + } else
18812 + filled = 1;
18813 + pos+=size;
18814 + if(pos < xb_size -sizeof(int))
18815 + memcpy(&size,xb + pos,sizeof(int));
18816 + else
18817 + size = 0;
18818 + }
18819 + return ncopied;
18820 +}
18821 +
18822 +
18823 +int nval_hasvalues(const char *xb, int xb_size)
18824 +{
18825 + return nval_used(xb, xb_size) > 0;
18826 +}
18827 --- /dev/null
18828 +++ b/fs/yaffs2/yaffs_nameval.h
18829 @@ -0,0 +1,25 @@
18830 +/*
18831 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18832 + *
18833 + * Copyright (C) 2002-2010 Aleph One Ltd.
18834 + * for Toby Churchill Ltd and Brightstar Engineering
18835 + *
18836 + * Created by Charles Manning <charles@aleph1.co.uk>
18837 + *
18838 + * This program is free software; you can redistribute it and/or modify
18839 + * it under the terms of the GNU Lesser General Public License version 2.1 as
18840 + * published by the Free Software Foundation.
18841 + *
18842 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
18843 + */
18844 +#ifndef __NAMEVAL_H__
18845 +#define __NAMEVAL_H__
18846 +
18847 +#include "yportenv.h"
18848 +
18849 +int nval_del(char *xb, int xb_size, const YCHAR *name);
18850 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
18851 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
18852 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
18853 +int nval_hasvalues(const char *xb, int xb_size);
18854 +#endif
18855 --- a/fs/yaffs2/yaffs_nand.c
18856 +++ b/fs/yaffs2/yaffs_nand.c
18857 @@ -1,7 +1,7 @@
18858 /*
18859 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18860 *
18861 - * Copyright (C) 2002-2007 Aleph One Ltd.
18862 + * Copyright (C) 2002-2010 Aleph One Ltd.
18863 * for Toby Churchill Ltd and Brightstar Engineering
18864 *
18865 * Created by Charles Manning <charles@aleph1.co.uk>
18866 @@ -11,124 +11,129 @@
18867 * published by the Free Software Foundation.
18868 */
18869
18870 -const char *yaffs_nand_c_version =
18871 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
18872 -
18873 #include "yaffs_nand.h"
18874 #include "yaffs_tagscompat.h"
18875 #include "yaffs_tagsvalidity.h"
18876
18877 #include "yaffs_getblockinfo.h"
18878
18879 -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18880 +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
18881 __u8 *buffer,
18882 - yaffs_ExtendedTags *tags)
18883 + yaffs_ext_tags *tags)
18884 {
18885 int result;
18886 - yaffs_ExtendedTags localTags;
18887 + yaffs_ext_tags localTags;
18888 +
18889 + int realignedChunkInNAND = nand_chunk - dev->chunk_offset;
18890
18891 - int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
18892 + dev->n_page_reads++;
18893
18894 /* If there are no tags provided, use local tags to get prioritised gc working */
18895 if (!tags)
18896 tags = &localTags;
18897
18898 - if (dev->readChunkWithTagsFromNAND)
18899 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
18900 + if (dev->param.read_chunk_tags_fn)
18901 + result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer,
18902 tags);
18903 else
18904 - result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
18905 + result = yaffs_tags_compat_rd(dev,
18906 realignedChunkInNAND,
18907 buffer,
18908 tags);
18909 if (tags &&
18910 - tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
18911 + tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
18912
18913 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
18914 - yaffs_HandleChunkError(dev, bi);
18915 + yaffs_block_info_t *bi;
18916 + bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block);
18917 + yaffs_handle_chunk_error(dev, bi);
18918 }
18919
18920 return result;
18921 }
18922
18923 -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
18924 - int chunkInNAND,
18925 +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
18926 + int nand_chunk,
18927 const __u8 *buffer,
18928 - yaffs_ExtendedTags *tags)
18929 + yaffs_ext_tags *tags)
18930 {
18931 - chunkInNAND -= dev->chunkOffset;
18932 +
18933 + dev->n_page_writes++;
18934 +
18935 + nand_chunk -= dev->chunk_offset;
18936
18937
18938 if (tags) {
18939 - tags->sequenceNumber = dev->sequenceNumber;
18940 - tags->chunkUsed = 1;
18941 - if (!yaffs_ValidateTags(tags)) {
18942 + tags->seq_number = dev->seq_number;
18943 + tags->chunk_used = 1;
18944 + if (!yaffs_validate_tags(tags)) {
18945 T(YAFFS_TRACE_ERROR,
18946 (TSTR("Writing uninitialised tags" TENDSTR)));
18947 YBUG();
18948 }
18949 T(YAFFS_TRACE_WRITE,
18950 - (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
18951 - tags->objectId, tags->chunkId));
18952 + (TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
18953 + tags->obj_id, tags->chunk_id));
18954 } else {
18955 T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
18956 YBUG();
18957 }
18958
18959 - if (dev->writeChunkWithTagsToNAND)
18960 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
18961 + if (dev->param.write_chunk_tags_fn)
18962 + return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
18963 tags);
18964 else
18965 - return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
18966 - chunkInNAND,
18967 + return yaffs_tags_compat_wr(dev,
18968 + nand_chunk,
18969 buffer,
18970 tags);
18971 }
18972
18973 -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
18974 +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no)
18975 {
18976 - blockNo -= dev->blockOffset;
18977 + block_no -= dev->block_offset;
18978 +
18979
18980 -;
18981 - if (dev->markNANDBlockBad)
18982 - return dev->markNANDBlockBad(dev, blockNo);
18983 + if (dev->param.bad_block_fn)
18984 + return dev->param.bad_block_fn(dev, block_no);
18985 else
18986 - return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
18987 + return yaffs_tags_compat_mark_bad(dev, block_no);
18988 }
18989
18990 -int yaffs_QueryInitialBlockState(yaffs_Device *dev,
18991 - int blockNo,
18992 - yaffs_BlockState *state,
18993 - __u32 *sequenceNumber)
18994 +int yaffs_query_init_block_state(yaffs_dev_t *dev,
18995 + int block_no,
18996 + yaffs_block_state_t *state,
18997 + __u32 *seq_number)
18998 {
18999 - blockNo -= dev->blockOffset;
19000 + block_no -= dev->block_offset;
19001
19002 - if (dev->queryNANDBlock)
19003 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
19004 + if (dev->param.query_block_fn)
19005 + return dev->param.query_block_fn(dev, block_no, state, seq_number);
19006 else
19007 - return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
19008 + return yaffs_tags_compat_query_block(dev, block_no,
19009 state,
19010 - sequenceNumber);
19011 + seq_number);
19012 }
19013
19014
19015 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19016 - int blockInNAND)
19017 +int yaffs_erase_block(struct yaffs_dev_s *dev,
19018 + int flash_block)
19019 {
19020 int result;
19021
19022 - blockInNAND -= dev->blockOffset;
19023 + flash_block -= dev->block_offset;
19024
19025 + dev->n_erasures++;
19026
19027 - dev->nBlockErasures++;
19028 - result = dev->eraseBlockInNAND(dev, blockInNAND);
19029 + result = dev->param.erase_fn(dev, flash_block);
19030
19031 return result;
19032 }
19033
19034 -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
19035 +int yaffs_init_nand(struct yaffs_dev_s *dev)
19036 {
19037 - return dev->initialiseNAND(dev);
19038 + if(dev->param.initialise_flash_fn)
19039 + return dev->param.initialise_flash_fn(dev);
19040 + return YAFFS_OK;
19041 }
19042
19043
19044 --- a/fs/yaffs2/yaffs_nandemul2k.h
19045 +++ b/fs/yaffs2/yaffs_nandemul2k.h
19046 @@ -1,7 +1,7 @@
19047 /*
19048 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19049 *
19050 - * Copyright (C) 2002-2007 Aleph One Ltd.
19051 + * Copyright (C) 2002-2010 Aleph One Ltd.
19052 * for Toby Churchill Ltd and Brightstar Engineering
19053 *
19054 * Created by Charles Manning <charles@aleph1.co.uk>
19055 @@ -20,18 +20,18 @@
19056
19057 #include "yaffs_guts.h"
19058
19059 -int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
19060 - int chunkInNAND, const __u8 *data,
19061 - const yaffs_ExtendedTags *tags);
19062 -int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
19063 - int chunkInNAND, __u8 *data,
19064 - yaffs_ExtendedTags *tags);
19065 -int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
19066 -int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
19067 - yaffs_BlockState *state, __u32 *sequenceNumber);
19068 -int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19069 - int blockInNAND);
19070 -int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
19071 +int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev,
19072 + int nand_chunk, const __u8 *data,
19073 + const yaffs_ext_tags *tags);
19074 +int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev,
19075 + int nand_chunk, __u8 *data,
19076 + yaffs_ext_tags *tags);
19077 +int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
19078 +int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
19079 + yaffs_block_state_t *state, __u32 *seq_number);
19080 +int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev,
19081 + int flash_block);
19082 +int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev);
19083 int nandemul2k_GetBytesPerChunk(void);
19084 int nandemul2k_GetChunksPerBlock(void);
19085 int nandemul2k_GetNumberOfBlocks(void);
19086 --- a/fs/yaffs2/yaffs_nand.h
19087 +++ b/fs/yaffs2/yaffs_nand.h
19088 @@ -1,7 +1,7 @@
19089 /*
19090 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19091 *
19092 - * Copyright (C) 2002-2007 Aleph One Ltd.
19093 + * Copyright (C) 2002-2010 Aleph One Ltd.
19094 * for Toby Churchill Ltd and Brightstar Engineering
19095 *
19096 * Created by Charles Manning <charles@aleph1.co.uk>
19097 @@ -19,26 +19,26 @@
19098
19099
19100
19101 -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
19102 +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
19103 __u8 *buffer,
19104 - yaffs_ExtendedTags *tags);
19105 + yaffs_ext_tags *tags);
19106
19107 -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
19108 - int chunkInNAND,
19109 +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
19110 + int nand_chunk,
19111 const __u8 *buffer,
19112 - yaffs_ExtendedTags *tags);
19113 + yaffs_ext_tags *tags);
19114
19115 -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
19116 +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no);
19117
19118 -int yaffs_QueryInitialBlockState(yaffs_Device *dev,
19119 - int blockNo,
19120 - yaffs_BlockState *state,
19121 - unsigned *sequenceNumber);
19122 +int yaffs_query_init_block_state(yaffs_dev_t *dev,
19123 + int block_no,
19124 + yaffs_block_state_t *state,
19125 + unsigned *seq_number);
19126
19127 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19128 - int blockInNAND);
19129 +int yaffs_erase_block(struct yaffs_dev_s *dev,
19130 + int flash_block);
19131
19132 -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
19133 +int yaffs_init_nand(struct yaffs_dev_s *dev);
19134
19135 #endif
19136
19137 --- a/fs/yaffs2/yaffs_packedtags1.c
19138 +++ b/fs/yaffs2/yaffs_packedtags1.c
19139 @@ -1,7 +1,7 @@
19140 /*
19141 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19142 *
19143 - * Copyright (C) 2002-2007 Aleph One Ltd.
19144 + * Copyright (C) 2002-2010 Aleph One Ltd.
19145 * for Toby Churchill Ltd and Brightstar Engineering
19146 *
19147 * Created by Charles Manning <charles@aleph1.co.uk>
19148 @@ -14,37 +14,37 @@
19149 #include "yaffs_packedtags1.h"
19150 #include "yportenv.h"
19151
19152 -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
19153 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t)
19154 {
19155 - pt->chunkId = t->chunkId;
19156 - pt->serialNumber = t->serialNumber;
19157 - pt->byteCount = t->byteCount;
19158 - pt->objectId = t->objectId;
19159 + pt->chunk_id = t->chunk_id;
19160 + pt->serial_number = t->serial_number;
19161 + pt->n_bytes = t->n_bytes;
19162 + pt->obj_id = t->obj_id;
19163 pt->ecc = 0;
19164 - pt->deleted = (t->chunkDeleted) ? 0 : 1;
19165 + pt->deleted = (t->is_deleted) ? 0 : 1;
19166 pt->unusedStuff = 0;
19167 pt->shouldBeFF = 0xFFFFFFFF;
19168
19169 }
19170
19171 -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
19172 +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt)
19173 {
19174 static const __u8 allFF[] =
19175 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
19176 0xff };
19177
19178 if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
19179 - t->blockBad = 0;
19180 + t->block_bad = 0;
19181 if (pt->shouldBeFF != 0xFFFFFFFF)
19182 - t->blockBad = 1;
19183 - t->chunkUsed = 1;
19184 - t->objectId = pt->objectId;
19185 - t->chunkId = pt->chunkId;
19186 - t->byteCount = pt->byteCount;
19187 - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19188 - t->chunkDeleted = (pt->deleted) ? 0 : 1;
19189 - t->serialNumber = pt->serialNumber;
19190 + t->block_bad = 1;
19191 + t->chunk_used = 1;
19192 + t->obj_id = pt->obj_id;
19193 + t->chunk_id = pt->chunk_id;
19194 + t->n_bytes = pt->n_bytes;
19195 + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19196 + t->is_deleted = (pt->deleted) ? 0 : 1;
19197 + t->serial_number = pt->serial_number;
19198 } else {
19199 - memset(t, 0, sizeof(yaffs_ExtendedTags));
19200 + memset(t, 0, sizeof(yaffs_ext_tags));
19201 }
19202 }
19203 --- a/fs/yaffs2/yaffs_packedtags1.h
19204 +++ b/fs/yaffs2/yaffs_packedtags1.h
19205 @@ -1,7 +1,7 @@
19206 /*
19207 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19208 *
19209 - * Copyright (C) 2002-2007 Aleph One Ltd.
19210 + * Copyright (C) 2002-2010 Aleph One Ltd.
19211 * for Toby Churchill Ltd and Brightstar Engineering
19212 *
19213 * Created by Charles Manning <charles@aleph1.co.uk>
19214 @@ -21,10 +21,10 @@
19215 #include "yaffs_guts.h"
19216
19217 typedef struct {
19218 - unsigned chunkId:20;
19219 - unsigned serialNumber:2;
19220 - unsigned byteCount:10;
19221 - unsigned objectId:18;
19222 + unsigned chunk_id:20;
19223 + unsigned serial_number:2;
19224 + unsigned n_bytes:10;
19225 + unsigned obj_id:18;
19226 unsigned ecc:12;
19227 unsigned deleted:1;
19228 unsigned unusedStuff:1;
19229 @@ -32,6 +32,6 @@ typedef struct {
19230
19231 } yaffs_PackedTags1;
19232
19233 -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
19234 -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
19235 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t);
19236 +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt);
19237 #endif
19238 --- a/fs/yaffs2/yaffs_packedtags2.c
19239 +++ b/fs/yaffs2/yaffs_packedtags2.c
19240 @@ -1,7 +1,7 @@
19241 /*
19242 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19243 *
19244 - * Copyright (C) 2002-2007 Aleph One Ltd.
19245 + * Copyright (C) 2002-2010 Aleph One Ltd.
19246 * for Toby Churchill Ltd and Brightstar Engineering
19247 *
19248 * Created by Charles Manning <charles@aleph1.co.uk>
19249 @@ -13,6 +13,7 @@
19250
19251 #include "yaffs_packedtags2.h"
19252 #include "yportenv.h"
19253 +#include "yaffs_trace.h"
19254 #include "yaffs_tagsvalidity.h"
19255
19256 /* This code packs a set of extended tags into a binary structure for
19257 @@ -24,7 +25,7 @@
19258 * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
19259 */
19260
19261 -/* Extra flags applied to chunkId */
19262 +/* Extra flags applied to chunk_id */
19263
19264 #define EXTRA_HEADER_INFO_FLAG 0x80000000
19265 #define EXTRA_SHRINK_FLAG 0x40000000
19266 @@ -42,53 +43,53 @@ static void yaffs_DumpPackedTags2TagsPar
19267 {
19268 T(YAFFS_TRACE_MTD,
19269 (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
19270 - ptt->objectId, ptt->chunkId, ptt->byteCount,
19271 - ptt->sequenceNumber));
19272 + ptt->obj_id, ptt->chunk_id, ptt->n_bytes,
19273 + ptt->seq_number));
19274 }
19275 static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
19276 {
19277 yaffs_DumpPackedTags2TagsPart(&pt->t);
19278 }
19279
19280 -static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
19281 +static void yaffs_DumpTags2(const yaffs_ext_tags *t)
19282 {
19283 T(YAFFS_TRACE_MTD,
19284 (TSTR
19285 ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
19286 - TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
19287 - t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
19288 - t->sequenceNumber));
19289 + TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
19290 + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
19291 + t->seq_number));
19292
19293 }
19294
19295 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
19296 - const yaffs_ExtendedTags *t)
19297 + const yaffs_ext_tags *t)
19298 {
19299 - ptt->chunkId = t->chunkId;
19300 - ptt->sequenceNumber = t->sequenceNumber;
19301 - ptt->byteCount = t->byteCount;
19302 - ptt->objectId = t->objectId;
19303 + ptt->chunk_id = t->chunk_id;
19304 + ptt->seq_number = t->seq_number;
19305 + ptt->n_bytes = t->n_bytes;
19306 + ptt->obj_id = t->obj_id;
19307
19308 - if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
19309 + if (t->chunk_id == 0 && t->extra_available) {
19310 /* Store the extra header info instead */
19311 - /* We save the parent object in the chunkId */
19312 - ptt->chunkId = EXTRA_HEADER_INFO_FLAG
19313 - | t->extraParentObjectId;
19314 - if (t->extraIsShrinkHeader)
19315 - ptt->chunkId |= EXTRA_SHRINK_FLAG;
19316 - if (t->extraShadows)
19317 - ptt->chunkId |= EXTRA_SHADOWS_FLAG;
19318 -
19319 - ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
19320 - ptt->objectId |=
19321 - (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
19322 -
19323 - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
19324 - ptt->byteCount = t->extraEquivalentObjectId;
19325 - else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
19326 - ptt->byteCount = t->extraFileLength;
19327 + /* We save the parent object in the chunk_id */
19328 + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG
19329 + | t->extra_parent_id;
19330 + if (t->extra_is_shrink)
19331 + ptt->chunk_id |= EXTRA_SHRINK_FLAG;
19332 + if (t->extra_shadows)
19333 + ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
19334 +
19335 + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
19336 + ptt->obj_id |=
19337 + (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
19338 +
19339 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
19340 + ptt->n_bytes = t->extra_equiv_id;
19341 + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
19342 + ptt->n_bytes = t->extra_length;
19343 else
19344 - ptt->byteCount = 0;
19345 + ptt->n_bytes = 0;
19346 }
19347
19348 yaffs_DumpPackedTags2TagsPart(ptt);
19349 @@ -96,59 +97,56 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
19350 }
19351
19352
19353 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
19354 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC)
19355 {
19356 yaffs_PackTags2TagsPart(&pt->t, t);
19357
19358 -#ifndef YAFFS_IGNORE_TAGS_ECC
19359 - {
19360 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
19361 + if(tagsECC)
19362 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
19363 sizeof(yaffs_PackedTags2TagsPart),
19364 &pt->ecc);
19365 - }
19366 -#endif
19367 }
19368
19369
19370 -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
19371 +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t,
19372 yaffs_PackedTags2TagsPart *ptt)
19373 {
19374
19375 - memset(t, 0, sizeof(yaffs_ExtendedTags));
19376 + memset(t, 0, sizeof(yaffs_ext_tags));
19377
19378 - yaffs_InitialiseTags(t);
19379 + yaffs_init_tags(t);
19380
19381 - if (ptt->sequenceNumber != 0xFFFFFFFF) {
19382 - t->blockBad = 0;
19383 - t->chunkUsed = 1;
19384 - t->objectId = ptt->objectId;
19385 - t->chunkId = ptt->chunkId;
19386 - t->byteCount = ptt->byteCount;
19387 - t->chunkDeleted = 0;
19388 - t->serialNumber = 0;
19389 - t->sequenceNumber = ptt->sequenceNumber;
19390 + if (ptt->seq_number != 0xFFFFFFFF) {
19391 + t->block_bad = 0;
19392 + t->chunk_used = 1;
19393 + t->obj_id = ptt->obj_id;
19394 + t->chunk_id = ptt->chunk_id;
19395 + t->n_bytes = ptt->n_bytes;
19396 + t->is_deleted = 0;
19397 + t->serial_number = 0;
19398 + t->seq_number = ptt->seq_number;
19399
19400 /* Do extra header info stuff */
19401
19402 - if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
19403 - t->chunkId = 0;
19404 - t->byteCount = 0;
19405 -
19406 - t->extraHeaderInfoAvailable = 1;
19407 - t->extraParentObjectId =
19408 - ptt->chunkId & (~(ALL_EXTRA_FLAGS));
19409 - t->extraIsShrinkHeader =
19410 - (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
19411 - t->extraShadows =
19412 - (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
19413 - t->extraObjectType =
19414 - ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
19415 - t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
19416 + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
19417 + t->chunk_id = 0;
19418 + t->n_bytes = 0;
19419 +
19420 + t->extra_available = 1;
19421 + t->extra_parent_id =
19422 + ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
19423 + t->extra_is_shrink =
19424 + (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
19425 + t->extra_shadows =
19426 + (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
19427 + t->extra_obj_type =
19428 + ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
19429 + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
19430
19431 - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
19432 - t->extraEquivalentObjectId = ptt->byteCount;
19433 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
19434 + t->extra_equiv_id = ptt->n_bytes;
19435 else
19436 - t->extraFileLength = ptt->byteCount;
19437 + t->extra_length = ptt->n_bytes;
19438 }
19439 }
19440
19441 @@ -158,49 +156,43 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
19442 }
19443
19444
19445 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
19446 +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC)
19447 {
19448
19449 - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19450 + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19451
19452 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
19453 - /* Page is in use */
19454 -#ifndef YAFFS_IGNORE_TAGS_ECC
19455 - {
19456 - yaffs_ECCOther ecc;
19457 - int result;
19458 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
19459 - sizeof
19460 - (yaffs_PackedTags2TagsPart),
19461 - &ecc);
19462 - result =
19463 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
19464 - sizeof
19465 - (yaffs_PackedTags2TagsPart),
19466 - &pt->ecc, &ecc);
19467 - switch (result) {
19468 + if (pt->t.seq_number != 0xFFFFFFFF &&
19469 + tagsECC){
19470 + /* Chunk is in use and we need to do ECC */
19471 +
19472 + yaffs_ECCOther ecc;
19473 + int result;
19474 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
19475 + sizeof(yaffs_PackedTags2TagsPart),
19476 + &ecc);
19477 + result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
19478 + sizeof(yaffs_PackedTags2TagsPart),
19479 + &pt->ecc, &ecc);
19480 + switch (result) {
19481 case 0:
19482 - eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19483 + ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19484 break;
19485 case 1:
19486 - eccResult = YAFFS_ECC_RESULT_FIXED;
19487 + ecc_result = YAFFS_ECC_RESULT_FIXED;
19488 break;
19489 case -1:
19490 - eccResult = YAFFS_ECC_RESULT_UNFIXED;
19491 + ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19492 break;
19493 default:
19494 - eccResult = YAFFS_ECC_RESULT_UNKNOWN;
19495 - }
19496 + ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
19497 }
19498 -#endif
19499 }
19500
19501 - yaffs_UnpackTags2TagsPart(t, &pt->t);
19502 + yaffs_unpack_tags2tags_part(t, &pt->t);
19503
19504 - t->eccResult = eccResult;
19505 + t->ecc_result = ecc_result;
19506
19507 yaffs_DumpPackedTags2(pt);
19508 yaffs_DumpTags2(t);
19509 -
19510 }
19511
19512 --- a/fs/yaffs2/yaffs_packedtags2.h
19513 +++ b/fs/yaffs2/yaffs_packedtags2.h
19514 @@ -1,7 +1,7 @@
19515 /*
19516 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19517 *
19518 - * Copyright (C) 2002-2007 Aleph One Ltd.
19519 + * Copyright (C) 2002-2010 Aleph One Ltd.
19520 * for Toby Churchill Ltd and Brightstar Engineering
19521 *
19522 * Created by Charles Manning <charles@aleph1.co.uk>
19523 @@ -22,10 +22,10 @@
19524 #include "yaffs_ecc.h"
19525
19526 typedef struct {
19527 - unsigned sequenceNumber;
19528 - unsigned objectId;
19529 - unsigned chunkId;
19530 - unsigned byteCount;
19531 + unsigned seq_number;
19532 + unsigned obj_id;
19533 + unsigned chunk_id;
19534 + unsigned n_bytes;
19535 } yaffs_PackedTags2TagsPart;
19536
19537 typedef struct {
19538 @@ -34,10 +34,10 @@ typedef struct {
19539 } yaffs_PackedTags2;
19540
19541 /* Full packed tags with ECC, used for oob tags */
19542 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
19543 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
19544 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC);
19545 +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC);
19546
19547 /* Only the tags part (no ECC for use with inband tags */
19548 -void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
19549 -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
19550 +void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t);
19551 +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt);
19552 #endif
19553 --- a/fs/yaffs2/yaffs_qsort.h
19554 +++ b/fs/yaffs2/yaffs_qsort.h
19555 @@ -1,7 +1,7 @@
19556 /*
19557 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19558 *
19559 - * Copyright (C) 2002-2007 Aleph One Ltd.
19560 + * Copyright (C) 2002-2010 Aleph One Ltd.
19561 * for Toby Churchill Ltd and Brightstar Engineering
19562 *
19563 * Created by Charles Manning <charles@aleph1.co.uk>
19564 @@ -17,7 +17,18 @@
19565 #ifndef __YAFFS_QSORT_H__
19566 #define __YAFFS_QSORT_H__
19567
19568 +#ifdef __KERNEL__
19569 +#include <linux/sort.h>
19570 +
19571 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
19572 + int (*cmp)(const void *, const void *)){
19573 + sort(base, total_elems, size, cmp, NULL);
19574 +}
19575 +
19576 +#else
19577 +
19578 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
19579 int (*cmp)(const void *, const void *));
19580
19581 #endif
19582 +#endif
19583 --- a/fs/yaffs2/yaffs_tagscompat.c
19584 +++ b/fs/yaffs2/yaffs_tagscompat.c
19585 @@ -1,7 +1,7 @@
19586 /*
19587 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19588 *
19589 - * Copyright (C) 2002-2007 Aleph One Ltd.
19590 + * Copyright (C) 2002-2010 Aleph One Ltd.
19591 * for Toby Churchill Ltd and Brightstar Engineering
19592 *
19593 * Created by Charles Manning <charles@aleph1.co.uk>
19594 @@ -15,19 +15,20 @@
19595 #include "yaffs_tagscompat.h"
19596 #include "yaffs_ecc.h"
19597 #include "yaffs_getblockinfo.h"
19598 +#include "yaffs_trace.h"
19599
19600 -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
19601 +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk);
19602 #ifdef NOTYET
19603 -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
19604 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
19605 +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk);
19606 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
19607 const __u8 *data,
19608 - const yaffs_Spare *spare);
19609 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
19610 - const yaffs_Spare *spare);
19611 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
19612 + const yaffs_spare *spare);
19613 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
19614 + const yaffs_spare *spare);
19615 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk);
19616 #endif
19617
19618 -static const char yaffs_countBitsTable[256] = {
19619 +static const char yaffs_count_bits_table[256] = {
19620 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
19621 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
19622 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
19623 @@ -46,26 +47,26 @@ static const char yaffs_countBitsTable[2
19624 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
19625 };
19626
19627 -int yaffs_CountBits(__u8 x)
19628 +int yaffs_count_bits(__u8 x)
19629 {
19630 int retVal;
19631 - retVal = yaffs_countBitsTable[x];
19632 + retVal = yaffs_count_bits_table[x];
19633 return retVal;
19634 }
19635
19636 /********** Tags ECC calculations *********/
19637
19638 -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
19639 +void yaffs_calc_ecc(const __u8 *data, yaffs_spare *spare)
19640 {
19641 - yaffs_ECCCalculate(data, spare->ecc1);
19642 - yaffs_ECCCalculate(&data[256], spare->ecc2);
19643 + yaffs_ecc_cacl(data, spare->ecc1);
19644 + yaffs_ecc_cacl(&data[256], spare->ecc2);
19645 }
19646
19647 -void yaffs_CalcTagsECC(yaffs_Tags *tags)
19648 +void yaffs_calc_tags_ecc(yaffs_tags_t *tags)
19649 {
19650 /* Calculate an ecc */
19651
19652 - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
19653 + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
19654 unsigned i, j;
19655 unsigned ecc = 0;
19656 unsigned bit = 0;
19657 @@ -84,24 +85,24 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
19658
19659 }
19660
19661 -int yaffs_CheckECCOnTags(yaffs_Tags *tags)
19662 +int yaffs_check_tags_ecc(yaffs_tags_t *tags)
19663 {
19664 unsigned ecc = tags->ecc;
19665
19666 - yaffs_CalcTagsECC(tags);
19667 + yaffs_calc_tags_ecc(tags);
19668
19669 ecc ^= tags->ecc;
19670
19671 if (ecc && ecc <= 64) {
19672 /* TODO: Handle the failure better. Retire? */
19673 - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
19674 + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
19675
19676 ecc--;
19677
19678 b[ecc / 8] ^= (1 << (ecc & 7));
19679
19680 /* Now recvalc the ecc */
19681 - yaffs_CalcTagsECC(tags);
19682 + yaffs_calc_tags_ecc(tags);
19683
19684 return 1; /* recovered error */
19685 } else if (ecc) {
19686 @@ -115,76 +116,73 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tag
19687
19688 /********** Tags **********/
19689
19690 -static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
19691 - yaffs_Tags *tagsPtr)
19692 +static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr,
19693 + yaffs_tags_t *tagsPtr)
19694 {
19695 - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
19696 + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
19697
19698 - yaffs_CalcTagsECC(tagsPtr);
19699 + yaffs_calc_tags_ecc(tagsPtr);
19700
19701 - sparePtr->tagByte0 = tu->asBytes[0];
19702 - sparePtr->tagByte1 = tu->asBytes[1];
19703 - sparePtr->tagByte2 = tu->asBytes[2];
19704 - sparePtr->tagByte3 = tu->asBytes[3];
19705 - sparePtr->tagByte4 = tu->asBytes[4];
19706 - sparePtr->tagByte5 = tu->asBytes[5];
19707 - sparePtr->tagByte6 = tu->asBytes[6];
19708 - sparePtr->tagByte7 = tu->asBytes[7];
19709 + sparePtr->tb0 = tu->as_bytes[0];
19710 + sparePtr->tb1 = tu->as_bytes[1];
19711 + sparePtr->tb2 = tu->as_bytes[2];
19712 + sparePtr->tb3 = tu->as_bytes[3];
19713 + sparePtr->tb4 = tu->as_bytes[4];
19714 + sparePtr->tb5 = tu->as_bytes[5];
19715 + sparePtr->tb6 = tu->as_bytes[6];
19716 + sparePtr->tb7 = tu->as_bytes[7];
19717 }
19718
19719 -static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
19720 - yaffs_Tags *tagsPtr)
19721 +static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr,
19722 + yaffs_tags_t *tagsPtr)
19723 {
19724 - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
19725 + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
19726 int result;
19727
19728 - tu->asBytes[0] = sparePtr->tagByte0;
19729 - tu->asBytes[1] = sparePtr->tagByte1;
19730 - tu->asBytes[2] = sparePtr->tagByte2;
19731 - tu->asBytes[3] = sparePtr->tagByte3;
19732 - tu->asBytes[4] = sparePtr->tagByte4;
19733 - tu->asBytes[5] = sparePtr->tagByte5;
19734 - tu->asBytes[6] = sparePtr->tagByte6;
19735 - tu->asBytes[7] = sparePtr->tagByte7;
19736 + tu->as_bytes[0] = sparePtr->tb0;
19737 + tu->as_bytes[1] = sparePtr->tb1;
19738 + tu->as_bytes[2] = sparePtr->tb2;
19739 + tu->as_bytes[3] = sparePtr->tb3;
19740 + tu->as_bytes[4] = sparePtr->tb4;
19741 + tu->as_bytes[5] = sparePtr->tb5;
19742 + tu->as_bytes[6] = sparePtr->tb6;
19743 + tu->as_bytes[7] = sparePtr->tb7;
19744
19745 - result = yaffs_CheckECCOnTags(tagsPtr);
19746 + result = yaffs_check_tags_ecc(tagsPtr);
19747 if (result > 0)
19748 - dev->tagsEccFixed++;
19749 + dev->n_tags_ecc_fixed++;
19750 else if (result < 0)
19751 - dev->tagsEccUnfixed++;
19752 + dev->n_tags_ecc_unfixed++;
19753 }
19754
19755 -static void yaffs_SpareInitialise(yaffs_Spare *spare)
19756 +static void yaffs_spare_init(yaffs_spare *spare)
19757 {
19758 - memset(spare, 0xFF, sizeof(yaffs_Spare));
19759 + memset(spare, 0xFF, sizeof(yaffs_spare));
19760 }
19761
19762 -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
19763 - int chunkInNAND, const __u8 *data,
19764 - yaffs_Spare *spare)
19765 +static int yaffs_wr_nand(struct yaffs_dev_s *dev,
19766 + int nand_chunk, const __u8 *data,
19767 + yaffs_spare *spare)
19768 {
19769 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
19770 + if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
19771 T(YAFFS_TRACE_ERROR,
19772 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
19773 - chunkInNAND));
19774 + nand_chunk));
19775 return YAFFS_FAIL;
19776 }
19777
19778 - dev->nPageWrites++;
19779 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
19780 + return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
19781 }
19782
19783 -static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
19784 - int chunkInNAND,
19785 +static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev,
19786 + int nand_chunk,
19787 __u8 *data,
19788 - yaffs_Spare *spare,
19789 - yaffs_ECCResult *eccResult,
19790 + yaffs_spare *spare,
19791 + yaffs_ecc_result *ecc_result,
19792 int doErrorCorrection)
19793 {
19794 int retVal;
19795 - yaffs_Spare localSpare;
19796 -
19797 - dev->nPageReads++;
19798 + yaffs_spare localSpare;
19799
19800 if (!spare && data) {
19801 /* If we don't have a real spare, then we use a local one. */
19802 @@ -192,107 +190,107 @@ static int yaffs_ReadChunkFromNAND(struc
19803 spare = &localSpare;
19804 }
19805
19806 - if (!dev->useNANDECC) {
19807 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
19808 + if (!dev->param.use_nand_ecc) {
19809 + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
19810 if (data && doErrorCorrection) {
19811 /* Do ECC correction */
19812 /* Todo handle any errors */
19813 - int eccResult1, eccResult2;
19814 + int ecc_result1, ecc_result2;
19815 __u8 calcEcc[3];
19816
19817 - yaffs_ECCCalculate(data, calcEcc);
19818 - eccResult1 =
19819 - yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
19820 - yaffs_ECCCalculate(&data[256], calcEcc);
19821 - eccResult2 =
19822 - yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
19823 + yaffs_ecc_cacl(data, calcEcc);
19824 + ecc_result1 =
19825 + yaffs_ecc_correct(data, spare->ecc1, calcEcc);
19826 + yaffs_ecc_cacl(&data[256], calcEcc);
19827 + ecc_result2 =
19828 + yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc);
19829
19830 - if (eccResult1 > 0) {
19831 + if (ecc_result1 > 0) {
19832 T(YAFFS_TRACE_ERROR,
19833 (TSTR
19834 ("**>>yaffs ecc error fix performed on chunk %d:0"
19835 - TENDSTR), chunkInNAND));
19836 - dev->eccFixed++;
19837 - } else if (eccResult1 < 0) {
19838 + TENDSTR), nand_chunk));
19839 + dev->n_ecc_fixed++;
19840 + } else if (ecc_result1 < 0) {
19841 T(YAFFS_TRACE_ERROR,
19842 (TSTR
19843 ("**>>yaffs ecc error unfixed on chunk %d:0"
19844 - TENDSTR), chunkInNAND));
19845 - dev->eccUnfixed++;
19846 + TENDSTR), nand_chunk));
19847 + dev->n_ecc_unfixed++;
19848 }
19849
19850 - if (eccResult2 > 0) {
19851 + if (ecc_result2 > 0) {
19852 T(YAFFS_TRACE_ERROR,
19853 (TSTR
19854 ("**>>yaffs ecc error fix performed on chunk %d:1"
19855 - TENDSTR), chunkInNAND));
19856 - dev->eccFixed++;
19857 - } else if (eccResult2 < 0) {
19858 + TENDSTR), nand_chunk));
19859 + dev->n_ecc_fixed++;
19860 + } else if (ecc_result2 < 0) {
19861 T(YAFFS_TRACE_ERROR,
19862 (TSTR
19863 ("**>>yaffs ecc error unfixed on chunk %d:1"
19864 - TENDSTR), chunkInNAND));
19865 - dev->eccUnfixed++;
19866 + TENDSTR), nand_chunk));
19867 + dev->n_ecc_unfixed++;
19868 }
19869
19870 - if (eccResult1 || eccResult2) {
19871 + if (ecc_result1 || ecc_result2) {
19872 /* We had a data problem on this page */
19873 - yaffs_HandleReadDataError(dev, chunkInNAND);
19874 + yaffs_handle_rd_data_error(dev, nand_chunk);
19875 }
19876
19877 - if (eccResult1 < 0 || eccResult2 < 0)
19878 - *eccResult = YAFFS_ECC_RESULT_UNFIXED;
19879 - else if (eccResult1 > 0 || eccResult2 > 0)
19880 - *eccResult = YAFFS_ECC_RESULT_FIXED;
19881 + if (ecc_result1 < 0 || ecc_result2 < 0)
19882 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19883 + else if (ecc_result1 > 0 || ecc_result2 > 0)
19884 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
19885 else
19886 - *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19887 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19888 }
19889 } else {
19890 /* Must allocate enough memory for spare+2*sizeof(int) */
19891 /* for ecc results from device. */
19892 - struct yaffs_NANDSpare nspare;
19893 + struct yaffs_nand_spare nspare;
19894
19895 memset(&nspare, 0, sizeof(nspare));
19896
19897 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
19898 - (yaffs_Spare *) &nspare);
19899 - memcpy(spare, &nspare, sizeof(yaffs_Spare));
19900 + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data,
19901 + (yaffs_spare *) &nspare);
19902 + memcpy(spare, &nspare, sizeof(yaffs_spare));
19903 if (data && doErrorCorrection) {
19904 if (nspare.eccres1 > 0) {
19905 T(YAFFS_TRACE_ERROR,
19906 (TSTR
19907 ("**>>mtd ecc error fix performed on chunk %d:0"
19908 - TENDSTR), chunkInNAND));
19909 + TENDSTR), nand_chunk));
19910 } else if (nspare.eccres1 < 0) {
19911 T(YAFFS_TRACE_ERROR,
19912 (TSTR
19913 ("**>>mtd ecc error unfixed on chunk %d:0"
19914 - TENDSTR), chunkInNAND));
19915 + TENDSTR), nand_chunk));
19916 }
19917
19918 if (nspare.eccres2 > 0) {
19919 T(YAFFS_TRACE_ERROR,
19920 (TSTR
19921 ("**>>mtd ecc error fix performed on chunk %d:1"
19922 - TENDSTR), chunkInNAND));
19923 + TENDSTR), nand_chunk));
19924 } else if (nspare.eccres2 < 0) {
19925 T(YAFFS_TRACE_ERROR,
19926 (TSTR
19927 ("**>>mtd ecc error unfixed on chunk %d:1"
19928 - TENDSTR), chunkInNAND));
19929 + TENDSTR), nand_chunk));
19930 }
19931
19932 if (nspare.eccres1 || nspare.eccres2) {
19933 /* We had a data problem on this page */
19934 - yaffs_HandleReadDataError(dev, chunkInNAND);
19935 + yaffs_handle_rd_data_error(dev, nand_chunk);
19936 }
19937
19938 if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
19939 - *eccResult = YAFFS_ECC_RESULT_UNFIXED;
19940 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19941 else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
19942 - *eccResult = YAFFS_ECC_RESULT_FIXED;
19943 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
19944 else
19945 - *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19946 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19947
19948 }
19949 }
19950 @@ -300,17 +298,17 @@ static int yaffs_ReadChunkFromNAND(struc
19951 }
19952
19953 #ifdef NOTYET
19954 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
19955 - int chunkInNAND)
19956 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
19957 + int nand_chunk)
19958 {
19959 static int init;
19960 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
19961 static __u8 data[YAFFS_BYTES_PER_CHUNK];
19962 /* Might as well always allocate the larger size for */
19963 - /* dev->useNANDECC == true; */
19964 - static __u8 spare[sizeof(struct yaffs_NANDSpare)];
19965 + /* dev->param.use_nand_ecc == true; */
19966 + static __u8 spare[sizeof(struct yaffs_nand_spare)];
19967
19968 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
19969 + dev->param.read_chunk_fn(dev, nand_chunk, data, (yaffs_spare *) spare);
19970
19971 if (!init) {
19972 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
19973 @@ -331,14 +329,14 @@ static int yaffs_CheckChunkErased(struct
19974 * Functions for robustisizing
19975 */
19976
19977 -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
19978 +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk)
19979 {
19980 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
19981 + int flash_block = nand_chunk / dev->param.chunks_per_block;
19982
19983 /* Mark the block for retirement */
19984 - yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
19985 + yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1;
19986 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
19987 - (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
19988 + (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
19989
19990 /* TODO:
19991 * Just do a garbage collection on the affected block
19992 @@ -348,44 +346,44 @@ static void yaffs_HandleReadDataError(ya
19993 }
19994
19995 #ifdef NOTYET
19996 -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
19997 +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk)
19998 {
19999 }
20000
20001 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
20002 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
20003 const __u8 *data,
20004 - const yaffs_Spare *spare)
20005 + const yaffs_spare *spare)
20006 {
20007 }
20008
20009 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
20010 - const yaffs_Spare *spare)
20011 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
20012 + const yaffs_spare *spare)
20013 {
20014 }
20015
20016 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
20017 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk)
20018 {
20019 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
20020 + int flash_block = nand_chunk / dev->param.chunks_per_block;
20021
20022 /* Mark the block for retirement */
20023 - yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
20024 + yaffs_get_block_info(dev, flash_block)->needs_retiring = 1;
20025 /* Delete the chunk */
20026 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
20027 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
20028 }
20029
20030 -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
20031 - const yaffs_Spare *s0, const yaffs_Spare *s1)
20032 +static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1,
20033 + const yaffs_spare *s0, const yaffs_spare *s1)
20034 {
20035
20036 if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
20037 - s0->tagByte0 != s1->tagByte0 ||
20038 - s0->tagByte1 != s1->tagByte1 ||
20039 - s0->tagByte2 != s1->tagByte2 ||
20040 - s0->tagByte3 != s1->tagByte3 ||
20041 - s0->tagByte4 != s1->tagByte4 ||
20042 - s0->tagByte5 != s1->tagByte5 ||
20043 - s0->tagByte6 != s1->tagByte6 ||
20044 - s0->tagByte7 != s1->tagByte7 ||
20045 + s0->tb0 != s1->tb0 ||
20046 + s0->tb1 != s1->tb1 ||
20047 + s0->tb2 != s1->tb2 ||
20048 + s0->tb3 != s1->tb3 ||
20049 + s0->tb4 != s1->tb4 ||
20050 + s0->tb5 != s1->tb5 ||
20051 + s0->tb6 != s1->tb6 ||
20052 + s0->tb7 != s1->tb7 ||
20053 s0->ecc1[0] != s1->ecc1[0] ||
20054 s0->ecc1[1] != s1->ecc1[1] ||
20055 s0->ecc1[2] != s1->ecc1[2] ||
20056 @@ -398,53 +396,53 @@ static int yaffs_VerifyCompare(const __u
20057 }
20058 #endif /* NOTYET */
20059
20060 -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
20061 - int chunkInNAND,
20062 +int yaffs_tags_compat_wr(yaffs_dev_t *dev,
20063 + int nand_chunk,
20064 const __u8 *data,
20065 - const yaffs_ExtendedTags *eTags)
20066 + const yaffs_ext_tags *eTags)
20067 {
20068 - yaffs_Spare spare;
20069 - yaffs_Tags tags;
20070 + yaffs_spare spare;
20071 + yaffs_tags_t tags;
20072
20073 - yaffs_SpareInitialise(&spare);
20074 + yaffs_spare_init(&spare);
20075
20076 - if (eTags->chunkDeleted)
20077 - spare.pageStatus = 0;
20078 + if (eTags->is_deleted)
20079 + spare.page_status = 0;
20080 else {
20081 - tags.objectId = eTags->objectId;
20082 - tags.chunkId = eTags->chunkId;
20083 + tags.obj_id = eTags->obj_id;
20084 + tags.chunk_id = eTags->chunk_id;
20085
20086 - tags.byteCountLSB = eTags->byteCount & 0x3ff;
20087 + tags.n_bytes_lsb = eTags->n_bytes & 0x3ff;
20088
20089 - if (dev->nDataBytesPerChunk >= 1024)
20090 - tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
20091 + if (dev->data_bytes_per_chunk >= 1024)
20092 + tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3;
20093 else
20094 - tags.byteCountMSB = 3;
20095 + tags.n_bytes_msb = 3;
20096
20097
20098 - tags.serialNumber = eTags->serialNumber;
20099 + tags.serial_number = eTags->serial_number;
20100
20101 - if (!dev->useNANDECC && data)
20102 - yaffs_CalcECC(data, &spare);
20103 + if (!dev->param.use_nand_ecc && data)
20104 + yaffs_calc_ecc(data, &spare);
20105
20106 - yaffs_LoadTagsIntoSpare(&spare, &tags);
20107 + yaffs_load_tags_to_spare(&spare, &tags);
20108
20109 }
20110
20111 - return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
20112 + return yaffs_wr_nand(dev, nand_chunk, data, &spare);
20113 }
20114
20115 -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
20116 - int chunkInNAND,
20117 +int yaffs_tags_compat_rd(yaffs_dev_t *dev,
20118 + int nand_chunk,
20119 __u8 *data,
20120 - yaffs_ExtendedTags *eTags)
20121 + yaffs_ext_tags *eTags)
20122 {
20123
20124 - yaffs_Spare spare;
20125 - yaffs_Tags tags;
20126 - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
20127 + yaffs_spare spare;
20128 + yaffs_tags_t tags;
20129 + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
20130
20131 - static yaffs_Spare spareFF;
20132 + static yaffs_spare spareFF;
20133 static int init;
20134
20135 if (!init) {
20136 @@ -452,33 +450,33 @@ int yaffs_TagsCompatabilityReadChunkWith
20137 init = 1;
20138 }
20139
20140 - if (yaffs_ReadChunkFromNAND
20141 - (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
20142 + if (yaffs_rd_chunk_nand
20143 + (dev, nand_chunk, data, &spare, &ecc_result, 1)) {
20144 /* eTags may be NULL */
20145 if (eTags) {
20146
20147 int deleted =
20148 - (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
20149 + (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
20150
20151 - eTags->chunkDeleted = deleted;
20152 - eTags->eccResult = eccResult;
20153 - eTags->blockBad = 0; /* We're reading it */
20154 + eTags->is_deleted = deleted;
20155 + eTags->ecc_result = ecc_result;
20156 + eTags->block_bad = 0; /* We're reading it */
20157 /* therefore it is not a bad block */
20158 - eTags->chunkUsed =
20159 + eTags->chunk_used =
20160 (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
20161 0) ? 1 : 0;
20162
20163 - if (eTags->chunkUsed) {
20164 - yaffs_GetTagsFromSpare(dev, &spare, &tags);
20165 + if (eTags->chunk_used) {
20166 + yaffs_get_tags_from_spare(dev, &spare, &tags);
20167
20168 - eTags->objectId = tags.objectId;
20169 - eTags->chunkId = tags.chunkId;
20170 - eTags->byteCount = tags.byteCountLSB;
20171 + eTags->obj_id = tags.obj_id;
20172 + eTags->chunk_id = tags.chunk_id;
20173 + eTags->n_bytes = tags.n_bytes_lsb;
20174
20175 - if (dev->nDataBytesPerChunk >= 1024)
20176 - eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
20177 + if (dev->data_bytes_per_chunk >= 1024)
20178 + eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10);
20179
20180 - eTags->serialNumber = tags.serialNumber;
20181 + eTags->serial_number = tags.serial_number;
20182 }
20183 }
20184
20185 @@ -488,49 +486,49 @@ int yaffs_TagsCompatabilityReadChunkWith
20186 }
20187 }
20188
20189 -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
20190 - int blockInNAND)
20191 +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
20192 + int flash_block)
20193 {
20194
20195 - yaffs_Spare spare;
20196 + yaffs_spare spare;
20197
20198 - memset(&spare, 0xff, sizeof(yaffs_Spare));
20199 + memset(&spare, 0xff, sizeof(yaffs_spare));
20200
20201 - spare.blockStatus = 'Y';
20202 + spare.block_status = 'Y';
20203
20204 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
20205 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
20206 &spare);
20207 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
20208 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
20209 NULL, &spare);
20210
20211 return YAFFS_OK;
20212
20213 }
20214
20215 -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
20216 - int blockNo,
20217 - yaffs_BlockState *state,
20218 - __u32 *sequenceNumber)
20219 +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
20220 + int block_no,
20221 + yaffs_block_state_t *state,
20222 + __u32 *seq_number)
20223 {
20224
20225 - yaffs_Spare spare0, spare1;
20226 - static yaffs_Spare spareFF;
20227 + yaffs_spare spare0, spare1;
20228 + static yaffs_spare spareFF;
20229 static int init;
20230 - yaffs_ECCResult dummy;
20231 + yaffs_ecc_result dummy;
20232
20233 if (!init) {
20234 memset(&spareFF, 0xFF, sizeof(spareFF));
20235 init = 1;
20236 }
20237
20238 - *sequenceNumber = 0;
20239 + *seq_number = 0;
20240
20241 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
20242 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
20243 &spare0, &dummy, 1);
20244 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
20245 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL,
20246 &spare1, &dummy, 1);
20247
20248 - if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
20249 + if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7)
20250 *state = YAFFS_BLOCK_STATE_DEAD;
20251 else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
20252 *state = YAFFS_BLOCK_STATE_EMPTY;
20253 --- a/fs/yaffs2/yaffs_tagscompat.h
20254 +++ b/fs/yaffs2/yaffs_tagscompat.h
20255 @@ -1,7 +1,7 @@
20256 /*
20257 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20258 *
20259 - * Copyright (C) 2002-2007 Aleph One Ltd.
20260 + * Copyright (C) 2002-2010 Aleph One Ltd.
20261 * for Toby Churchill Ltd and Brightstar Engineering
20262 *
20263 * Created by Charles Manning <charles@aleph1.co.uk>
20264 @@ -17,23 +17,23 @@
20265 #define __YAFFS_TAGSCOMPAT_H__
20266
20267 #include "yaffs_guts.h"
20268 -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
20269 - int chunkInNAND,
20270 +int yaffs_tags_compat_wr(yaffs_dev_t *dev,
20271 + int nand_chunk,
20272 const __u8 *data,
20273 - const yaffs_ExtendedTags *tags);
20274 -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
20275 - int chunkInNAND,
20276 + const yaffs_ext_tags *tags);
20277 +int yaffs_tags_compat_rd(yaffs_dev_t *dev,
20278 + int nand_chunk,
20279 __u8 *data,
20280 - yaffs_ExtendedTags *tags);
20281 -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
20282 - int blockNo);
20283 -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
20284 - int blockNo,
20285 - yaffs_BlockState *state,
20286 - __u32 *sequenceNumber);
20287 + yaffs_ext_tags *tags);
20288 +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
20289 + int block_no);
20290 +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
20291 + int block_no,
20292 + yaffs_block_state_t *state,
20293 + __u32 *seq_number);
20294
20295 -void yaffs_CalcTagsECC(yaffs_Tags *tags);
20296 -int yaffs_CheckECCOnTags(yaffs_Tags *tags);
20297 -int yaffs_CountBits(__u8 byte);
20298 +void yaffs_calc_tags_ecc(yaffs_tags_t *tags);
20299 +int yaffs_check_tags_ecc(yaffs_tags_t *tags);
20300 +int yaffs_count_bits(__u8 byte);
20301
20302 #endif
20303 --- a/fs/yaffs2/yaffs_tagsvalidity.c
20304 +++ b/fs/yaffs2/yaffs_tagsvalidity.c
20305 @@ -1,7 +1,7 @@
20306 /*
20307 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
20308 *
20309 - * Copyright (C) 2002-2007 Aleph One Ltd.
20310 + * Copyright (C) 2002-2010 Aleph One Ltd.
20311 * for Toby Churchill Ltd and Brightstar Engineering
20312 *
20313 * Created by Charles Manning <charles@aleph1.co.uk>
20314 @@ -13,16 +13,16 @@
20315
20316 #include "yaffs_tagsvalidity.h"
20317
20318 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
20319 +void yaffs_init_tags(yaffs_ext_tags *tags)
20320 {
20321 - memset(tags, 0, sizeof(yaffs_ExtendedTags));
20322 - tags->validMarker0 = 0xAAAAAAAA;
20323 - tags->validMarker1 = 0x55555555;
20324 + memset(tags, 0, sizeof(yaffs_ext_tags));
20325 + tags->validity1 = 0xAAAAAAAA;
20326 + tags->validty1 = 0x55555555;
20327 }
20328
20329 -int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
20330 +int yaffs_validate_tags(yaffs_ext_tags *tags)
20331 {
20332 - return (tags->validMarker0 == 0xAAAAAAAA &&
20333 - tags->validMarker1 == 0x55555555);
20334 + return (tags->validity1 == 0xAAAAAAAA &&
20335 + tags->validty1 == 0x55555555);
20336
20337 }
20338 --- a/fs/yaffs2/yaffs_tagsvalidity.h
20339 +++ b/fs/yaffs2/yaffs_tagsvalidity.h
20340 @@ -1,7 +1,7 @@
20341 /*
20342 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20343 *
20344 - * Copyright (C) 2002-2007 Aleph One Ltd.
20345 + * Copyright (C) 2002-2010 Aleph One Ltd.
20346 * for Toby Churchill Ltd and Brightstar Engineering
20347 *
20348 * Created by Charles Manning <charles@aleph1.co.uk>
20349 @@ -19,6 +19,6 @@
20350
20351 #include "yaffs_guts.h"
20352
20353 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
20354 -int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
20355 +void yaffs_init_tags(yaffs_ext_tags *tags);
20356 +int yaffs_validate_tags(yaffs_ext_tags *tags);
20357 #endif
20358 --- /dev/null
20359 +++ b/fs/yaffs2/yaffs_trace.h
20360 @@ -0,0 +1,60 @@
20361 +/*
20362 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20363 + *
20364 + * Copyright (C) 2002-2010 Aleph One Ltd.
20365 + * for Toby Churchill Ltd and Brightstar Engineering
20366 + *
20367 + * Created by Charles Manning <charles@aleph1.co.uk>
20368 + *
20369 + * This program is free software; you can redistribute it and/or modify
20370 + * it under the terms of the GNU Lesser General Public License version 2.1 as
20371 + * published by the Free Software Foundation.
20372 + *
20373 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
20374 + */
20375 +
20376 +
20377 +#ifndef __YTRACE_H__
20378 +#define __YTRACE_H__
20379 +
20380 +extern unsigned int yaffs_trace_mask;
20381 +extern unsigned int yaffs_wr_attempts;
20382 +
20383 +/*
20384 + * Tracing flags.
20385 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
20386 + */
20387 +
20388 +#define YAFFS_TRACE_OS 0x00000002
20389 +#define YAFFS_TRACE_ALLOCATE 0x00000004
20390 +#define YAFFS_TRACE_SCAN 0x00000008
20391 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
20392 +#define YAFFS_TRACE_ERASE 0x00000020
20393 +#define YAFFS_TRACE_GC 0x00000040
20394 +#define YAFFS_TRACE_WRITE 0x00000080
20395 +#define YAFFS_TRACE_TRACING 0x00000100
20396 +#define YAFFS_TRACE_DELETION 0x00000200
20397 +#define YAFFS_TRACE_BUFFERS 0x00000400
20398 +#define YAFFS_TRACE_NANDACCESS 0x00000800
20399 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
20400 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
20401 +#define YAFFS_TRACE_MTD 0x00004000
20402 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
20403 +
20404 +#define YAFFS_TRACE_VERIFY 0x00010000
20405 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
20406 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
20407 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
20408 +
20409 +#define YAFFS_TRACE_SYNC 0x00100000
20410 +#define YAFFS_TRACE_BACKGROUND 0x00200000
20411 +#define YAFFS_TRACE_LOCK 0x00400000
20412 +
20413 +#define YAFFS_TRACE_ERROR 0x40000000
20414 +#define YAFFS_TRACE_BUG 0x80000000
20415 +#define YAFFS_TRACE_ALWAYS 0xF0000000
20416 +
20417 +
20418 +#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
20419 +
20420 +#endif
20421 --- /dev/null
20422 +++ b/fs/yaffs2/yaffs_verify.c
20423 @@ -0,0 +1,626 @@
20424 +/*
20425 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
20426 + *
20427 + * Copyright (C) 2002-2010 Aleph One Ltd.
20428 + * for Toby Churchill Ltd and Brightstar Engineering
20429 + *
20430 + * Created by Charles Manning <charles@aleph1.co.uk>
20431 + *
20432 + * This program is free software; you can redistribute it and/or modify
20433 + * it under the terms of the GNU General Public License version 2 as
20434 + * published by the Free Software Foundation.
20435 + */
20436 +
20437 +
20438 +#include "yaffs_verify.h"
20439 +#include "yaffs_trace.h"
20440 +#include "yaffs_bitmap.h"
20441 +#include "yaffs_getblockinfo.h"
20442 +#include "yaffs_nand.h"
20443 +
20444 +int yaffs_skip_verification(yaffs_dev_t *dev)
20445 +{
20446 + dev=dev;
20447 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
20448 +}
20449 +
20450 +static int yaffs_skip_full_verification(yaffs_dev_t *dev)
20451 +{
20452 + dev=dev;
20453 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
20454 +}
20455 +
20456 +static int yaffs_skip_nand_verification(yaffs_dev_t *dev)
20457 +{
20458 + dev=dev;
20459 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
20460 +}
20461 +
20462 +
20463 +static const char *block_stateName[] = {
20464 +"Unknown",
20465 +"Needs scanning",
20466 +"Scanning",
20467 +"Empty",
20468 +"Allocating",
20469 +"Full",
20470 +"Dirty",
20471 +"Checkpoint",
20472 +"Collecting",
20473 +"Dead"
20474 +};
20475 +
20476 +
20477 +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
20478 +{
20479 + int actuallyUsed;
20480 + int inUse;
20481 +
20482 + if (yaffs_skip_verification(dev))
20483 + return;
20484 +
20485 + /* Report illegal runtime states */
20486 + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
20487 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state));
20488 +
20489 + switch (bi->block_state) {
20490 + case YAFFS_BLOCK_STATE_UNKNOWN:
20491 + case YAFFS_BLOCK_STATE_SCANNING:
20492 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
20493 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
20494 + n, block_stateName[bi->block_state]));
20495 + }
20496 +
20497 + /* Check pages in use and soft deletions are legal */
20498 +
20499 + actuallyUsed = bi->pages_in_use - bi->soft_del_pages;
20500 +
20501 + if (bi->pages_in_use < 0 || bi->pages_in_use > dev->param.chunks_per_block ||
20502 + bi->soft_del_pages < 0 || bi->soft_del_pages > dev->param.chunks_per_block ||
20503 + actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block)
20504 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR),
20505 + n, bi->pages_in_use, bi->soft_del_pages));
20506 +
20507 +
20508 + /* Check chunk bitmap legal */
20509 + inUse = yaffs_count_chunk_bits(dev, n);
20510 + if (inUse != bi->pages_in_use)
20511 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR),
20512 + n, bi->pages_in_use, inUse));
20513 +
20514 +}
20515 +
20516 +
20517 +
20518 +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
20519 +{
20520 + yaffs_verify_blk(dev, bi, n);
20521 +
20522 + /* After collection the block should be in the erased state */
20523 +
20524 + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
20525 + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
20526 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
20527 + n, bi->block_state));
20528 + }
20529 +}
20530 +
20531 +void yaffs_verify_blocks(yaffs_dev_t *dev)
20532 +{
20533 + int i;
20534 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
20535 + int nIllegalBlockStates = 0;
20536 +
20537 + if (yaffs_skip_verification(dev))
20538 + return;
20539 +
20540 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
20541 +
20542 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
20543 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
20544 + yaffs_verify_blk(dev, bi, i);
20545 +
20546 + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
20547 + nBlocksPerState[bi->block_state]++;
20548 + else
20549 + nIllegalBlockStates++;
20550 + }
20551 +
20552 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
20553 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
20554 +
20555 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
20556 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
20557 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
20558 +
20559 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
20560 + T(YAFFS_TRACE_VERIFY,
20561 + (TSTR("%s %d blocks"TENDSTR),
20562 + block_stateName[i], nBlocksPerState[i]));
20563 +
20564 + if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
20565 + T(YAFFS_TRACE_VERIFY,
20566 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
20567 + dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
20568 +
20569 + if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
20570 + T(YAFFS_TRACE_VERIFY,
20571 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
20572 + dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
20573 +
20574 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
20575 + T(YAFFS_TRACE_VERIFY,
20576 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
20577 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
20578 +
20579 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
20580 +
20581 +}
20582 +
20583 +/*
20584 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
20585 + * case those tests will not be performed.
20586 + */
20587 +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck)
20588 +{
20589 + if (obj && yaffs_skip_verification(obj->my_dev))
20590 + return;
20591 +
20592 + if (!(tags && obj && oh)) {
20593 + T(YAFFS_TRACE_VERIFY,
20594 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
20595 + tags, obj, oh));
20596 + return;
20597 + }
20598 +
20599 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
20600 + oh->type > YAFFS_OBJECT_TYPE_MAX)
20601 + T(YAFFS_TRACE_VERIFY,
20602 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
20603 + tags->obj_id, oh->type));
20604 +
20605 + if (tags->obj_id != obj->obj_id)
20606 + T(YAFFS_TRACE_VERIFY,
20607 + (TSTR("Obj %d header mismatch obj_id %d"TENDSTR),
20608 + tags->obj_id, obj->obj_id));
20609 +
20610 +
20611 + /*
20612 + * Check that the object's parent ids match if parentCheck requested.
20613 + *
20614 + * Tests do not apply to the root object.
20615 + */
20616 +
20617 + if (parentCheck && tags->obj_id > 1 && !obj->parent)
20618 + T(YAFFS_TRACE_VERIFY,
20619 + (TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR),
20620 + tags->obj_id, oh->parent_obj_id));
20621 +
20622 + if (parentCheck && obj->parent &&
20623 + oh->parent_obj_id != obj->parent->obj_id &&
20624 + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
20625 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
20626 + T(YAFFS_TRACE_VERIFY,
20627 + (TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR),
20628 + tags->obj_id, oh->parent_obj_id, obj->parent->obj_id));
20629 +
20630 + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
20631 + T(YAFFS_TRACE_VERIFY,
20632 + (TSTR("Obj %d header name is NULL"TENDSTR),
20633 + obj->obj_id));
20634 +
20635 + if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
20636 + T(YAFFS_TRACE_VERIFY,
20637 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
20638 + obj->obj_id));
20639 +}
20640 +
20641 +
20642 +#if 0
20643 +/* Not being used, but don't want to throw away yet */
20644 +int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn,
20645 + __u32 level, int chunk_offset)
20646 +{
20647 + int i;
20648 + yaffs_dev_t *dev = obj->my_dev;
20649 + int ok = 1;
20650 +
20651 + if (tn) {
20652 + if (level > 0) {
20653 +
20654 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
20655 + if (tn->internal[i]) {
20656 + ok = yaffs_verify_tnode_worker(obj,
20657 + tn->internal[i],
20658 + level - 1,
20659 + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
20660 + }
20661 + }
20662 + } else if (level == 0) {
20663 + yaffs_ext_tags tags;
20664 + __u32 obj_id = obj->obj_id;
20665 +
20666 + chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS;
20667 +
20668 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
20669 + __u32 theChunk = yaffs_get_group_base(dev, tn, i);
20670 +
20671 + if (theChunk > 0) {
20672 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */
20673 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
20674 + if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) {
20675 + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
20676 + obj_id, chunk_offset, theChunk,
20677 + tags.obj_id, tags.chunk_id));
20678 + }
20679 + }
20680 + chunk_offset++;
20681 + }
20682 + }
20683 + }
20684 +
20685 + return ok;
20686 +
20687 +}
20688 +
20689 +#endif
20690 +
20691 +void yaffs_verify_file(yaffs_obj_t *obj)
20692 +{
20693 + int requiredTallness;
20694 + int actualTallness;
20695 + __u32 lastChunk;
20696 + __u32 x;
20697 + __u32 i;
20698 + yaffs_dev_t *dev;
20699 + yaffs_ext_tags tags;
20700 + yaffs_tnode_t *tn;
20701 + __u32 obj_id;
20702 +
20703 + if (!obj)
20704 + return;
20705 +
20706 + if (yaffs_skip_verification(obj->my_dev))
20707 + return;
20708 +
20709 + dev = obj->my_dev;
20710 + obj_id = obj->obj_id;
20711 +
20712 + /* Check file size is consistent with tnode depth */
20713 + lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
20714 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
20715 + requiredTallness = 0;
20716 + while (x > 0) {
20717 + x >>= YAFFS_TNODES_INTERNAL_BITS;
20718 + requiredTallness++;
20719 + }
20720 +
20721 + actualTallness = obj->variant.file_variant.top_level;
20722 +
20723 + /* Check that the chunks in the tnode tree are all correct.
20724 + * We do this by scanning through the tnode tree and
20725 + * checking the tags for every chunk match.
20726 + */
20727 +
20728 + if (yaffs_skip_nand_verification(dev))
20729 + return;
20730 +
20731 + for (i = 1; i <= lastChunk; i++) {
20732 + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
20733 +
20734 + if (tn) {
20735 + __u32 theChunk = yaffs_get_group_base(dev, tn, i);
20736 + if (theChunk > 0) {
20737 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */
20738 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
20739 + if (tags.obj_id != obj_id || tags.chunk_id != i) {
20740 + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
20741 + obj_id, i, theChunk,
20742 + tags.obj_id, tags.chunk_id));
20743 + }
20744 + }
20745 + }
20746 + }
20747 +}
20748 +
20749 +
20750 +void yaffs_verify_link(yaffs_obj_t *obj)
20751 +{
20752 + if (obj && yaffs_skip_verification(obj->my_dev))
20753 + return;
20754 +
20755 + /* Verify sane equivalent object */
20756 +}
20757 +
20758 +void yaffs_verify_symlink(yaffs_obj_t *obj)
20759 +{
20760 + if (obj && yaffs_skip_verification(obj->my_dev))
20761 + return;
20762 +
20763 + /* Verify symlink string */
20764 +}
20765 +
20766 +void yaffs_verify_special(yaffs_obj_t *obj)
20767 +{
20768 + if (obj && yaffs_skip_verification(obj->my_dev))
20769 + return;
20770 +}
20771 +
20772 +void yaffs_verify_obj(yaffs_obj_t *obj)
20773 +{
20774 + yaffs_dev_t *dev;
20775 +
20776 + __u32 chunkMin;
20777 + __u32 chunkMax;
20778 +
20779 + __u32 chunk_idOk;
20780 + __u32 chunkInRange;
20781 + __u32 chunkShouldNotBeDeleted;
20782 + __u32 chunkValid;
20783 +
20784 + if (!obj)
20785 + return;
20786 +
20787 + if (obj->being_created)
20788 + return;
20789 +
20790 + dev = obj->my_dev;
20791 +
20792 + if (yaffs_skip_verification(dev))
20793 + return;
20794 +
20795 + /* Check sane object header chunk */
20796 +
20797 + chunkMin = dev->internal_start_block * dev->param.chunks_per_block;
20798 + chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1;
20799 +
20800 + chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax);
20801 + chunk_idOk = chunkInRange || (obj->hdr_chunk == 0);
20802 + chunkValid = chunkInRange &&
20803 + yaffs_check_chunk_bit(dev,
20804 + obj->hdr_chunk / dev->param.chunks_per_block,
20805 + obj->hdr_chunk % dev->param.chunks_per_block);
20806 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
20807 +
20808 + if (!obj->fake &&
20809 + (!chunk_idOk || chunkShouldNotBeDeleted)) {
20810 + T(YAFFS_TRACE_VERIFY,
20811 + (TSTR("Obj %d has chunk_id %d %s %s"TENDSTR),
20812 + obj->obj_id, obj->hdr_chunk,
20813 + chunk_idOk ? "" : ",out of range",
20814 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
20815 + }
20816 +
20817 + if (chunkValid && !yaffs_skip_nand_verification(dev)) {
20818 + yaffs_ext_tags tags;
20819 + yaffs_obj_header *oh;
20820 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
20821 +
20822 + oh = (yaffs_obj_header *)buffer;
20823 +
20824 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer,
20825 + &tags);
20826 +
20827 + yaffs_verify_oh(obj, oh, &tags, 1);
20828 +
20829 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
20830 + }
20831 +
20832 + /* Verify it has a parent */
20833 + if (obj && !obj->fake &&
20834 + (!obj->parent || obj->parent->my_dev != dev)) {
20835 + T(YAFFS_TRACE_VERIFY,
20836 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
20837 + obj->obj_id, obj->parent));
20838 + }
20839 +
20840 + /* Verify parent is a directory */
20841 + if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20842 + T(YAFFS_TRACE_VERIFY,
20843 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
20844 + obj->obj_id, obj->parent->variant_type));
20845 + }
20846 +
20847 + switch (obj->variant_type) {
20848 + case YAFFS_OBJECT_TYPE_FILE:
20849 + yaffs_verify_file(obj);
20850 + break;
20851 + case YAFFS_OBJECT_TYPE_SYMLINK:
20852 + yaffs_verify_symlink(obj);
20853 + break;
20854 + case YAFFS_OBJECT_TYPE_DIRECTORY:
20855 + yaffs_verify_dir(obj);
20856 + break;
20857 + case YAFFS_OBJECT_TYPE_HARDLINK:
20858 + yaffs_verify_link(obj);
20859 + break;
20860 + case YAFFS_OBJECT_TYPE_SPECIAL:
20861 + yaffs_verify_special(obj);
20862 + break;
20863 + case YAFFS_OBJECT_TYPE_UNKNOWN:
20864 + default:
20865 + T(YAFFS_TRACE_VERIFY,
20866 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
20867 + obj->obj_id, obj->variant_type));
20868 + break;
20869 + }
20870 +}
20871 +
20872 +void yaffs_verify_objects(yaffs_dev_t *dev)
20873 +{
20874 + yaffs_obj_t *obj;
20875 + int i;
20876 + struct ylist_head *lh;
20877 +
20878 + if (yaffs_skip_verification(dev))
20879 + return;
20880 +
20881 + /* Iterate through the objects in each hash entry */
20882 +
20883 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
20884 + ylist_for_each(lh, &dev->obj_bucket[i].list) {
20885 + if (lh) {
20886 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
20887 + yaffs_verify_obj(obj);
20888 + }
20889 + }
20890 + }
20891 +}
20892 +
20893 +
20894 +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
20895 +{
20896 + struct ylist_head *lh;
20897 + yaffs_obj_t *listObj;
20898 +
20899 + int count = 0;
20900 +
20901 + if (!obj) {
20902 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
20903 + YBUG();
20904 + return;
20905 + }
20906 +
20907 + if (yaffs_skip_verification(obj->my_dev))
20908 + return;
20909 +
20910 + if (!obj->parent) {
20911 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
20912 + YBUG();
20913 + return;
20914 + }
20915 +
20916 + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20917 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
20918 + YBUG();
20919 + }
20920 +
20921 + /* Iterate through the objects in each hash entry */
20922 +
20923 + ylist_for_each(lh, &obj->parent->variant.dir_variant.children) {
20924 + if (lh) {
20925 + listObj = ylist_entry(lh, yaffs_obj_t, siblings);
20926 + yaffs_verify_obj(listObj);
20927 + if (obj == listObj)
20928 + count++;
20929 + }
20930 + }
20931 +
20932 + if (count != 1) {
20933 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
20934 + YBUG();
20935 + }
20936 +}
20937 +
20938 +void yaffs_verify_dir(yaffs_obj_t *directory)
20939 +{
20940 + struct ylist_head *lh;
20941 + yaffs_obj_t *listObj;
20942 +
20943 + if (!directory) {
20944 + YBUG();
20945 + return;
20946 + }
20947 +
20948 + if (yaffs_skip_full_verification(directory->my_dev))
20949 + return;
20950 +
20951 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20952 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type));
20953 + YBUG();
20954 + }
20955 +
20956 + /* Iterate through the objects in each hash entry */
20957 +
20958 + ylist_for_each(lh, &directory->variant.dir_variant.children) {
20959 + if (lh) {
20960 + listObj = ylist_entry(lh, yaffs_obj_t, siblings);
20961 + if (listObj->parent != directory) {
20962 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
20963 + YBUG();
20964 + }
20965 + yaffs_verify_obj_in_dir(listObj);
20966 + }
20967 + }
20968 +}
20969 +
20970 +static int yaffs_free_verification_failures;
20971 +
20972 +void yaffs_verify_free_chunks(yaffs_dev_t *dev)
20973 +{
20974 + int counted;
20975 + int difference;
20976 +
20977 + if (yaffs_skip_verification(dev))
20978 + return;
20979 +
20980 + counted = yaffs_count_free_chunks(dev);
20981 +
20982 + difference = dev->n_free_chunks - counted;
20983 +
20984 + if (difference) {
20985 + T(YAFFS_TRACE_ALWAYS,
20986 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
20987 + dev->n_free_chunks, counted, difference));
20988 + yaffs_free_verification_failures++;
20989 + }
20990 +}
20991 +
20992 +int yaffs_verify_file_sane(yaffs_obj_t *in)
20993 +{
20994 +#if 0
20995 + int chunk;
20996 + int n_chunks;
20997 + int fSize;
20998 + int failed = 0;
20999 + int obj_id;
21000 + yaffs_tnode_t *tn;
21001 + yaffs_tags_t localTags;
21002 + yaffs_tags_t *tags = &localTags;
21003 + int theChunk;
21004 + int is_deleted;
21005 +
21006 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
21007 + return YAFFS_FAIL;
21008 +
21009 + obj_id = in->obj_id;
21010 + fSize = in->variant.file_variant.file_size;
21011 + n_chunks =
21012 + (fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk;
21013 +
21014 + for (chunk = 1; chunk <= n_chunks; chunk++) {
21015 + tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant,
21016 + chunk);
21017 +
21018 + if (tn) {
21019 +
21020 + theChunk = yaffs_get_group_base(dev, tn, chunk);
21021 +
21022 + if (yaffs_check_chunk_bits
21023 + (dev, theChunk / dev->param.chunks_per_block,
21024 + theChunk % dev->param.chunks_per_block)) {
21025 +
21026 + yaffs_rd_chunk_tags_nand(in->my_dev, theChunk,
21027 + tags,
21028 + &is_deleted);
21029 + if (yaffs_tags_match
21030 + (tags, in->obj_id, chunk, is_deleted)) {
21031 + /* found it; */
21032 +
21033 + }
21034 + } else {
21035 +
21036 + failed = 1;
21037 + }
21038 +
21039 + } else {
21040 + /* T(("No level 0 found for %d\n", chunk)); */
21041 + }
21042 + }
21043 +
21044 + return failed ? YAFFS_FAIL : YAFFS_OK;
21045 +#else
21046 + in=in;
21047 + return YAFFS_OK;
21048 +#endif
21049 +}
21050 --- /dev/null
21051 +++ b/fs/yaffs2/yaffs_verify.h
21052 @@ -0,0 +1,39 @@
21053 +/*
21054 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21055 + *
21056 + * Copyright (C) 2002-2010 Aleph One Ltd.
21057 + * for Toby Churchill Ltd and Brightstar Engineering
21058 + *
21059 + * Created by Charles Manning <charles@aleph1.co.uk>
21060 + *
21061 + * This program is free software; you can redistribute it and/or modify
21062 + * it under the terms of the GNU General Public License version 2 as
21063 + * published by the Free Software Foundation.
21064 + */
21065 +
21066 +#ifndef __YAFFS_VERIFY_H__
21067 +#define __YAFFS_VERIFY_H__
21068 +
21069 +#include "yaffs_guts.h"
21070 +
21071 +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
21072 +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
21073 +void yaffs_verify_blocks(yaffs_dev_t *dev);
21074 +
21075 +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck);
21076 +void yaffs_verify_file(yaffs_obj_t *obj);
21077 +void yaffs_verify_link(yaffs_obj_t *obj);
21078 +void yaffs_verify_symlink(yaffs_obj_t *obj);
21079 +void yaffs_verify_special(yaffs_obj_t *obj);
21080 +void yaffs_verify_obj(yaffs_obj_t *obj);
21081 +void yaffs_verify_objects(yaffs_dev_t *dev);
21082 +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj);
21083 +void yaffs_verify_dir(yaffs_obj_t *directory);
21084 +void yaffs_verify_free_chunks(yaffs_dev_t *dev);
21085 +
21086 +int yaffs_verify_file_sane(yaffs_obj_t *obj);
21087 +
21088 +int yaffs_skip_verification(yaffs_dev_t *dev);
21089 +
21090 +#endif
21091 +
21092 --- /dev/null
21093 +++ b/fs/yaffs2/yaffs_vfs_glue.c
21094 @@ -0,0 +1,3576 @@
21095 +/*
21096 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21097 + *
21098 + * Copyright (C) 2002-2010 Aleph One Ltd.
21099 + * for Toby Churchill Ltd and Brightstar Engineering
21100 + *
21101 + * Created by Charles Manning <charles@aleph1.co.uk>
21102 + * Acknowledgements:
21103 + * Luc van OostenRyck for numerous patches.
21104 + * Nick Bane for numerous patches.
21105 + * Nick Bane for 2.5/2.6 integration.
21106 + * Andras Toth for mknod rdev issue.
21107 + * Michael Fischer for finding the problem with inode inconsistency.
21108 + * Some code bodily lifted from JFFS
21109 + *
21110 + * This program is free software; you can redistribute it and/or modify
21111 + * it under the terms of the GNU General Public License version 2 as
21112 + * published by the Free Software Foundation.
21113 + */
21114 +
21115 +/*
21116 + *
21117 + * This is the file system front-end to YAFFS that hooks it up to
21118 + * the VFS.
21119 + *
21120 + * Special notes:
21121 + * >> 2.4: sb->u.generic_sbp points to the yaffs_dev_t associated with
21122 + * this superblock
21123 + * >> 2.6: sb->s_fs_info points to the yaffs_dev_t associated with this
21124 + * superblock
21125 + * >> inode->u.generic_ip points to the associated yaffs_obj_t.
21126 + */
21127 +
21128 +/*
21129 + * There are two variants of the VFS glue code. This variant should compile
21130 + * for any version of Linux.
21131 + */
21132 +#include <linux/version.h>
21133 +
21134 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
21135 +#define YAFFS_COMPILE_BACKGROUND
21136 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
21137 +#define YAFFS_COMPILE_FREEZER
21138 +#endif
21139 +#endif
21140 +
21141 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
21142 +#define YAFFS_COMPILE_EXPORTFS
21143 +#endif
21144 +
21145 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
21146 +#define YAFFS_USE_SETATTR_COPY
21147 +#define YAFFS_USE_TRUNCATE_SETSIZE
21148 +#endif
21149 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
21150 +#define YAFFS_HAS_EVICT_INODE
21151 +#endif
21152 +
21153 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
21154 +#define YAFFS_NEW_FOLLOW_LINK 1
21155 +#else
21156 +#define YAFFS_NEW_FOLLOW_LINK 0
21157 +#endif
21158 +
21159 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
21160 +#include <linux/config.h>
21161 +#endif
21162 +
21163 +#include <linux/kernel.h>
21164 +#include <linux/module.h>
21165 +#include <linux/slab.h>
21166 +#include <linux/init.h>
21167 +#include <linux/fs.h>
21168 +#include <linux/proc_fs.h>
21169 +#include <linux/smp_lock.h>
21170 +#include <linux/pagemap.h>
21171 +#include <linux/mtd/mtd.h>
21172 +#include <linux/interrupt.h>
21173 +#include <linux/string.h>
21174 +#include <linux/ctype.h>
21175 +
21176 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21177 +#include <linux/namei.h>
21178 +#endif
21179 +
21180 +#ifdef YAFFS_COMPILE_EXPORTFS
21181 +#include <linux/exportfs.h>
21182 +#endif
21183 +
21184 +#ifdef YAFFS_COMPILE_BACKGROUND
21185 +#include <linux/kthread.h>
21186 +#include <linux/delay.h>
21187 +#endif
21188 +#ifdef YAFFS_COMPILE_FREEZER
21189 +#include <linux/freezer.h>
21190 +#endif
21191 +
21192 +#include <asm/div64.h>
21193 +
21194 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21195 +
21196 +#include <linux/statfs.h>
21197 +
21198 +#define UnlockPage(p) unlock_page(p)
21199 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
21200 +
21201 +/* FIXME: use sb->s_id instead ? */
21202 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
21203 +
21204 +#else
21205 +
21206 +#include <linux/locks.h>
21207 +#define BDEVNAME_SIZE 0
21208 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
21209 +
21210 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
21211 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
21212 +#define __user
21213 +#endif
21214 +
21215 +#endif
21216 +
21217 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
21218 +#define YPROC_ROOT (&proc_root)
21219 +#else
21220 +#define YPROC_ROOT NULL
21221 +#endif
21222 +
21223 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
21224 +#define Y_INIT_TIMER(a) init_timer(a)
21225 +#else
21226 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
21227 +#endif
21228 +
21229 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21230 +#define WRITE_SIZE_STR "writesize"
21231 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
21232 +#else
21233 +#define WRITE_SIZE_STR "oobblock"
21234 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
21235 +#endif
21236 +
21237 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
21238 +#define YAFFS_USE_WRITE_BEGIN_END 1
21239 +#else
21240 +#define YAFFS_USE_WRITE_BEGIN_END 0
21241 +#endif
21242 +
21243 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
21244 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
21245 +{
21246 + uint64_t result = partition_size;
21247 + do_div(result, block_size);
21248 + return (uint32_t)result;
21249 +}
21250 +#else
21251 +#define YCALCBLOCKS(s, b) ((s)/(b))
21252 +#endif
21253 +
21254 +#include <linux/uaccess.h>
21255 +#include <linux/mtd/mtd.h>
21256 +
21257 +#include "yportenv.h"
21258 +#include "yaffs_trace.h"
21259 +#include "yaffs_guts.h"
21260 +
21261 +#include "yaffs_linux.h"
21262 +
21263 +#include "yaffs_mtdif.h"
21264 +#include "yaffs_mtdif1.h"
21265 +#include "yaffs_mtdif2.h"
21266 +
21267 +unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
21268 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
21269 +unsigned int yaffs_auto_checkpoint = 1;
21270 +unsigned int yaffs_gc_control = 1;
21271 +unsigned int yaffs_bg_enable = 1;
21272 +
21273 +/* Module Parameters */
21274 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21275 +module_param(yaffs_trace_mask, uint, 0644);
21276 +module_param(yaffs_wr_attempts, uint, 0644);
21277 +module_param(yaffs_auto_checkpoint, uint, 0644);
21278 +module_param(yaffs_gc_control, uint, 0644);
21279 +module_param(yaffs_bg_enable, uint, 0644);
21280 +#else
21281 +MODULE_PARM(yaffs_trace_mask, "i");
21282 +MODULE_PARM(yaffs_wr_attempts, "i");
21283 +MODULE_PARM(yaffs_auto_checkpoint, "i");
21284 +MODULE_PARM(yaffs_gc_control, "i");
21285 +#endif
21286 +
21287 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
21288 +/* use iget and read_inode */
21289 +#define Y_IGET(sb, inum) iget((sb), (inum))
21290 +static void yaffs_read_inode(struct inode *inode);
21291 +
21292 +#else
21293 +/* Call local equivalent */
21294 +#define YAFFS_USE_OWN_IGET
21295 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
21296 +
21297 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
21298 +#endif
21299 +
21300 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
21301 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
21302 +#else
21303 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
21304 +#endif
21305 +
21306 +#define yaffs_InodeToObject(iptr) ((yaffs_obj_t *)(yaffs_InodeToObjectLV(iptr)))
21307 +#define yaffs_dentry_to_obj(dptr) yaffs_InodeToObject((dptr)->d_inode)
21308 +
21309 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21310 +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->s_fs_info)
21311 +#else
21312 +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
21313 +#endif
21314 +
21315 +
21316 +#define update_dir_time(dir) do {\
21317 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
21318 + } while(0)
21319 +
21320 +static void yaffs_put_super(struct super_block *sb);
21321 +
21322 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
21323 + loff_t *pos);
21324 +static ssize_t yaffs_hold_space(struct file *f);
21325 +static void yaffs_release_space(struct file *f);
21326 +
21327 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21328 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
21329 +#else
21330 +static int yaffs_file_flush(struct file *file);
21331 +#endif
21332 +
21333 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
21334 +static int yaffs_sync_object(struct file *file, int datasync);
21335 +#else
21336 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
21337 + int datasync);
21338 +#endif
21339 +
21340 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
21341 +
21342 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21343 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
21344 + struct nameidata *n);
21345 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
21346 + struct nameidata *n);
21347 +#else
21348 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
21349 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
21350 +#endif
21351 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
21352 + struct dentry *dentry);
21353 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
21354 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
21355 + const char *symname);
21356 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
21357 +
21358 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21359 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
21360 + dev_t dev);
21361 +#else
21362 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
21363 + int dev);
21364 +#endif
21365 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
21366 + struct inode *new_dir, struct dentry *new_dentry);
21367 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
21368 +
21369 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21370 +static int yaffs_sync_fs(struct super_block *sb, int wait);
21371 +static void yaffs_write_super(struct super_block *sb);
21372 +#else
21373 +static int yaffs_sync_fs(struct super_block *sb);
21374 +static int yaffs_write_super(struct super_block *sb);
21375 +#endif
21376 +
21377 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21378 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
21379 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21380 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
21381 +#else
21382 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
21383 +#endif
21384 +
21385 +#ifdef YAFFS_HAS_PUT_INODE
21386 +static void yaffs_put_inode(struct inode *inode);
21387 +#endif
21388 +
21389 +#ifdef YAFFS_HAS_EVICT_INODE
21390 +static void yaffs_evict_inode(struct inode *);
21391 +#else
21392 +static void yaffs_delete_inode(struct inode *);
21393 +static void yaffs_clear_inode(struct inode *);
21394 +#endif
21395 +
21396 +static int yaffs_readpage(struct file *file, struct page *page);
21397 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21398 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
21399 +#else
21400 +static int yaffs_writepage(struct page *page);
21401 +#endif
21402 +
21403 +#ifdef CONFIG_YAFFS_XATTR
21404 +int yaffs_setxattr(struct dentry *dentry, const char *name,
21405 + const void *value, size_t size, int flags);
21406 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
21407 + size_t size);
21408 +int yaffs_removexattr(struct dentry *dentry, const char *name);
21409 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
21410 +#endif
21411 +
21412 +
21413 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
21414 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
21415 + loff_t pos, unsigned len, unsigned flags,
21416 + struct page **pagep, void **fsdata);
21417 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
21418 + loff_t pos, unsigned len, unsigned copied,
21419 + struct page *pg, void *fsdadata);
21420 +#else
21421 +static int yaffs_prepare_write(struct file *f, struct page *pg,
21422 + unsigned offset, unsigned to);
21423 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
21424 + unsigned to);
21425 +
21426 +#endif
21427 +
21428 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
21429 + int buflen);
21430 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21431 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
21432 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
21433 +#else
21434 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
21435 +#endif
21436 +
21437 +static void yaffs_touch_super(yaffs_dev_t *dev);
21438 +
21439 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
21440 +
21441 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
21442 +
21443 +
21444 +static struct address_space_operations yaffs_file_address_operations = {
21445 + .readpage = yaffs_readpage,
21446 + .writepage = yaffs_writepage,
21447 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
21448 + .write_begin = yaffs_write_begin,
21449 + .write_end = yaffs_write_end,
21450 +#else
21451 + .prepare_write = yaffs_prepare_write,
21452 + .commit_write = yaffs_commit_write,
21453 +#endif
21454 +};
21455 +
21456 +
21457 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
21458 +static const struct file_operations yaffs_file_operations = {
21459 + .read = do_sync_read,
21460 + .write = do_sync_write,
21461 + .aio_read = generic_file_aio_read,
21462 + .aio_write = generic_file_aio_write,
21463 + .mmap = generic_file_mmap,
21464 + .flush = yaffs_file_flush,
21465 + .fsync = yaffs_sync_object,
21466 + .splice_read = generic_file_splice_read,
21467 + .splice_write = generic_file_splice_write,
21468 + .llseek = generic_file_llseek,
21469 +};
21470 +
21471 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
21472 +
21473 +static const struct file_operations yaffs_file_operations = {
21474 + .read = do_sync_read,
21475 + .write = do_sync_write,
21476 + .aio_read = generic_file_aio_read,
21477 + .aio_write = generic_file_aio_write,
21478 + .mmap = generic_file_mmap,
21479 + .flush = yaffs_file_flush,
21480 + .fsync = yaffs_sync_object,
21481 + .sendfile = generic_file_sendfile,
21482 +};
21483 +
21484 +#else
21485 +
21486 +static const struct file_operations yaffs_file_operations = {
21487 + .read = generic_file_read,
21488 + .write = generic_file_write,
21489 + .mmap = generic_file_mmap,
21490 + .flush = yaffs_file_flush,
21491 + .fsync = yaffs_sync_object,
21492 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21493 + .sendfile = generic_file_sendfile,
21494 +#endif
21495 +};
21496 +#endif
21497 +
21498 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
21499 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
21500 +{
21501 + void * kaddr = kmap_atomic(page, KM_USER0);
21502 + memset(kaddr + start, 0, end - start);
21503 + kunmap_atomic(kaddr, KM_USER0);
21504 + flush_dcache_page(page);
21505 +}
21506 +#endif
21507 +
21508 +
21509 +static const struct inode_operations yaffs_file_inode_operations = {
21510 + .setattr = yaffs_setattr,
21511 +#ifdef CONFIG_YAFFS_XATTR
21512 + .setxattr = yaffs_setxattr,
21513 + .getxattr = yaffs_getxattr,
21514 + .listxattr = yaffs_listxattr,
21515 + .removexattr = yaffs_removexattr,
21516 +#endif
21517 +};
21518 +
21519 +static const struct inode_operations yaffs_symlink_inode_operations = {
21520 + .readlink = yaffs_readlink,
21521 + .follow_link = yaffs_follow_link,
21522 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21523 + .put_link = yaffs_put_link,
21524 +#endif
21525 + .setattr = yaffs_setattr,
21526 +#ifdef CONFIG_YAFFS_XATTR
21527 + .setxattr = yaffs_setxattr,
21528 + .getxattr = yaffs_getxattr,
21529 + .listxattr = yaffs_listxattr,
21530 + .removexattr = yaffs_removexattr,
21531 +#endif
21532 +};
21533 +
21534 +static const struct inode_operations yaffs_dir_inode_operations = {
21535 + .create = yaffs_create,
21536 + .lookup = yaffs_lookup,
21537 + .link = yaffs_link,
21538 + .unlink = yaffs_unlink,
21539 + .symlink = yaffs_symlink,
21540 + .mkdir = yaffs_mkdir,
21541 + .rmdir = yaffs_unlink,
21542 + .mknod = yaffs_mknod,
21543 + .rename = yaffs_rename,
21544 + .setattr = yaffs_setattr,
21545 +#ifdef CONFIG_YAFFS_XATTR
21546 + .setxattr = yaffs_setxattr,
21547 + .getxattr = yaffs_getxattr,
21548 + .listxattr = yaffs_listxattr,
21549 + .removexattr = yaffs_removexattr,
21550 +#endif
21551 +};
21552 +
21553 +static const struct file_operations yaffs_dir_operations = {
21554 + .read = generic_read_dir,
21555 + .readdir = yaffs_readdir,
21556 + .fsync = yaffs_sync_object,
21557 + .llseek = yaffs_dir_llseek,
21558 +};
21559 +
21560 +static const struct super_operations yaffs_super_ops = {
21561 + .statfs = yaffs_statfs,
21562 +
21563 +#ifndef YAFFS_USE_OWN_IGET
21564 + .read_inode = yaffs_read_inode,
21565 +#endif
21566 +#ifdef YAFFS_HAS_PUT_INODE
21567 + .put_inode = yaffs_put_inode,
21568 +#endif
21569 + .put_super = yaffs_put_super,
21570 +#ifdef YAFFS_HAS_EVICT_INODE
21571 + .evict_inode = yaffs_evict_inode,
21572 +#else
21573 + .delete_inode = yaffs_delete_inode,
21574 + .clear_inode = yaffs_clear_inode,
21575 +#endif
21576 + .sync_fs = yaffs_sync_fs,
21577 + .write_super = yaffs_write_super,
21578 +};
21579 +
21580 +
21581 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
21582 +{
21583 +#ifdef YAFFS_USE_SETATTR_COPY
21584 + setattr_copy(inode,attr);
21585 + return 0;
21586 +#else
21587 + return inode_setattr(inode, attr);
21588 +#endif
21589 +
21590 +}
21591 +
21592 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
21593 +{
21594 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
21595 + truncate_setsize(inode,newsize);
21596 + return 0;
21597 +#else
21598 + truncate_inode_pages(&inode->i_data,newsize);
21599 + return 0;
21600 +#endif
21601 +
21602 +}
21603 +
21604 +static unsigned yaffs_gc_control_callback(yaffs_dev_t *dev)
21605 +{
21606 + return yaffs_gc_control;
21607 +}
21608 +
21609 +static void yaffs_gross_lock(yaffs_dev_t *dev)
21610 +{
21611 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
21612 + down(&(yaffs_dev_to_lc(dev)->grossLock));
21613 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
21614 +}
21615 +
21616 +static void yaffs_gross_unlock(yaffs_dev_t *dev)
21617 +{
21618 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
21619 + up(&(yaffs_dev_to_lc(dev)->grossLock));
21620 +}
21621 +
21622 +#ifdef YAFFS_COMPILE_EXPORTFS
21623 +
21624 +static struct inode *
21625 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
21626 +{
21627 + return Y_IGET(sb, ino);
21628 +}
21629 +
21630 +static struct dentry *
21631 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
21632 +{
21633 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
21634 +}
21635 +
21636 +static struct dentry *
21637 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
21638 +{
21639 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
21640 +}
21641 +
21642 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
21643 +{
21644 +
21645 + struct super_block *sb = dentry->d_inode->i_sb;
21646 + struct dentry *parent = ERR_PTR(-ENOENT);
21647 + struct inode *inode;
21648 + unsigned long parent_ino;
21649 + yaffs_obj_t *d_obj;
21650 + yaffs_obj_t *parent_obj;
21651 +
21652 + d_obj = yaffs_InodeToObject(dentry->d_inode);
21653 +
21654 + if (d_obj) {
21655 + parent_obj = d_obj->parent;
21656 + if (parent_obj) {
21657 + parent_ino = yaffs_get_obj_inode(parent_obj);
21658 + inode = Y_IGET(sb, parent_ino);
21659 +
21660 + if (IS_ERR(inode)) {
21661 + parent = ERR_CAST(inode);
21662 + } else {
21663 + parent = d_obtain_alias(inode);
21664 + if (!IS_ERR(parent)) {
21665 + parent = ERR_PTR(-ENOMEM);
21666 + iput(inode);
21667 + }
21668 + }
21669 + }
21670 + }
21671 +
21672 + return parent;
21673 +}
21674 +
21675 +/* Just declare a zero structure as a NULL value implies
21676 + * using the default functions of exportfs.
21677 + */
21678 +
21679 +static struct export_operations yaffs_export_ops =
21680 +{
21681 + .fh_to_dentry = yaffs2_fh_to_dentry,
21682 + .fh_to_parent = yaffs2_fh_to_parent,
21683 + .get_parent = yaffs2_get_parent,
21684 +} ;
21685 +
21686 +#endif
21687 +
21688 +/*-----------------------------------------------------------------*/
21689 +/* Directory search context allows us to unlock access to yaffs during
21690 + * filldir without causing problems with the directory being modified.
21691 + * This is similar to the tried and tested mechanism used in yaffs direct.
21692 + *
21693 + * A search context iterates along a doubly linked list of siblings in the
21694 + * directory. If the iterating object is deleted then this would corrupt
21695 + * the list iteration, likely causing a crash. The search context avoids
21696 + * this by using the remove_obj_fn to move the search context to the
21697 + * next object before the object is deleted.
21698 + *
21699 + * Many readdirs (and thus seach conexts) may be alive simulateously so
21700 + * each yaffs_dev_t has a list of these.
21701 + *
21702 + * A seach context lives for the duration of a readdir.
21703 + *
21704 + * All these functions must be called while yaffs is locked.
21705 + */
21706 +
21707 +struct yaffs_SearchContext {
21708 + yaffs_dev_t *dev;
21709 + yaffs_obj_t *dirObj;
21710 + yaffs_obj_t *nextReturn;
21711 + struct ylist_head others;
21712 +};
21713 +
21714 +/*
21715 + * yaffs_NewSearch() creates a new search context, initialises it and
21716 + * adds it to the device's search context list.
21717 + *
21718 + * Called at start of readdir.
21719 + */
21720 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_obj_t *dir)
21721 +{
21722 + yaffs_dev_t *dev = dir->my_dev;
21723 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
21724 + if(sc){
21725 + sc->dirObj = dir;
21726 + sc->dev = dev;
21727 + if( ylist_empty(&sc->dirObj->variant.dir_variant.children))
21728 + sc->nextReturn = NULL;
21729 + else
21730 + sc->nextReturn = ylist_entry(
21731 + dir->variant.dir_variant.children.next,
21732 + yaffs_obj_t,siblings);
21733 + YINIT_LIST_HEAD(&sc->others);
21734 + ylist_add(&sc->others,&(yaffs_dev_to_lc(dev)->searchContexts));
21735 + }
21736 + return sc;
21737 +}
21738 +
21739 +/*
21740 + * yaffs_search_end() disposes of a search context and cleans up.
21741 + */
21742 +static void yaffs_search_end(struct yaffs_SearchContext * sc)
21743 +{
21744 + if(sc){
21745 + ylist_del(&sc->others);
21746 + YFREE(sc);
21747 + }
21748 +}
21749 +
21750 +/*
21751 + * yaffs_search_advance() moves a search context to the next object.
21752 + * Called when the search iterates or when an object removal causes
21753 + * the search context to be moved to the next object.
21754 + */
21755 +static void yaffs_search_advance(struct yaffs_SearchContext *sc)
21756 +{
21757 + if(!sc)
21758 + return;
21759 +
21760 + if( sc->nextReturn == NULL ||
21761 + ylist_empty(&sc->dirObj->variant.dir_variant.children))
21762 + sc->nextReturn = NULL;
21763 + else {
21764 + struct ylist_head *next = sc->nextReturn->siblings.next;
21765 +
21766 + if( next == &sc->dirObj->variant.dir_variant.children)
21767 + sc->nextReturn = NULL; /* end of list */
21768 + else
21769 + sc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
21770 + }
21771 +}
21772 +
21773 +/*
21774 + * yaffs_remove_obj_callback() is called when an object is unlinked.
21775 + * We check open search contexts and advance any which are currently
21776 + * on the object being iterated.
21777 + */
21778 +static void yaffs_remove_obj_callback(yaffs_obj_t *obj)
21779 +{
21780 +
21781 + struct ylist_head *i;
21782 + struct yaffs_SearchContext *sc;
21783 + struct ylist_head *search_contexts = &(yaffs_dev_to_lc(obj->my_dev)->searchContexts);
21784 +
21785 +
21786 + /* Iterate through the directory search contexts.
21787 + * If any are currently on the object being removed, then advance
21788 + * the search context to the next object to prevent a hanging pointer.
21789 + */
21790 + ylist_for_each(i, search_contexts) {
21791 + if (i) {
21792 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
21793 + if(sc->nextReturn == obj)
21794 + yaffs_search_advance(sc);
21795 + }
21796 + }
21797 +
21798 +}
21799 +
21800 +
21801 +/*-----------------------------------------------------------------*/
21802 +
21803 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
21804 + int buflen)
21805 +{
21806 + unsigned char *alias;
21807 + int ret;
21808 +
21809 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
21810 +
21811 + yaffs_gross_lock(dev);
21812 +
21813 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
21814 +
21815 + yaffs_gross_unlock(dev);
21816 +
21817 + if (!alias)
21818 + return -ENOMEM;
21819 +
21820 + ret = vfs_readlink(dentry, buffer, buflen, alias);
21821 + kfree(alias);
21822 + return ret;
21823 +}
21824 +
21825 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21826 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
21827 +#else
21828 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
21829 +#endif
21830 +{
21831 + unsigned char *alias;
21832 + int ret;
21833 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
21834 +
21835 + yaffs_gross_lock(dev);
21836 +
21837 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
21838 + yaffs_gross_unlock(dev);
21839 +
21840 + if (!alias) {
21841 + ret = -ENOMEM;
21842 + goto out;
21843 + }
21844 +
21845 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21846 + nd_set_link(nd, alias);
21847 + ret = (int)alias;
21848 +out:
21849 + return ERR_PTR(ret);
21850 +#else
21851 + ret = vfs_follow_link(nd, alias);
21852 + kfree(alias);
21853 +out:
21854 + return ret;
21855 +#endif
21856 +}
21857 +
21858 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21859 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
21860 + kfree(alias);
21861 +}
21862 +#endif
21863 +
21864 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
21865 + yaffs_obj_t *obj);
21866 +
21867 +/*
21868 + * Lookup is used to find objects in the fs
21869 + */
21870 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21871 +
21872 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
21873 + struct nameidata *n)
21874 +#else
21875 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
21876 +#endif
21877 +{
21878 + yaffs_obj_t *obj;
21879 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
21880 +
21881 + yaffs_dev_t *dev = yaffs_InodeToObject(dir)->my_dev;
21882 +
21883 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
21884 + yaffs_gross_lock(dev);
21885 +
21886 + T(YAFFS_TRACE_OS,
21887 + (TSTR("yaffs_lookup for %d:%s\n"),
21888 + yaffs_InodeToObject(dir)->obj_id, dentry->d_name.name));
21889 +
21890 + obj = yaffs_find_by_name(yaffs_InodeToObject(dir),
21891 + dentry->d_name.name);
21892 +
21893 + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
21894 +
21895 + /* Can't hold gross lock when calling yaffs_get_inode() */
21896 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
21897 + yaffs_gross_unlock(dev);
21898 +
21899 + if (obj) {
21900 + T(YAFFS_TRACE_OS,
21901 + (TSTR("yaffs_lookup found %d\n"), obj->obj_id));
21902 +
21903 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
21904 +
21905 + if (inode) {
21906 + T(YAFFS_TRACE_OS,
21907 + (TSTR("yaffs_loookup dentry \n")));
21908 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
21909 + * d_add even if NULL inode */
21910 +#if 0
21911 + /*dget(dentry); // try to solve directory bug */
21912 + d_add(dentry, inode);
21913 +
21914 + /* return dentry; */
21915 + return NULL;
21916 +#endif
21917 + }
21918 +
21919 + } else {
21920 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
21921 +
21922 + }
21923 +
21924 +/* added NCB for 2.5/6 compatability - forces add even if inode is
21925 + * NULL which creates dentry hash */
21926 + d_add(dentry, inode);
21927 +
21928 + return NULL;
21929 +}
21930 +
21931 +
21932 +#ifdef YAFFS_HAS_PUT_INODE
21933 +
21934 +/* For now put inode is just for debugging
21935 + * Put inode is called when the inode **structure** is put.
21936 + */
21937 +static void yaffs_put_inode(struct inode *inode)
21938 +{
21939 + T(YAFFS_TRACE_OS,
21940 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
21941 + atomic_read(&inode->i_count)));
21942 +
21943 +}
21944 +#endif
21945 +
21946 +
21947 +static void yaffs_unstitch_obj(struct inode *inode, yaffs_obj_t *obj)
21948 +{
21949 + /* Clear the association between the inode and
21950 + * the yaffs_obj_t.
21951 + */
21952 + obj->my_inode = NULL;
21953 + yaffs_InodeToObjectLV(inode) = NULL;
21954 +
21955 + /* If the object freeing was deferred, then the real
21956 + * free happens now.
21957 + * This should fix the inode inconsistency problem.
21958 + */
21959 + yaffs_handle_defered_free(obj);
21960 +}
21961 +
21962 +#ifdef YAFFS_HAS_EVICT_INODE
21963 +/* yaffs_evict_inode combines into one operation what was previously done in
21964 + * yaffs_clear_inode() and yaffs_delete_inode()
21965 + *
21966 + */
21967 +static void yaffs_evict_inode( struct inode *inode)
21968 +{
21969 + yaffs_obj_t *obj;
21970 + yaffs_dev_t *dev;
21971 + int deleteme = 0;
21972 +
21973 + obj = yaffs_InodeToObject(inode);
21974 +
21975 + T(YAFFS_TRACE_OS,
21976 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
21977 + atomic_read(&inode->i_count),
21978 + obj ? "object exists" : "null object"));
21979 +
21980 + if (!inode->i_nlink && !is_bad_inode(inode))
21981 + deleteme = 1;
21982 + truncate_inode_pages(&inode->i_data,0);
21983 + end_writeback(inode);
21984 +
21985 + if(deleteme && obj){
21986 + dev = obj->my_dev;
21987 + yaffs_gross_lock(dev);
21988 + yaffs_del_obj(obj);
21989 + yaffs_gross_unlock(dev);
21990 + }
21991 + if (obj) {
21992 + dev = obj->my_dev;
21993 + yaffs_gross_lock(dev);
21994 + yaffs_unstitch_obj(inode,obj);
21995 + yaffs_gross_unlock(dev);
21996 + }
21997 +
21998 +
21999 +}
22000 +#else
22001 +
22002 +/* clear is called to tell the fs to release any per-inode data it holds.
22003 + * The object might still exist on disk and is just being thrown out of the cache
22004 + * or else the object has actually been deleted and we're being called via
22005 + * the chain
22006 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
22007 + */
22008 +
22009 +static void yaffs_clear_inode(struct inode *inode)
22010 +{
22011 + yaffs_obj_t *obj;
22012 + yaffs_dev_t *dev;
22013 +
22014 + obj = yaffs_InodeToObject(inode);
22015 +
22016 + T(YAFFS_TRACE_OS,
22017 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22018 + atomic_read(&inode->i_count),
22019 + obj ? "object exists" : "null object"));
22020 +
22021 + if (obj) {
22022 + dev = obj->my_dev;
22023 + yaffs_gross_lock(dev);
22024 + yaffs_unstitch_obj(inode,obj);
22025 + yaffs_gross_unlock(dev);
22026 + }
22027 +
22028 +}
22029 +
22030 +/* delete is called when the link count is zero and the inode
22031 + * is put (ie. nobody wants to know about it anymore, time to
22032 + * delete the file).
22033 + * NB Must call clear_inode()
22034 + */
22035 +static void yaffs_delete_inode(struct inode *inode)
22036 +{
22037 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
22038 + yaffs_dev_t *dev;
22039 +
22040 + T(YAFFS_TRACE_OS,
22041 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22042 + atomic_read(&inode->i_count),
22043 + obj ? "object exists" : "null object"));
22044 +
22045 + if (obj) {
22046 + dev = obj->my_dev;
22047 + yaffs_gross_lock(dev);
22048 + yaffs_del_obj(obj);
22049 + yaffs_gross_unlock(dev);
22050 + }
22051 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
22052 + truncate_inode_pages(&inode->i_data, 0);
22053 +#endif
22054 + clear_inode(inode);
22055 +}
22056 +#endif
22057 +
22058 +
22059 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
22060 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
22061 +#else
22062 +static int yaffs_file_flush(struct file *file)
22063 +#endif
22064 +{
22065 + yaffs_obj_t *obj = yaffs_dentry_to_obj(file->f_dentry);
22066 +
22067 + yaffs_dev_t *dev = obj->my_dev;
22068 +
22069 + T(YAFFS_TRACE_OS,
22070 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id,
22071 + obj->dirty ? "dirty" : "clean"));
22072 +
22073 + yaffs_gross_lock(dev);
22074 +
22075 + yaffs_flush_file(obj, 1, 0);
22076 +
22077 + yaffs_gross_unlock(dev);
22078 +
22079 + return 0;
22080 +}
22081 +
22082 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
22083 +{
22084 + /* Lifted from jffs2 */
22085 +
22086 + yaffs_obj_t *obj;
22087 + unsigned char *pg_buf;
22088 + int ret;
22089 +
22090 + yaffs_dev_t *dev;
22091 +
22092 + T(YAFFS_TRACE_OS,
22093 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
22094 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
22095 + (unsigned)PAGE_CACHE_SIZE));
22096 +
22097 + obj = yaffs_dentry_to_obj(f->f_dentry);
22098 +
22099 + dev = obj->my_dev;
22100 +
22101 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22102 + BUG_ON(!PageLocked(pg));
22103 +#else
22104 + if (!PageLocked(pg))
22105 + PAGE_BUG(pg);
22106 +#endif
22107 +
22108 + pg_buf = kmap(pg);
22109 + /* FIXME: Can kmap fail? */
22110 +
22111 + yaffs_gross_lock(dev);
22112 +
22113 + ret = yaffs_file_rd(obj, pg_buf,
22114 + pg->index << PAGE_CACHE_SHIFT,
22115 + PAGE_CACHE_SIZE);
22116 +
22117 + yaffs_gross_unlock(dev);
22118 +
22119 + if (ret >= 0)
22120 + ret = 0;
22121 +
22122 + if (ret) {
22123 + ClearPageUptodate(pg);
22124 + SetPageError(pg);
22125 + } else {
22126 + SetPageUptodate(pg);
22127 + ClearPageError(pg);
22128 + }
22129 +
22130 + flush_dcache_page(pg);
22131 + kunmap(pg);
22132 +
22133 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
22134 + return ret;
22135 +}
22136 +
22137 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
22138 +{
22139 + int ret = yaffs_readpage_nolock(f, pg);
22140 + UnlockPage(pg);
22141 + return ret;
22142 +}
22143 +
22144 +static int yaffs_readpage(struct file *f, struct page *pg)
22145 +{
22146 + int ret;
22147 +
22148 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
22149 + ret=yaffs_readpage_unlock(f, pg);
22150 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
22151 + return ret;
22152 +}
22153 +
22154 +/* writepage inspired by/stolen from smbfs */
22155 +
22156 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22157 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
22158 +#else
22159 +static int yaffs_writepage(struct page *page)
22160 +#endif
22161 +{
22162 + yaffs_dev_t *dev;
22163 + struct address_space *mapping = page->mapping;
22164 + struct inode *inode;
22165 + unsigned long end_index;
22166 + char *buffer;
22167 + yaffs_obj_t *obj;
22168 + int nWritten = 0;
22169 + unsigned n_bytes;
22170 + loff_t i_size;
22171 +
22172 + if (!mapping)
22173 + BUG();
22174 + inode = mapping->host;
22175 + if (!inode)
22176 + BUG();
22177 + i_size = i_size_read(inode);
22178 +
22179 + end_index = i_size >> PAGE_CACHE_SHIFT;
22180 +
22181 + if(page->index < end_index)
22182 + n_bytes = PAGE_CACHE_SIZE;
22183 + else {
22184 + n_bytes = i_size & (PAGE_CACHE_SIZE -1);
22185 +
22186 + if (page->index > end_index || !n_bytes) {
22187 + T(YAFFS_TRACE_OS,
22188 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
22189 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
22190 + (unsigned)inode->i_size));
22191 + T(YAFFS_TRACE_OS,
22192 + (TSTR(" -> don't care!!\n")));
22193 +
22194 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
22195 + set_page_writeback(page);
22196 + unlock_page(page);
22197 + end_page_writeback(page);
22198 + return 0;
22199 + }
22200 + }
22201 +
22202 + if(n_bytes != PAGE_CACHE_SIZE)
22203 + zero_user_segment(page,n_bytes,PAGE_CACHE_SIZE);
22204 +
22205 + get_page(page);
22206 +
22207 + buffer = kmap(page);
22208 +
22209 + obj = yaffs_InodeToObject(inode);
22210 + dev = obj->my_dev;
22211 + yaffs_gross_lock(dev);
22212 +
22213 + T(YAFFS_TRACE_OS,
22214 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
22215 + (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes));
22216 + T(YAFFS_TRACE_OS,
22217 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
22218 + (int)obj->variant.file_variant.file_size, (int)inode->i_size));
22219 +
22220 + nWritten = yaffs_wr_file(obj, buffer,
22221 + page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
22222 +
22223 + yaffs_touch_super(dev);
22224 +
22225 + T(YAFFS_TRACE_OS,
22226 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
22227 + (int)obj->variant.file_variant.file_size, (int)inode->i_size));
22228 +
22229 + yaffs_gross_unlock(dev);
22230 +
22231 + kunmap(page);
22232 + set_page_writeback(page);
22233 + unlock_page(page);
22234 + end_page_writeback(page);
22235 + put_page(page);
22236 +
22237 + return (nWritten == n_bytes) ? 0 : -ENOSPC;
22238 +}
22239 +
22240 +
22241 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
22242 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
22243 + loff_t pos, unsigned len, unsigned flags,
22244 + struct page **pagep, void **fsdata)
22245 +{
22246 + struct page *pg = NULL;
22247 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
22248 +
22249 + int ret = 0;
22250 + int space_held = 0;
22251 +
22252 + /* Get a page */
22253 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
22254 + pg = grab_cache_page_write_begin(mapping, index, flags);
22255 +#else
22256 + pg = __grab_cache_page(mapping, index);
22257 +#endif
22258 +
22259 + *pagep = pg;
22260 + if (!pg) {
22261 + ret = -ENOMEM;
22262 + goto out;
22263 + }
22264 + T(YAFFS_TRACE_OS,
22265 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
22266 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
22267 +
22268 + /* Get fs space */
22269 + space_held = yaffs_hold_space(filp);
22270 +
22271 + if (!space_held) {
22272 + ret = -ENOSPC;
22273 + goto out;
22274 + }
22275 +
22276 + /* Update page if required */
22277 +
22278 + if (!Page_Uptodate(pg))
22279 + ret = yaffs_readpage_nolock(filp, pg);
22280 +
22281 + if (ret)
22282 + goto out;
22283 +
22284 + /* Happy path return */
22285 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
22286 +
22287 + return 0;
22288 +
22289 +out:
22290 + T(YAFFS_TRACE_OS,
22291 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
22292 + if (space_held)
22293 + yaffs_release_space(filp);
22294 + if (pg) {
22295 + unlock_page(pg);
22296 + page_cache_release(pg);
22297 + }
22298 + return ret;
22299 +}
22300 +
22301 +#else
22302 +
22303 +static int yaffs_prepare_write(struct file *f, struct page *pg,
22304 + unsigned offset, unsigned to)
22305 +{
22306 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
22307 +
22308 + if (!Page_Uptodate(pg))
22309 + return yaffs_readpage_nolock(f, pg);
22310 + return 0;
22311 +}
22312 +#endif
22313 +
22314 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
22315 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
22316 + loff_t pos, unsigned len, unsigned copied,
22317 + struct page *pg, void *fsdadata)
22318 +{
22319 + int ret = 0;
22320 + void *addr, *kva;
22321 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
22322 +
22323 + kva = kmap(pg);
22324 + addr = kva + offset_into_page;
22325 +
22326 + T(YAFFS_TRACE_OS,
22327 + ("yaffs_write_end addr %p pos %x n_bytes %d\n",
22328 + addr,(unsigned)pos, copied));
22329 +
22330 + ret = yaffs_file_write(filp, addr, copied, &pos);
22331 +
22332 + if (ret != copied) {
22333 + T(YAFFS_TRACE_OS,
22334 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
22335 + ret, copied));
22336 + SetPageError(pg);
22337 + } else {
22338 + /* Nothing */
22339 + }
22340 +
22341 + kunmap(pg);
22342 +
22343 + yaffs_release_space(filp);
22344 + unlock_page(pg);
22345 + page_cache_release(pg);
22346 + return ret;
22347 +}
22348 +#else
22349 +
22350 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
22351 + unsigned to)
22352 +{
22353 + void *addr, *kva;
22354 +
22355 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
22356 + int n_bytes = to - offset;
22357 + int nWritten;
22358 +
22359 + unsigned spos = pos;
22360 + unsigned saddr;
22361 +
22362 + kva = kmap(pg);
22363 + addr = kva + offset;
22364 +
22365 + saddr = (unsigned) addr;
22366 +
22367 + T(YAFFS_TRACE_OS,
22368 + (TSTR("yaffs_commit_write addr %x pos %x n_bytes %d\n"),
22369 + saddr, spos, n_bytes));
22370 +
22371 + nWritten = yaffs_file_write(f, addr, n_bytes, &pos);
22372 +
22373 + if (nWritten != n_bytes) {
22374 + T(YAFFS_TRACE_OS,
22375 + (TSTR("yaffs_commit_write not same size nWritten %d n_bytes %d\n"),
22376 + nWritten, n_bytes));
22377 + SetPageError(pg);
22378 + } else {
22379 + /* Nothing */
22380 + }
22381 +
22382 + kunmap(pg);
22383 +
22384 + T(YAFFS_TRACE_OS,
22385 + (TSTR("yaffs_commit_write returning %d\n"),
22386 + nWritten == n_bytes ? 0 : nWritten));
22387 +
22388 + return nWritten == n_bytes ? 0 : nWritten;
22389 +}
22390 +#endif
22391 +
22392 +
22393 +static void yaffs_fill_inode_from_obj(struct inode *inode, yaffs_obj_t *obj)
22394 +{
22395 + if (inode && obj) {
22396 +
22397 +
22398 + /* Check mode against the variant type and attempt to repair if broken. */
22399 + __u32 mode = obj->yst_mode;
22400 + switch (obj->variant_type) {
22401 + case YAFFS_OBJECT_TYPE_FILE:
22402 + if (!S_ISREG(mode)) {
22403 + obj->yst_mode &= ~S_IFMT;
22404 + obj->yst_mode |= S_IFREG;
22405 + }
22406 +
22407 + break;
22408 + case YAFFS_OBJECT_TYPE_SYMLINK:
22409 + if (!S_ISLNK(mode)) {
22410 + obj->yst_mode &= ~S_IFMT;
22411 + obj->yst_mode |= S_IFLNK;
22412 + }
22413 +
22414 + break;
22415 + case YAFFS_OBJECT_TYPE_DIRECTORY:
22416 + if (!S_ISDIR(mode)) {
22417 + obj->yst_mode &= ~S_IFMT;
22418 + obj->yst_mode |= S_IFDIR;
22419 + }
22420 +
22421 + break;
22422 + case YAFFS_OBJECT_TYPE_UNKNOWN:
22423 + case YAFFS_OBJECT_TYPE_HARDLINK:
22424 + case YAFFS_OBJECT_TYPE_SPECIAL:
22425 + default:
22426 + /* TODO? */
22427 + break;
22428 + }
22429 +
22430 + inode->i_flags |= S_NOATIME;
22431 +
22432 + inode->i_ino = obj->obj_id;
22433 + inode->i_mode = obj->yst_mode;
22434 + inode->i_uid = obj->yst_uid;
22435 + inode->i_gid = obj->yst_gid;
22436 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
22437 + inode->i_blksize = inode->i_sb->s_blocksize;
22438 +#endif
22439 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22440 +
22441 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
22442 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
22443 + inode->i_atime.tv_nsec = 0;
22444 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
22445 + inode->i_mtime.tv_nsec = 0;
22446 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
22447 + inode->i_ctime.tv_nsec = 0;
22448 +#else
22449 + inode->i_rdev = obj->yst_rdev;
22450 + inode->i_atime = obj->yst_atime;
22451 + inode->i_mtime = obj->yst_mtime;
22452 + inode->i_ctime = obj->yst_ctime;
22453 +#endif
22454 + inode->i_size = yaffs_get_obj_length(obj);
22455 + inode->i_blocks = (inode->i_size + 511) >> 9;
22456 +
22457 + inode->i_nlink = yaffs_get_obj_link_count(obj);
22458 +
22459 + T(YAFFS_TRACE_OS,
22460 + (TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
22461 + inode->i_mode, inode->i_uid, inode->i_gid,
22462 + (int)inode->i_size, atomic_read(&inode->i_count)));
22463 +
22464 + switch (obj->yst_mode & S_IFMT) {
22465 + default: /* fifo, device or socket */
22466 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22467 + init_special_inode(inode, obj->yst_mode,
22468 + old_decode_dev(obj->yst_rdev));
22469 +#else
22470 + init_special_inode(inode, obj->yst_mode,
22471 + (dev_t) (obj->yst_rdev));
22472 +#endif
22473 + break;
22474 + case S_IFREG: /* file */
22475 + inode->i_op = &yaffs_file_inode_operations;
22476 + inode->i_fop = &yaffs_file_operations;
22477 + inode->i_mapping->a_ops =
22478 + &yaffs_file_address_operations;
22479 + break;
22480 + case S_IFDIR: /* directory */
22481 + inode->i_op = &yaffs_dir_inode_operations;
22482 + inode->i_fop = &yaffs_dir_operations;
22483 + break;
22484 + case S_IFLNK: /* symlink */
22485 + inode->i_op = &yaffs_symlink_inode_operations;
22486 + break;
22487 + }
22488 +
22489 + yaffs_InodeToObjectLV(inode) = obj;
22490 +
22491 + obj->my_inode = inode;
22492 +
22493 + } else {
22494 + T(YAFFS_TRACE_OS,
22495 + (TSTR("yaffs_FileInode invalid parameters\n")));
22496 + }
22497 +
22498 +}
22499 +
22500 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
22501 + yaffs_obj_t *obj)
22502 +{
22503 + struct inode *inode;
22504 +
22505 + if (!sb) {
22506 + T(YAFFS_TRACE_OS,
22507 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
22508 + return NULL;
22509 +
22510 + }
22511 +
22512 + if (!obj) {
22513 + T(YAFFS_TRACE_OS,
22514 + (TSTR("yaffs_get_inode for NULL object!!\n")));
22515 + return NULL;
22516 +
22517 + }
22518 +
22519 + T(YAFFS_TRACE_OS,
22520 + (TSTR("yaffs_get_inode for object %d\n"), obj->obj_id));
22521 +
22522 + inode = Y_IGET(sb, obj->obj_id);
22523 + if (IS_ERR(inode))
22524 + return NULL;
22525 +
22526 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
22527 + /* iget also increments the inode's i_count */
22528 + /* NB You can't be holding grossLock or deadlock will happen! */
22529 +
22530 + return inode;
22531 +}
22532 +
22533 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
22534 + loff_t *pos)
22535 +{
22536 + yaffs_obj_t *obj;
22537 + int nWritten, ipos;
22538 + struct inode *inode;
22539 + yaffs_dev_t *dev;
22540 +
22541 + obj = yaffs_dentry_to_obj(f->f_dentry);
22542 +
22543 + dev = obj->my_dev;
22544 +
22545 + yaffs_gross_lock(dev);
22546 +
22547 + inode = f->f_dentry->d_inode;
22548 +
22549 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
22550 + ipos = inode->i_size;
22551 + else
22552 + ipos = *pos;
22553 +
22554 + if (!obj)
22555 + T(YAFFS_TRACE_OS,
22556 + (TSTR("yaffs_file_write: hey obj is null!\n")));
22557 + else
22558 + T(YAFFS_TRACE_OS,
22559 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
22560 + "to object %d at %d(%x)\n"),
22561 + (unsigned) n, (unsigned) n, obj->obj_id, ipos,ipos));
22562 +
22563 + nWritten = yaffs_wr_file(obj, buf, ipos, n, 0);
22564 +
22565 + yaffs_touch_super(dev);
22566 +
22567 + T(YAFFS_TRACE_OS,
22568 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
22569 + (unsigned )n,(unsigned)n));
22570 +
22571 + if (nWritten > 0) {
22572 + ipos += nWritten;
22573 + *pos = ipos;
22574 + if (ipos > inode->i_size) {
22575 + inode->i_size = ipos;
22576 + inode->i_blocks = (ipos + 511) >> 9;
22577 +
22578 + T(YAFFS_TRACE_OS,
22579 + (TSTR("yaffs_file_write size updated to %d bytes, "
22580 + "%d blocks\n"),
22581 + ipos, (int)(inode->i_blocks)));
22582 + }
22583 +
22584 + }
22585 + yaffs_gross_unlock(dev);
22586 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
22587 +}
22588 +
22589 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
22590 +/* For now we just assume few parallel writes and check against a small number. */
22591 +/* Todo: need to do this with a counter to handle parallel reads better */
22592 +
22593 +static ssize_t yaffs_hold_space(struct file *f)
22594 +{
22595 + yaffs_obj_t *obj;
22596 + yaffs_dev_t *dev;
22597 +
22598 + int n_free_chunks;
22599 +
22600 +
22601 + obj = yaffs_dentry_to_obj(f->f_dentry);
22602 +
22603 + dev = obj->my_dev;
22604 +
22605 + yaffs_gross_lock(dev);
22606 +
22607 + n_free_chunks = yaffs_get_n_free_chunks(dev);
22608 +
22609 + yaffs_gross_unlock(dev);
22610 +
22611 + return (n_free_chunks > 20) ? 1 : 0;
22612 +}
22613 +
22614 +static void yaffs_release_space(struct file *f)
22615 +{
22616 + yaffs_obj_t *obj;
22617 + yaffs_dev_t *dev;
22618 +
22619 +
22620 + obj = yaffs_dentry_to_obj(f->f_dentry);
22621 +
22622 + dev = obj->my_dev;
22623 +
22624 + yaffs_gross_lock(dev);
22625 +
22626 +
22627 + yaffs_gross_unlock(dev);
22628 +}
22629 +
22630 +
22631 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
22632 +{
22633 + long long retval;
22634 +
22635 + lock_kernel();
22636 +
22637 + switch (origin){
22638 + case 2:
22639 + offset += i_size_read(file->f_path.dentry->d_inode);
22640 + break;
22641 + case 1:
22642 + offset += file->f_pos;
22643 + }
22644 + retval = -EINVAL;
22645 +
22646 + if (offset >= 0){
22647 + if (offset != file->f_pos)
22648 + file->f_pos = offset;
22649 +
22650 + retval = offset;
22651 + }
22652 + unlock_kernel();
22653 + return retval;
22654 +}
22655 +
22656 +
22657 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
22658 +{
22659 + yaffs_obj_t *obj;
22660 + yaffs_dev_t *dev;
22661 + struct yaffs_SearchContext *sc;
22662 + struct inode *inode = f->f_dentry->d_inode;
22663 + unsigned long offset, curoffs;
22664 + yaffs_obj_t *l;
22665 + int retVal = 0;
22666 +
22667 + char name[YAFFS_MAX_NAME_LENGTH + 1];
22668 +
22669 + obj = yaffs_dentry_to_obj(f->f_dentry);
22670 + dev = obj->my_dev;
22671 +
22672 + yaffs_gross_lock(dev);
22673 +
22674 + yaffs_dev_to_lc(dev)->readdirProcess = current;
22675 +
22676 + offset = f->f_pos;
22677 +
22678 + sc = yaffs_NewSearch(obj);
22679 + if(!sc){
22680 + retVal = -ENOMEM;
22681 + goto out;
22682 + }
22683 +
22684 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
22685 +
22686 + if (offset == 0) {
22687 + T(YAFFS_TRACE_OS,
22688 + (TSTR("yaffs_readdir: entry . ino %d \n"),
22689 + (int)inode->i_ino));
22690 + yaffs_gross_unlock(dev);
22691 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
22692 + yaffs_gross_lock(dev);
22693 + goto out;
22694 + }
22695 + yaffs_gross_lock(dev);
22696 + offset++;
22697 + f->f_pos++;
22698 + }
22699 + if (offset == 1) {
22700 + T(YAFFS_TRACE_OS,
22701 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
22702 + (int)f->f_dentry->d_parent->d_inode->i_ino));
22703 + yaffs_gross_unlock(dev);
22704 + if (filldir(dirent, "..", 2, offset,
22705 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
22706 + yaffs_gross_lock(dev);
22707 + goto out;
22708 + }
22709 + yaffs_gross_lock(dev);
22710 + offset++;
22711 + f->f_pos++;
22712 + }
22713 +
22714 + curoffs = 1;
22715 +
22716 + /* If the directory has changed since the open or last call to
22717 + readdir, rewind to after the 2 canned entries. */
22718 + if (f->f_version != inode->i_version) {
22719 + offset = 2;
22720 + f->f_pos = offset;
22721 + f->f_version = inode->i_version;
22722 + }
22723 +
22724 + while(sc->nextReturn){
22725 + curoffs++;
22726 + l = sc->nextReturn;
22727 + if (curoffs >= offset) {
22728 + int this_inode = yaffs_get_obj_inode(l);
22729 + int this_type = yaffs_get_obj_type(l);
22730 +
22731 + yaffs_get_obj_name(l, name,
22732 + YAFFS_MAX_NAME_LENGTH + 1);
22733 + T(YAFFS_TRACE_OS,
22734 + (TSTR("yaffs_readdir: %s inode %d\n"),
22735 + name, yaffs_get_obj_inode(l)));
22736 +
22737 + yaffs_gross_unlock(dev);
22738 +
22739 + if (filldir(dirent,
22740 + name,
22741 + strlen(name),
22742 + offset,
22743 + this_inode,
22744 + this_type) < 0){
22745 + yaffs_gross_lock(dev);
22746 + goto out;
22747 + }
22748 +
22749 + yaffs_gross_lock(dev);
22750 +
22751 + offset++;
22752 + f->f_pos++;
22753 + }
22754 + yaffs_search_advance(sc);
22755 + }
22756 +
22757 +out:
22758 + yaffs_search_end(sc);
22759 + yaffs_dev_to_lc(dev)->readdirProcess = NULL;
22760 + yaffs_gross_unlock(dev);
22761 +
22762 + return retVal;
22763 +}
22764 +
22765 +
22766 +
22767 +/*
22768 + * File creation. Allocate an inode, and we're done..
22769 + */
22770 +
22771 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
22772 +#define YCRED(x) x
22773 +#else
22774 +#define YCRED(x) (x->cred)
22775 +#endif
22776 +
22777 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22778 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
22779 + dev_t rdev)
22780 +#else
22781 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
22782 + int rdev)
22783 +#endif
22784 +{
22785 + struct inode *inode;
22786 +
22787 + yaffs_obj_t *obj = NULL;
22788 + yaffs_dev_t *dev;
22789 +
22790 + yaffs_obj_t *parent = yaffs_InodeToObject(dir);
22791 +
22792 + int error = -ENOSPC;
22793 + uid_t uid = YCRED(current)->fsuid;
22794 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
22795 +
22796 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
22797 + mode |= S_ISGID;
22798 +
22799 + if (parent) {
22800 + T(YAFFS_TRACE_OS,
22801 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
22802 + parent->obj_id, parent->variant_type));
22803 + } else {
22804 + T(YAFFS_TRACE_OS,
22805 + (TSTR("yaffs_mknod: could not get parent object\n")));
22806 + return -EPERM;
22807 + }
22808 +
22809 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
22810 + "mode %x dev %x\n"),
22811 + dentry->d_name.name, mode, rdev));
22812 +
22813 + dev = parent->my_dev;
22814 +
22815 + yaffs_gross_lock(dev);
22816 +
22817 + switch (mode & S_IFMT) {
22818 + default:
22819 + /* Special (socket, fifo, device...) */
22820 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
22821 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22822 + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
22823 + gid, old_encode_dev(rdev));
22824 +#else
22825 + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
22826 + gid, rdev);
22827 +#endif
22828 + break;
22829 + case S_IFREG: /* file */
22830 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
22831 + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
22832 + gid);
22833 + break;
22834 + case S_IFDIR: /* directory */
22835 + T(YAFFS_TRACE_OS,
22836 + (TSTR("yaffs_mknod: making directory\n")));
22837 + obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
22838 + uid, gid);
22839 + break;
22840 + case S_IFLNK: /* symlink */
22841 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
22842 + obj = NULL; /* Do we ever get here? */
22843 + break;
22844 + }
22845 +
22846 + /* Can not call yaffs_get_inode() with gross lock held */
22847 + yaffs_gross_unlock(dev);
22848 +
22849 + if (obj) {
22850 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
22851 + d_instantiate(dentry, inode);
22852 + update_dir_time(dir);
22853 + T(YAFFS_TRACE_OS,
22854 + (TSTR("yaffs_mknod created object %d count = %d\n"),
22855 + obj->obj_id, atomic_read(&inode->i_count)));
22856 + error = 0;
22857 + yaffs_fill_inode_from_obj(dir,parent);
22858 + } else {
22859 + T(YAFFS_TRACE_OS,
22860 + (TSTR("yaffs_mknod failed making object\n")));
22861 + error = -ENOMEM;
22862 + }
22863 +
22864 + return error;
22865 +}
22866 +
22867 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
22868 +{
22869 + int retVal;
22870 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
22871 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
22872 + return retVal;
22873 +}
22874 +
22875 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22876 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
22877 + struct nameidata *n)
22878 +#else
22879 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
22880 +#endif
22881 +{
22882 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
22883 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
22884 +}
22885 +
22886 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
22887 +{
22888 + int retVal;
22889 +
22890 + yaffs_dev_t *dev;
22891 + yaffs_obj_t *obj;
22892 +
22893 + T(YAFFS_TRACE_OS,
22894 + (TSTR("yaffs_unlink %d:%s\n"),
22895 + (int)(dir->i_ino),
22896 + dentry->d_name.name));
22897 + obj = yaffs_InodeToObject(dir);
22898 + dev = obj->my_dev;
22899 +
22900 + yaffs_gross_lock(dev);
22901 +
22902 + retVal = yaffs_unlinker(obj, dentry->d_name.name);
22903 +
22904 + if (retVal == YAFFS_OK) {
22905 + dentry->d_inode->i_nlink--;
22906 + dir->i_version++;
22907 + yaffs_gross_unlock(dev);
22908 + mark_inode_dirty(dentry->d_inode);
22909 + update_dir_time(dir);
22910 + return 0;
22911 + }
22912 + yaffs_gross_unlock(dev);
22913 + return -ENOTEMPTY;
22914 +}
22915 +
22916 +/*
22917 + * Create a link...
22918 + */
22919 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
22920 + struct dentry *dentry)
22921 +{
22922 + struct inode *inode = old_dentry->d_inode;
22923 + yaffs_obj_t *obj = NULL;
22924 + yaffs_obj_t *link = NULL;
22925 + yaffs_dev_t *dev;
22926 +
22927 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
22928 +
22929 + obj = yaffs_InodeToObject(inode);
22930 + dev = obj->my_dev;
22931 +
22932 + yaffs_gross_lock(dev);
22933 +
22934 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
22935 + link = yaffs_link_obj(yaffs_InodeToObject(dir), dentry->d_name.name,
22936 + obj);
22937 +
22938 + if (link) {
22939 + old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
22940 + d_instantiate(dentry, old_dentry->d_inode);
22941 + atomic_inc(&old_dentry->d_inode->i_count);
22942 + T(YAFFS_TRACE_OS,
22943 + (TSTR("yaffs_link link count %d i_count %d\n"),
22944 + old_dentry->d_inode->i_nlink,
22945 + atomic_read(&old_dentry->d_inode->i_count)));
22946 + }
22947 +
22948 + yaffs_gross_unlock(dev);
22949 +
22950 + if (link){
22951 + update_dir_time(dir);
22952 + return 0;
22953 + }
22954 +
22955 + return -EPERM;
22956 +}
22957 +
22958 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
22959 + const char *symname)
22960 +{
22961 + yaffs_obj_t *obj;
22962 + yaffs_dev_t *dev;
22963 + uid_t uid = YCRED(current)->fsuid;
22964 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
22965 +
22966 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
22967 +
22968 + dev = yaffs_InodeToObject(dir)->my_dev;
22969 + yaffs_gross_lock(dev);
22970 + obj = yaffs_create_symlink(yaffs_InodeToObject(dir), dentry->d_name.name,
22971 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
22972 + yaffs_gross_unlock(dev);
22973 +
22974 + if (obj) {
22975 + struct inode *inode;
22976 +
22977 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
22978 + d_instantiate(dentry, inode);
22979 + update_dir_time(dir);
22980 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
22981 + return 0;
22982 + } else {
22983 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
22984 + }
22985 +
22986 + return -ENOMEM;
22987 +}
22988 +
22989 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
22990 +static int yaffs_sync_object(struct file *file, int datasync)
22991 +#else
22992 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
22993 + int datasync)
22994 +#endif
22995 +{
22996 +
22997 + yaffs_obj_t *obj;
22998 + yaffs_dev_t *dev;
22999 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
23000 + struct dentry *dentry = file->f_path.dentry;
23001 +#endif
23002 +
23003 + obj = yaffs_dentry_to_obj(dentry);
23004 +
23005 + dev = obj->my_dev;
23006 +
23007 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
23008 + (TSTR("yaffs_sync_object\n")));
23009 + yaffs_gross_lock(dev);
23010 + yaffs_flush_file(obj, 1, datasync);
23011 + yaffs_gross_unlock(dev);
23012 + return 0;
23013 +}
23014 +
23015 +/*
23016 + * The VFS layer already does all the dentry stuff for rename.
23017 + *
23018 + * NB: POSIX says you can rename an object over an old object of the same name
23019 + */
23020 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
23021 + struct inode *new_dir, struct dentry *new_dentry)
23022 +{
23023 + yaffs_dev_t *dev;
23024 + int retVal = YAFFS_FAIL;
23025 + yaffs_obj_t *target;
23026 +
23027 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
23028 + dev = yaffs_InodeToObject(old_dir)->my_dev;
23029 +
23030 + yaffs_gross_lock(dev);
23031 +
23032 + /* Check if the target is an existing directory that is not empty. */
23033 + target = yaffs_find_by_name(yaffs_InodeToObject(new_dir),
23034 + new_dentry->d_name.name);
23035 +
23036 +
23037 +
23038 + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
23039 + !ylist_empty(&target->variant.dir_variant.children)) {
23040 +
23041 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
23042 +
23043 + retVal = YAFFS_FAIL;
23044 + } else {
23045 + /* Now does unlinking internally using shadowing mechanism */
23046 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_rename_obj\n")));
23047 +
23048 + retVal = yaffs_rename_obj(yaffs_InodeToObject(old_dir),
23049 + old_dentry->d_name.name,
23050 + yaffs_InodeToObject(new_dir),
23051 + new_dentry->d_name.name);
23052 + }
23053 + yaffs_gross_unlock(dev);
23054 +
23055 + if (retVal == YAFFS_OK) {
23056 + if (target) {
23057 + new_dentry->d_inode->i_nlink--;
23058 + mark_inode_dirty(new_dentry->d_inode);
23059 + }
23060 +
23061 + update_dir_time(old_dir);
23062 + if(old_dir != new_dir)
23063 + update_dir_time(new_dir);
23064 + return 0;
23065 + } else {
23066 + return -ENOTEMPTY;
23067 + }
23068 +}
23069 +
23070 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
23071 +{
23072 + struct inode *inode = dentry->d_inode;
23073 + int error = 0;
23074 + yaffs_dev_t *dev;
23075 +
23076 + T(YAFFS_TRACE_OS,
23077 + (TSTR("yaffs_setattr of object %d\n"),
23078 + yaffs_InodeToObject(inode)->obj_id));
23079 +
23080 + /* Fail if a requested resize >= 2GB */
23081 + if (attr->ia_valid & ATTR_SIZE &&
23082 + (attr->ia_size >> 31))
23083 + error = -EINVAL;
23084 +
23085 + if (error == 0)
23086 + error = inode_change_ok(inode, attr);
23087 + if (error == 0) {
23088 + int result;
23089 + if (!error){
23090 + error = yaffs_vfs_setattr(inode, attr);
23091 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
23092 + if (attr->ia_valid & ATTR_SIZE){
23093 + yaffs_vfs_setsize(inode,attr->ia_size);
23094 + inode->i_blocks = (inode->i_size + 511) >> 9;
23095 + }
23096 + }
23097 + dev = yaffs_InodeToObject(inode)->my_dev;
23098 + if (attr->ia_valid & ATTR_SIZE){
23099 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
23100 + (int)(attr->ia_size),(int)(attr->ia_size)));
23101 + }
23102 + yaffs_gross_lock(dev);
23103 + result = yaffs_set_attribs(yaffs_InodeToObject(inode), attr);
23104 + if(result == YAFFS_OK) {
23105 + error = 0;
23106 + } else {
23107 + error = -EPERM;
23108 + }
23109 + yaffs_gross_unlock(dev);
23110 +
23111 + }
23112 +
23113 + T(YAFFS_TRACE_OS,
23114 + (TSTR("yaffs_setattr done returning %d\n"),error));
23115 +
23116 + return error;
23117 +}
23118 +
23119 +#ifdef CONFIG_YAFFS_XATTR
23120 +int yaffs_setxattr(struct dentry *dentry, const char *name,
23121 + const void *value, size_t size, int flags)
23122 +{
23123 + struct inode *inode = dentry->d_inode;
23124 + int error = 0;
23125 + yaffs_dev_t *dev;
23126 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23127 +
23128 + T(YAFFS_TRACE_OS,
23129 + (TSTR("yaffs_setxattr of object %d\n"),
23130 + obj->obj_id));
23131 +
23132 +
23133 + if (error == 0) {
23134 + int result;
23135 + dev = obj->my_dev;
23136 + yaffs_gross_lock(dev);
23137 + result = yaffs_set_xattrib(obj, name, value, size, flags);
23138 + if(result == YAFFS_OK)
23139 + error = 0;
23140 + else if(result < 0)
23141 + error = result;
23142 + yaffs_gross_unlock(dev);
23143 +
23144 + }
23145 + T(YAFFS_TRACE_OS,
23146 + (TSTR("yaffs_setxattr done returning %d\n"),error));
23147 +
23148 + return error;
23149 +}
23150 +
23151 +
23152 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
23153 + size_t size)
23154 +{
23155 + struct inode *inode = dentry->d_inode;
23156 + int error = 0;
23157 + yaffs_dev_t *dev;
23158 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23159 +
23160 + T(YAFFS_TRACE_OS,
23161 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
23162 + name, obj->obj_id));
23163 +
23164 + if (error == 0) {
23165 + dev = obj->my_dev;
23166 + yaffs_gross_lock(dev);
23167 + error = yaffs_get_xattrib(obj, name, buff, size);
23168 + yaffs_gross_unlock(dev);
23169 +
23170 + }
23171 + T(YAFFS_TRACE_OS,
23172 + (TSTR("yaffs_getxattr done returning %d\n"),error));
23173 +
23174 + return error;
23175 +}
23176 +
23177 +int yaffs_removexattr(struct dentry *dentry, const char *name)
23178 +{
23179 + struct inode *inode = dentry->d_inode;
23180 + int error = 0;
23181 + yaffs_dev_t *dev;
23182 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23183 +
23184 + T(YAFFS_TRACE_OS,
23185 + (TSTR("yaffs_removexattr of object %d\n"),
23186 + obj->obj_id));
23187 +
23188 +
23189 + if (error == 0) {
23190 + int result;
23191 + dev = obj->my_dev;
23192 + yaffs_gross_lock(dev);
23193 + result = yaffs_remove_xattrib(obj, name);
23194 + if(result == YAFFS_OK)
23195 + error = 0;
23196 + else if(result < 0)
23197 + error = result;
23198 + yaffs_gross_unlock(dev);
23199 +
23200 + }
23201 + T(YAFFS_TRACE_OS,
23202 + (TSTR("yaffs_removexattr done returning %d\n"),error));
23203 +
23204 + return error;
23205 +}
23206 +
23207 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
23208 +{
23209 + struct inode *inode = dentry->d_inode;
23210 + int error = 0;
23211 + yaffs_dev_t *dev;
23212 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23213 +
23214 + T(YAFFS_TRACE_OS,
23215 + (TSTR("yaffs_listxattr of object %d\n"),
23216 + obj->obj_id));
23217 +
23218 +
23219 + if (error == 0) {
23220 + dev = obj->my_dev;
23221 + yaffs_gross_lock(dev);
23222 + error = yaffs_list_xattrib(obj, buff, size);
23223 + yaffs_gross_unlock(dev);
23224 +
23225 + }
23226 + T(YAFFS_TRACE_OS,
23227 + (TSTR("yaffs_listxattr done returning %d\n"),error));
23228 +
23229 + return error;
23230 +}
23231 +
23232 +#endif
23233 +
23234 +
23235 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23236 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
23237 +{
23238 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
23239 + struct super_block *sb = dentry->d_sb;
23240 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23241 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
23242 +{
23243 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23244 +#else
23245 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
23246 +{
23247 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23248 +#endif
23249 +
23250 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
23251 +
23252 + yaffs_gross_lock(dev);
23253 +
23254 + buf->f_type = YAFFS_MAGIC;
23255 + buf->f_bsize = sb->s_blocksize;
23256 + buf->f_namelen = 255;
23257 +
23258 + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
23259 + /* Do this if chunk size is not a power of 2 */
23260 +
23261 + uint64_t bytesInDev;
23262 + uint64_t bytesFree;
23263 +
23264 + bytesInDev = ((uint64_t)((dev->param.end_block - dev->param.start_block + 1))) *
23265 + ((uint64_t)(dev->param.chunks_per_block * dev->data_bytes_per_chunk));
23266 +
23267 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
23268 + buf->f_blocks = bytesInDev;
23269 +
23270 + bytesFree = ((uint64_t)(yaffs_get_n_free_chunks(dev))) *
23271 + ((uint64_t)(dev->data_bytes_per_chunk));
23272 +
23273 + do_div(bytesFree, sb->s_blocksize);
23274 +
23275 + buf->f_bfree = bytesFree;
23276 +
23277 + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
23278 +
23279 + buf->f_blocks =
23280 + (dev->param.end_block - dev->param.start_block + 1) *
23281 + dev->param.chunks_per_block /
23282 + (sb->s_blocksize / dev->data_bytes_per_chunk);
23283 + buf->f_bfree =
23284 + yaffs_get_n_free_chunks(dev) /
23285 + (sb->s_blocksize / dev->data_bytes_per_chunk);
23286 + } else {
23287 + buf->f_blocks =
23288 + (dev->param.end_block - dev->param.start_block + 1) *
23289 + dev->param.chunks_per_block *
23290 + (dev->data_bytes_per_chunk / sb->s_blocksize);
23291 +
23292 + buf->f_bfree =
23293 + yaffs_get_n_free_chunks(dev) *
23294 + (dev->data_bytes_per_chunk / sb->s_blocksize);
23295 + }
23296 +
23297 + buf->f_files = 0;
23298 + buf->f_ffree = 0;
23299 + buf->f_bavail = buf->f_bfree;
23300 +
23301 + yaffs_gross_unlock(dev);
23302 + return 0;
23303 +}
23304 +
23305 +
23306 +
23307 +static void yaffs_flush_inodes(struct super_block *sb)
23308 +{
23309 + struct inode *iptr;
23310 + yaffs_obj_t *obj;
23311 +
23312 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
23313 + obj = yaffs_InodeToObject(iptr);
23314 + if(obj){
23315 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
23316 + obj->obj_id));
23317 + yaffs_flush_file(obj,1,0);
23318 + }
23319 + }
23320 +}
23321 +
23322 +
23323 +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
23324 +{
23325 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23326 + if(!dev)
23327 + return;
23328 +
23329 + yaffs_flush_inodes(sb);
23330 + yaffs_update_dirty_dirs(dev);
23331 + yaffs_flush_whole_cache(dev);
23332 + if(do_checkpoint)
23333 + yaffs_checkpoint_save(dev);
23334 +}
23335 +
23336 +
23337 +static unsigned yaffs_bg_gc_urgency(yaffs_dev_t *dev)
23338 +{
23339 + unsigned erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
23340 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23341 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
23342 +
23343 + if(erasedChunks < dev->n_free_chunks)
23344 + scatteredFree = (dev->n_free_chunks - erasedChunks);
23345 +
23346 + if(!context->bgRunning)
23347 + return 0;
23348 + else if(scatteredFree < (dev->param.chunks_per_block * 2))
23349 + return 0;
23350 + else if(erasedChunks > dev->n_free_chunks/2)
23351 + return 0;
23352 + else if(erasedChunks > dev->n_free_chunks/4)
23353 + return 1;
23354 + else
23355 + return 2;
23356 +}
23357 +
23358 +static int yaffs_do_sync_fs(struct super_block *sb,
23359 + int request_checkpoint)
23360 +{
23361 +
23362 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23363 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
23364 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
23365 + int do_checkpoint;
23366 +
23367 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
23368 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
23369 + gc_urgent,
23370 + sb->s_dirt ? "dirty" : "clean",
23371 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
23372 + oneshot_checkpoint ? " one-shot" : "" ));
23373 +
23374 + yaffs_gross_lock(dev);
23375 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
23376 + oneshot_checkpoint) &&
23377 + !dev->is_checkpointed;
23378 +
23379 + if (sb->s_dirt || do_checkpoint) {
23380 + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
23381 + sb->s_dirt = 0;
23382 + if(oneshot_checkpoint)
23383 + yaffs_auto_checkpoint &= ~4;
23384 + }
23385 + yaffs_gross_unlock(dev);
23386 +
23387 + return 0;
23388 +}
23389 +
23390 +/*
23391 + * yaffs background thread functions .
23392 + * yaffs_bg_thread_fn() the thread function
23393 + * yaffs_bg_start() launches the background thread.
23394 + * yaffs_bg_stop() cleans up the background thread.
23395 + *
23396 + * NB:
23397 + * The thread should only run after the yaffs is initialised
23398 + * The thread should be stopped before yaffs is unmounted.
23399 + * The thread should not do any writing while the fs is in read only.
23400 + */
23401 +
23402 +#ifdef YAFFS_COMPILE_BACKGROUND
23403 +
23404 +void yaffs_background_waker(unsigned long data)
23405 +{
23406 + wake_up_process((struct task_struct *)data);
23407 +}
23408 +
23409 +static int yaffs_bg_thread_fn(void *data)
23410 +{
23411 + yaffs_dev_t *dev = (yaffs_dev_t *)data;
23412 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23413 + unsigned long now = jiffies;
23414 + unsigned long next_dir_update = now;
23415 + unsigned long next_gc = now;
23416 + unsigned long expires;
23417 + unsigned int urgency;
23418 +
23419 + int gcResult;
23420 + struct timer_list timer;
23421 +
23422 + T(YAFFS_TRACE_BACKGROUND,
23423 + (TSTR("yaffs_background starting for dev %p\n"),
23424 + (void *)dev));
23425 +
23426 +#ifdef YAFFS_COMPILE_FREEZER
23427 + set_freezable();
23428 +#endif
23429 + while(context->bgRunning){
23430 + T(YAFFS_TRACE_BACKGROUND,
23431 + (TSTR("yaffs_background\n")));
23432 +
23433 + if(kthread_should_stop())
23434 + break;
23435 +
23436 +#ifdef YAFFS_COMPILE_FREEZER
23437 + if(try_to_freeze())
23438 + continue;
23439 +#endif
23440 + yaffs_gross_lock(dev);
23441 +
23442 + now = jiffies;
23443 +
23444 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
23445 + yaffs_update_dirty_dirs(dev);
23446 + next_dir_update = now + HZ;
23447 + }
23448 +
23449 + if(time_after(now,next_gc) && yaffs_bg_enable){
23450 + if(!dev->is_checkpointed){
23451 + urgency = yaffs_bg_gc_urgency(dev);
23452 + gcResult = yaffs_bg_gc(dev, urgency);
23453 + if(urgency > 1)
23454 + next_gc = now + HZ/20+1;
23455 + else if(urgency > 0)
23456 + next_gc = now + HZ/10+1;
23457 + else
23458 + next_gc = now + HZ * 2;
23459 + } else /*
23460 + * gc not running so set to next_dir_update
23461 + * to cut down on wake ups
23462 + */
23463 + next_gc = next_dir_update;
23464 + }
23465 + yaffs_gross_unlock(dev);
23466 +#if 1
23467 + expires = next_dir_update;
23468 + if (time_before(next_gc,expires))
23469 + expires = next_gc;
23470 + if(time_before(expires,now))
23471 + expires = now + HZ;
23472 +
23473 + Y_INIT_TIMER(&timer);
23474 + timer.expires = expires+1;
23475 + timer.data = (unsigned long) current;
23476 + timer.function = yaffs_background_waker;
23477 +
23478 + set_current_state(TASK_INTERRUPTIBLE);
23479 + add_timer(&timer);
23480 + schedule();
23481 + del_timer_sync(&timer);
23482 +#else
23483 + msleep(10);
23484 +#endif
23485 + }
23486 +
23487 + return 0;
23488 +}
23489 +
23490 +static int yaffs_bg_start(yaffs_dev_t *dev)
23491 +{
23492 + int retval = 0;
23493 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23494 +
23495 + if(dev->read_only)
23496 + return -1;
23497 +
23498 + context->bgRunning = 1;
23499 +
23500 + context->bgThread = kthread_run(yaffs_bg_thread_fn,
23501 + (void *)dev,"yaffs-bg-%d",context->mount_id);
23502 +
23503 + if(IS_ERR(context->bgThread)){
23504 + retval = PTR_ERR(context->bgThread);
23505 + context->bgThread = NULL;
23506 + context->bgRunning = 0;
23507 + }
23508 + return retval;
23509 +}
23510 +
23511 +static void yaffs_bg_stop(yaffs_dev_t *dev)
23512 +{
23513 + struct yaffs_LinuxContext *ctxt = yaffs_dev_to_lc(dev);
23514 +
23515 + ctxt->bgRunning = 0;
23516 +
23517 + if( ctxt->bgThread){
23518 + kthread_stop(ctxt->bgThread);
23519 + ctxt->bgThread = NULL;
23520 + }
23521 +}
23522 +#else
23523 +static int yaffs_bg_thread_fn(void *data)
23524 +{
23525 + return 0;
23526 +}
23527 +
23528 +static int yaffs_bg_start(yaffs_dev_t *dev)
23529 +{
23530 + return 0;
23531 +}
23532 +
23533 +static void yaffs_bg_stop(yaffs_dev_t *dev)
23534 +{
23535 +}
23536 +#endif
23537 +
23538 +
23539 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23540 +static void yaffs_write_super(struct super_block *sb)
23541 +#else
23542 +static int yaffs_write_super(struct super_block *sb)
23543 +#endif
23544 +{
23545 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
23546 +
23547 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
23548 + (TSTR("yaffs_write_super%s\n"),
23549 + request_checkpoint ? " checkpt" : ""));
23550 +
23551 + yaffs_do_sync_fs(sb, request_checkpoint);
23552 +
23553 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
23554 + return 0;
23555 +#endif
23556 +}
23557 +
23558 +
23559 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23560 +static int yaffs_sync_fs(struct super_block *sb, int wait)
23561 +#else
23562 +static int yaffs_sync_fs(struct super_block *sb)
23563 +#endif
23564 +{
23565 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
23566 +
23567 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
23568 + (TSTR("yaffs_sync_fs%s\n"),
23569 + request_checkpoint ? " checkpt" : ""));
23570 +
23571 + yaffs_do_sync_fs(sb, request_checkpoint);
23572 +
23573 + return 0;
23574 +}
23575 +
23576 +#ifdef YAFFS_USE_OWN_IGET
23577 +
23578 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
23579 +{
23580 + struct inode *inode;
23581 + yaffs_obj_t *obj;
23582 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23583 +
23584 + T(YAFFS_TRACE_OS,
23585 + (TSTR("yaffs_iget for %lu\n"), ino));
23586 +
23587 + inode = iget_locked(sb, ino);
23588 + if (!inode)
23589 + return ERR_PTR(-ENOMEM);
23590 + if (!(inode->i_state & I_NEW))
23591 + return inode;
23592 +
23593 + /* NB This is called as a side effect of other functions, but
23594 + * we had to release the lock to prevent deadlocks, so
23595 + * need to lock again.
23596 + */
23597 +
23598 + yaffs_gross_lock(dev);
23599 +
23600 + obj = yaffs_find_by_number(dev, inode->i_ino);
23601 +
23602 + yaffs_fill_inode_from_obj(inode, obj);
23603 +
23604 + yaffs_gross_unlock(dev);
23605 +
23606 + unlock_new_inode(inode);
23607 + return inode;
23608 +}
23609 +
23610 +#else
23611 +
23612 +static void yaffs_read_inode(struct inode *inode)
23613 +{
23614 + /* NB This is called as a side effect of other functions, but
23615 + * we had to release the lock to prevent deadlocks, so
23616 + * need to lock again.
23617 + */
23618 +
23619 + yaffs_obj_t *obj;
23620 + yaffs_dev_t *dev = yaffs_SuperToDevice(inode->i_sb);
23621 +
23622 + T(YAFFS_TRACE_OS,
23623 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
23624 +
23625 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
23626 + yaffs_gross_lock(dev);
23627 +
23628 + obj = yaffs_find_by_number(dev, inode->i_ino);
23629 +
23630 + yaffs_fill_inode_from_obj(inode, obj);
23631 +
23632 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
23633 + yaffs_gross_unlock(dev);
23634 +}
23635 +
23636 +#endif
23637 +
23638 +static YLIST_HEAD(yaffs_context_list);
23639 +struct semaphore yaffs_context_lock;
23640 +
23641 +static void yaffs_put_super(struct super_block *sb)
23642 +{
23643 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23644 +
23645 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
23646 +
23647 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
23648 + (TSTR("Shutting down yaffs background thread\n")));
23649 + yaffs_bg_stop(dev);
23650 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
23651 + (TSTR("yaffs background thread shut down\n")));
23652 +
23653 + yaffs_gross_lock(dev);
23654 +
23655 + yaffs_flush_super(sb,1);
23656 +
23657 + if (yaffs_dev_to_lc(dev)->putSuperFunc)
23658 + yaffs_dev_to_lc(dev)->putSuperFunc(sb);
23659 +
23660 +
23661 + yaffs_deinitialise(dev);
23662 +
23663 + yaffs_gross_unlock(dev);
23664 +
23665 + down(&yaffs_context_lock);
23666 + ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
23667 + up(&yaffs_context_lock);
23668 +
23669 + if (yaffs_dev_to_lc(dev)->spareBuffer) {
23670 + YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
23671 + yaffs_dev_to_lc(dev)->spareBuffer = NULL;
23672 + }
23673 +
23674 + kfree(dev);
23675 +}
23676 +
23677 +
23678 +static void yaffs_MTDPutSuper(struct super_block *sb)
23679 +{
23680 + struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb));
23681 +
23682 + if (mtd->sync)
23683 + mtd->sync(mtd);
23684 +
23685 + put_mtd_device(mtd);
23686 +}
23687 +
23688 +
23689 +static void yaffs_touch_super(yaffs_dev_t *dev)
23690 +{
23691 + struct super_block *sb = yaffs_dev_to_lc(dev)->superBlock;
23692 +
23693 + T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
23694 + if (sb)
23695 + sb->s_dirt = 1;
23696 +}
23697 +
23698 +typedef struct {
23699 + int inband_tags;
23700 + int skip_checkpoint_read;
23701 + int skip_checkpoint_write;
23702 + int no_cache;
23703 + int tags_ecc_on;
23704 + int tags_ecc_overridden;
23705 + int lazy_loading_enabled;
23706 + int lazy_loading_overridden;
23707 + int empty_lost_and_found;
23708 + int empty_lost_and_found_overridden;
23709 +} yaffs_options;
23710 +
23711 +#define MAX_OPT_LEN 30
23712 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
23713 +{
23714 + char cur_opt[MAX_OPT_LEN + 1];
23715 + int p;
23716 + int error = 0;
23717 +
23718 + /* Parse through the options which is a comma seperated list */
23719 +
23720 + while (options_str && *options_str && !error) {
23721 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
23722 + p = 0;
23723 +
23724 + while(*options_str == ',')
23725 + options_str++;
23726 +
23727 + while (*options_str && *options_str != ',') {
23728 + if (p < MAX_OPT_LEN) {
23729 + cur_opt[p] = *options_str;
23730 + p++;
23731 + }
23732 + options_str++;
23733 + }
23734 +
23735 + if (!strcmp(cur_opt, "inband-tags"))
23736 + options->inband_tags = 1;
23737 + else if (!strcmp(cur_opt, "tags-ecc-off")){
23738 + options->tags_ecc_on = 0;
23739 + options->tags_ecc_overridden=1;
23740 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
23741 + options->tags_ecc_on = 1;
23742 + options->tags_ecc_overridden = 1;
23743 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
23744 + options->lazy_loading_enabled = 0;
23745 + options->lazy_loading_overridden=1;
23746 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
23747 + options->lazy_loading_enabled = 1;
23748 + options->lazy_loading_overridden = 1;
23749 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
23750 + options->empty_lost_and_found = 0;
23751 + options->empty_lost_and_found_overridden=1;
23752 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
23753 + options->empty_lost_and_found = 1;
23754 + options->empty_lost_and_found_overridden=1;
23755 + } else if (!strcmp(cur_opt, "no-cache"))
23756 + options->no_cache = 1;
23757 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
23758 + options->skip_checkpoint_read = 1;
23759 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
23760 + options->skip_checkpoint_write = 1;
23761 + else if (!strcmp(cur_opt, "no-checkpoint")) {
23762 + options->skip_checkpoint_read = 1;
23763 + options->skip_checkpoint_write = 1;
23764 + } else {
23765 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
23766 + cur_opt);
23767 + error = 1;
23768 + }
23769 + }
23770 +
23771 + return error;
23772 +}
23773 +
23774 +static struct super_block *yaffs_internal_read_super(int yaffs_version,
23775 + struct super_block *sb,
23776 + void *data, int silent)
23777 +{
23778 + int nBlocks;
23779 + struct inode *inode = NULL;
23780 + struct dentry *root;
23781 + yaffs_dev_t *dev = 0;
23782 + char devname_buf[BDEVNAME_SIZE + 1];
23783 + struct mtd_info *mtd;
23784 + int err;
23785 + char *data_str = (char *)data;
23786 + struct yaffs_LinuxContext *context = NULL;
23787 + yaffs_param_t *param;
23788 +
23789 + int read_only = 0;
23790 +
23791 + yaffs_options options;
23792 +
23793 + unsigned mount_id;
23794 + int found;
23795 + struct yaffs_LinuxContext *context_iterator;
23796 + struct ylist_head *l;
23797 +
23798 + sb->s_magic = YAFFS_MAGIC;
23799 + sb->s_op = &yaffs_super_ops;
23800 + sb->s_flags |= MS_NOATIME;
23801 +
23802 + read_only =((sb->s_flags & MS_RDONLY) != 0);
23803 +
23804 +
23805 +#ifdef YAFFS_COMPILE_EXPORTFS
23806 + sb->s_export_op = &yaffs_export_ops;
23807 +#endif
23808 +
23809 + if (!sb)
23810 + printk(KERN_INFO "yaffs: sb is NULL\n");
23811 + else if (!sb->s_dev)
23812 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
23813 + else if (!yaffs_devname(sb, devname_buf))
23814 + printk(KERN_INFO "yaffs: devname is NULL\n");
23815 + else
23816 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
23817 + sb->s_dev,
23818 + yaffs_devname(sb, devname_buf),
23819 + read_only ? "ro" : "rw");
23820 +
23821 + if (!data_str)
23822 + data_str = "";
23823 +
23824 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
23825 +
23826 + memset(&options, 0, sizeof(options));
23827 +
23828 + if (yaffs_parse_options(&options, data_str)) {
23829 + /* Option parsing failed */
23830 + return NULL;
23831 + }
23832 +
23833 +
23834 + sb->s_blocksize = PAGE_CACHE_SIZE;
23835 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
23836 +
23837 + T(YAFFS_TRACE_OS,
23838 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffs_version));
23839 + T(YAFFS_TRACE_OS,
23840 + (TSTR("yaffs_read_super: block size %d\n"),
23841 + (int)(sb->s_blocksize)));
23842 +
23843 + T(YAFFS_TRACE_ALWAYS,
23844 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
23845 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
23846 + yaffs_devname(sb, devname_buf)));
23847 +
23848 + /* Check it's an mtd device..... */
23849 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
23850 + return NULL; /* This isn't an mtd device */
23851 +
23852 + /* Get the device */
23853 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
23854 + if (!mtd) {
23855 + T(YAFFS_TRACE_ALWAYS,
23856 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
23857 + MINOR(sb->s_dev)));
23858 + return NULL;
23859 + }
23860 + /* Check it's NAND */
23861 + if (mtd->type != MTD_NANDFLASH) {
23862 + T(YAFFS_TRACE_ALWAYS,
23863 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
23864 + mtd->type));
23865 + return NULL;
23866 + }
23867 +
23868 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
23869 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
23870 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
23871 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
23872 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
23873 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
23874 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
23875 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
23876 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
23877 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
23878 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
23879 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
23880 +#else
23881 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
23882 +#endif
23883 +
23884 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
23885 +
23886 + if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
23887 + T(YAFFS_TRACE_ALWAYS,
23888 + (TSTR("yaffs: auto selecting yaffs2\n")));
23889 + yaffs_version = 2;
23890 + }
23891 +
23892 + /* Added NCB 26/5/2006 for completeness */
23893 + if (yaffs_version == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
23894 + T(YAFFS_TRACE_ALWAYS,
23895 + (TSTR("yaffs: auto selecting yaffs1\n")));
23896 + yaffs_version = 1;
23897 + }
23898 +
23899 +#endif
23900 +
23901 + if (yaffs_version == 2) {
23902 + /* Check for version 2 style functions */
23903 + if (!mtd->erase ||
23904 + !mtd->block_isbad ||
23905 + !mtd->block_markbad ||
23906 + !mtd->read ||
23907 + !mtd->write ||
23908 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23909 + !mtd->read_oob || !mtd->write_oob) {
23910 +#else
23911 + !mtd->write_ecc ||
23912 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
23913 +#endif
23914 + T(YAFFS_TRACE_ALWAYS,
23915 + (TSTR("yaffs: MTD device does not support required "
23916 + "functions\n")));
23917 + return NULL;
23918 + }
23919 +
23920 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
23921 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
23922 + !options.inband_tags) {
23923 + T(YAFFS_TRACE_ALWAYS,
23924 + (TSTR("yaffs: MTD device does not have the "
23925 + "right page sizes\n")));
23926 + return NULL;
23927 + }
23928 + } else {
23929 + /* Check for V1 style functions */
23930 + if (!mtd->erase ||
23931 + !mtd->read ||
23932 + !mtd->write ||
23933 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23934 + !mtd->read_oob || !mtd->write_oob) {
23935 +#else
23936 + !mtd->write_ecc ||
23937 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
23938 +#endif
23939 + T(YAFFS_TRACE_ALWAYS,
23940 + (TSTR("yaffs: MTD device does not support required "
23941 + "functions\n")));
23942 + return NULL;
23943 + }
23944 +
23945 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
23946 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
23947 + T(YAFFS_TRACE_ALWAYS,
23948 + (TSTR("yaffs: MTD device does not support have the "
23949 + "right page sizes\n")));
23950 + return NULL;
23951 + }
23952 + }
23953 +
23954 + /* OK, so if we got here, we have an MTD that's NAND and looks
23955 + * like it has the right capabilities
23956 + * Set the yaffs_dev_t up for mtd
23957 + */
23958 +
23959 + if (!read_only && !(mtd->flags & MTD_WRITEABLE)){
23960 + read_only = 1;
23961 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
23962 + sb->s_flags |= MS_RDONLY;
23963 + }
23964 +
23965 + dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL);
23966 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
23967 +
23968 + if(!dev || !context ){
23969 + if(dev)
23970 + kfree(dev);
23971 + if(context)
23972 + kfree(context);
23973 + dev = NULL;
23974 + context = NULL;
23975 + }
23976 +
23977 + if (!dev) {
23978 + /* Deep shit could not allocate device structure */
23979 + T(YAFFS_TRACE_ALWAYS,
23980 + (TSTR("yaffs_read_super: Failed trying to allocate "
23981 + "yaffs_dev_t. \n")));
23982 + return NULL;
23983 + }
23984 + memset(dev, 0, sizeof(yaffs_dev_t));
23985 + param = &(dev->param);
23986 +
23987 + memset(context,0,sizeof(struct yaffs_LinuxContext));
23988 + dev->os_context = context;
23989 + YINIT_LIST_HEAD(&(context->contextList));
23990 + context->dev = dev;
23991 + context->superBlock = sb;
23992 +
23993 + dev->read_only = read_only;
23994 +
23995 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23996 + sb->s_fs_info = dev;
23997 +#else
23998 + sb->u.generic_sbp = dev;
23999 +#endif
24000 +
24001 + dev->driver_context = mtd;
24002 + param->name = mtd->name;
24003 +
24004 + /* Set up the memory size parameters.... */
24005 +
24006 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
24007 +
24008 + param->start_block = 0;
24009 + param->end_block = nBlocks - 1;
24010 + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
24011 + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
24012 + param->n_reserved_blocks = 5;
24013 + param->n_caches = (options.no_cache) ? 0 : 10;
24014 + param->inband_tags = options.inband_tags;
24015 +
24016 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
24017 + param->disable_lazy_load = 1;
24018 +#endif
24019 +#ifdef CONFIG_YAFFS_XATTR
24020 + param->enable_xattr = 1;
24021 +#endif
24022 + if(options.lazy_loading_overridden)
24023 + param->disable_lazy_load = !options.lazy_loading_enabled;
24024 +
24025 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
24026 + param->no_tags_ecc = 1;
24027 +#endif
24028 +
24029 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
24030 +#else
24031 + param->defered_dir_update = 1;
24032 +#endif
24033 +
24034 + if(options.tags_ecc_overridden)
24035 + param->no_tags_ecc = !options.tags_ecc_on;
24036 +
24037 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
24038 + param->empty_lost_n_found = 1;
24039 +#endif
24040 +
24041 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
24042 + param->refresh_period = 0;
24043 +#else
24044 + param->refresh_period = 500;
24045 +#endif
24046 +
24047 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
24048 + param->always_check_erased = 1;
24049 +#endif
24050 +
24051 + if(options.empty_lost_and_found_overridden)
24052 + param->empty_lost_n_found = options.empty_lost_and_found;
24053 +
24054 + /* ... and the functions. */
24055 + if (yaffs_version == 2) {
24056 + param->write_chunk_tags_fn =
24057 + nandmtd2_WriteChunkWithTagsToNAND;
24058 + param->read_chunk_tags_fn =
24059 + nandmtd2_ReadChunkWithTagsFromNAND;
24060 + param->bad_block_fn = nandmtd2_MarkNANDBlockBad;
24061 + param->query_block_fn = nandmtd2_QueryNANDBlock;
24062 + yaffs_dev_to_lc(dev)->spareBuffer = YMALLOC(mtd->oobsize);
24063 + param->is_yaffs2 = 1;
24064 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24065 + param->total_bytes_per_chunk = mtd->writesize;
24066 + param->chunks_per_block = mtd->erasesize / mtd->writesize;
24067 +#else
24068 + param->total_bytes_per_chunk = mtd->oobblock;
24069 + param->chunks_per_block = mtd->erasesize / mtd->oobblock;
24070 +#endif
24071 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
24072 +
24073 + param->start_block = 0;
24074 + param->end_block = nBlocks - 1;
24075 + } else {
24076 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24077 + /* use the MTD interface in yaffs_mtdif1.c */
24078 + param->write_chunk_tags_fn =
24079 + nandmtd1_WriteChunkWithTagsToNAND;
24080 + param->read_chunk_tags_fn =
24081 + nandmtd1_ReadChunkWithTagsFromNAND;
24082 + param->bad_block_fn = nandmtd1_MarkNANDBlockBad;
24083 + param->query_block_fn = nandmtd1_QueryNANDBlock;
24084 +#else
24085 + param->write_chunk_fn = nandmtd_WriteChunkToNAND;
24086 + param->read_chunk_fn = nandmtd_ReadChunkFromNAND;
24087 +#endif
24088 + param->is_yaffs2 = 0;
24089 + }
24090 + /* ... and common functions */
24091 + param->erase_fn = nandmtd_EraseBlockInNAND;
24092 + param->initialise_flash_fn = nandmtd_InitialiseNAND;
24093 +
24094 + yaffs_dev_to_lc(dev)->putSuperFunc = yaffs_MTDPutSuper;
24095 +
24096 + param->sb_dirty_fn = yaffs_touch_super;
24097 + param->gc_control = yaffs_gc_control_callback;
24098 +
24099 + yaffs_dev_to_lc(dev)->superBlock= sb;
24100 +
24101 +
24102 +#ifndef CONFIG_YAFFS_DOES_ECC
24103 + param->use_nand_ecc = 1;
24104 +#endif
24105 +
24106 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
24107 + param->wide_tnodes_disabled = 1;
24108 +#endif
24109 +
24110 + param->skip_checkpt_rd = options.skip_checkpoint_read;
24111 + param->skip_checkpt_wr = options.skip_checkpoint_write;
24112 +
24113 + down(&yaffs_context_lock);
24114 + /* Get a mount id */
24115 + found = 0;
24116 + for(mount_id=0; ! found; mount_id++){
24117 + found = 1;
24118 + ylist_for_each(l,&yaffs_context_list){
24119 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
24120 + if(context_iterator->mount_id == mount_id)
24121 + found = 0;
24122 + }
24123 + }
24124 + context->mount_id = mount_id;
24125 +
24126 + ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
24127 + up(&yaffs_context_lock);
24128 +
24129 + /* Directory search handling...*/
24130 + YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts));
24131 + param->remove_obj_fn = yaffs_remove_obj_callback;
24132 +
24133 + init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock));
24134 +
24135 + yaffs_gross_lock(dev);
24136 +
24137 + err = yaffs_guts_initialise(dev);
24138 +
24139 + T(YAFFS_TRACE_OS,
24140 + (TSTR("yaffs_read_super: guts initialised %s\n"),
24141 + (err == YAFFS_OK) ? "OK" : "FAILED"));
24142 +
24143 + if(err == YAFFS_OK)
24144 + yaffs_bg_start(dev);
24145 +
24146 + if(!context->bgThread)
24147 + param->defered_dir_update = 0;
24148 +
24149 +
24150 + /* Release lock before yaffs_get_inode() */
24151 + yaffs_gross_unlock(dev);
24152 +
24153 + /* Create root inode */
24154 + if (err == YAFFS_OK)
24155 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
24156 + yaffs_root(dev));
24157 +
24158 + if (!inode)
24159 + return NULL;
24160 +
24161 + inode->i_op = &yaffs_dir_inode_operations;
24162 + inode->i_fop = &yaffs_dir_operations;
24163 +
24164 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
24165 +
24166 + root = d_alloc_root(inode);
24167 +
24168 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
24169 +
24170 + if (!root) {
24171 + iput(inode);
24172 + return NULL;
24173 + }
24174 + sb->s_root = root;
24175 + sb->s_dirt = !dev->is_checkpointed;
24176 + T(YAFFS_TRACE_ALWAYS,
24177 + (TSTR("yaffs_read_super: is_checkpointed %d\n"),
24178 + dev->is_checkpointed));
24179 +
24180 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
24181 + return sb;
24182 +}
24183 +
24184 +
24185 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24186 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
24187 + int silent)
24188 +{
24189 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
24190 +}
24191 +
24192 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24193 +static int yaffs_read_super(struct file_system_type *fs,
24194 + int flags, const char *dev_name,
24195 + void *data, struct vfsmount *mnt)
24196 +{
24197 +
24198 + return get_sb_bdev(fs, flags, dev_name, data,
24199 + yaffs_internal_read_super_mtd, mnt);
24200 +}
24201 +#else
24202 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
24203 + int flags, const char *dev_name,
24204 + void *data)
24205 +{
24206 +
24207 + return get_sb_bdev(fs, flags, dev_name, data,
24208 + yaffs_internal_read_super_mtd);
24209 +}
24210 +#endif
24211 +
24212 +static struct file_system_type yaffs_fs_type = {
24213 + .owner = THIS_MODULE,
24214 + .name = "yaffs",
24215 + .get_sb = yaffs_read_super,
24216 + .kill_sb = kill_block_super,
24217 + .fs_flags = FS_REQUIRES_DEV,
24218 +};
24219 +#else
24220 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
24221 + int silent)
24222 +{
24223 + return yaffs_internal_read_super(1, sb, data, silent);
24224 +}
24225 +
24226 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
24227 + FS_REQUIRES_DEV);
24228 +#endif
24229 +
24230 +
24231 +#ifdef CONFIG_YAFFS_YAFFS2
24232 +
24233 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24234 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
24235 + int silent)
24236 +{
24237 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
24238 +}
24239 +
24240 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24241 +static int yaffs2_read_super(struct file_system_type *fs,
24242 + int flags, const char *dev_name, void *data,
24243 + struct vfsmount *mnt)
24244 +{
24245 + return get_sb_bdev(fs, flags, dev_name, data,
24246 + yaffs2_internal_read_super_mtd, mnt);
24247 +}
24248 +#else
24249 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
24250 + int flags, const char *dev_name,
24251 + void *data)
24252 +{
24253 +
24254 + return get_sb_bdev(fs, flags, dev_name, data,
24255 + yaffs2_internal_read_super_mtd);
24256 +}
24257 +#endif
24258 +
24259 +static struct file_system_type yaffs2_fs_type = {
24260 + .owner = THIS_MODULE,
24261 + .name = "yaffs2",
24262 + .get_sb = yaffs2_read_super,
24263 + .kill_sb = kill_block_super,
24264 + .fs_flags = FS_REQUIRES_DEV,
24265 +};
24266 +#else
24267 +static struct super_block *yaffs2_read_super(struct super_block *sb,
24268 + void *data, int silent)
24269 +{
24270 + return yaffs_internal_read_super(2, sb, data, silent);
24271 +}
24272 +
24273 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
24274 + FS_REQUIRES_DEV);
24275 +#endif
24276 +
24277 +#endif /* CONFIG_YAFFS_YAFFS2 */
24278 +
24279 +static struct proc_dir_entry *my_proc_entry;
24280 +static struct proc_dir_entry *debug_proc_entry;
24281 +
24282 +static char *yaffs_dump_dev_part0(char *buf, yaffs_dev_t * dev)
24283 +{
24284 + buf += sprintf(buf, "start_block.......... %d\n", dev->param.start_block);
24285 + buf += sprintf(buf, "end_block............ %d\n", dev->param.end_block);
24286 + buf += sprintf(buf, "total_bytes_per_chunk %d\n", dev->param.total_bytes_per_chunk);
24287 + buf += sprintf(buf, "use_nand_ecc......... %d\n", dev->param.use_nand_ecc);
24288 + buf += sprintf(buf, "no_tags_ecc.......... %d\n", dev->param.no_tags_ecc);
24289 + buf += sprintf(buf, "is_yaffs2............ %d\n", dev->param.is_yaffs2);
24290 + buf += sprintf(buf, "inband_tags.......... %d\n", dev->param.inband_tags);
24291 + buf += sprintf(buf, "empty_lost_n_found... %d\n", dev->param.empty_lost_n_found);
24292 + buf += sprintf(buf, "disable_lazy_load.... %d\n", dev->param.disable_lazy_load);
24293 + buf += sprintf(buf, "refresh_period....... %d\n", dev->param.refresh_period);
24294 + buf += sprintf(buf, "n_caches............. %d\n", dev->param.n_caches);
24295 + buf += sprintf(buf, "n_reserved_blocks.... %d\n", dev->param.n_reserved_blocks);
24296 + buf += sprintf(buf, "always_check_erased.. %d\n", dev->param.always_check_erased);
24297 +
24298 + buf += sprintf(buf, "\n");
24299 +
24300 + return buf;
24301 +}
24302 +
24303 +
24304 +static char *yaffs_dump_dev_part1(char *buf, yaffs_dev_t * dev)
24305 +{
24306 + buf += sprintf(buf, "data_bytes_per_chunk. %d\n", dev->data_bytes_per_chunk);
24307 + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
24308 + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
24309 + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
24310 + buf += sprintf(buf, "blocks_in_checkpt.... %d\n", dev->blocks_in_checkpt);
24311 + buf += sprintf(buf, "\n");
24312 + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
24313 + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
24314 + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
24315 + buf += sprintf(buf, "\n");
24316 + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
24317 + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
24318 + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
24319 + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
24320 + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
24321 + buf += sprintf(buf, "passive_gc_count..... %u\n", dev->passive_gc_count);
24322 + buf += sprintf(buf, "oldest_dirty_gc_count %u\n", dev->oldest_dirty_gc_count);
24323 + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
24324 + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
24325 + buf += sprintf(buf, "n_retired_writes..... %u\n", dev->n_retired_writes);
24326 + buf += sprintf(buf, "nRetireBlocks........ %u\n", dev->n_retired_blocks);
24327 + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
24328 + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
24329 + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", dev->n_tags_ecc_fixed);
24330 + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", dev->n_tags_ecc_unfixed);
24331 + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
24332 + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
24333 + buf += sprintf(buf, "n_unlinked_files..... %u\n", dev->n_unlinked_files);
24334 + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
24335 + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
24336 +
24337 + return buf;
24338 +}
24339 +
24340 +static int yaffs_proc_read(char *page,
24341 + char **start,
24342 + off_t offset, int count, int *eof, void *data)
24343 +{
24344 + struct ylist_head *item;
24345 + char *buf = page;
24346 + int step = offset;
24347 + int n = 0;
24348 +
24349 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
24350 + * We use 'offset' (*ppos) to indicate where we are in dev_list.
24351 + * This also assumes the user has posted a read buffer large
24352 + * enough to hold the complete output; but that's life in /proc.
24353 + */
24354 +
24355 + *(int *)start = 1;
24356 +
24357 + /* Print header first */
24358 + if (step == 0)
24359 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
24360 + else if (step == 1)
24361 + buf += sprintf(buf,"\n");
24362 + else {
24363 + step-=2;
24364 +
24365 + down(&yaffs_context_lock);
24366 +
24367 + /* Locate and print the Nth entry. Order N-squared but N is small. */
24368 + ylist_for_each(item, &yaffs_context_list) {
24369 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
24370 + yaffs_dev_t *dev = dc->dev;
24371 +
24372 + if (n < (step & ~1)) {
24373 + n+=2;
24374 + continue;
24375 + }
24376 + if((step & 1)==0){
24377 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
24378 + buf = yaffs_dump_dev_part0(buf, dev);
24379 + } else
24380 + buf = yaffs_dump_dev_part1(buf, dev);
24381 +
24382 + break;
24383 + }
24384 + up(&yaffs_context_lock);
24385 + }
24386 +
24387 + return buf - page < count ? buf - page : count;
24388 +}
24389 +
24390 +static int yaffs_stats_proc_read(char *page,
24391 + char **start,
24392 + off_t offset, int count, int *eof, void *data)
24393 +{
24394 + struct ylist_head *item;
24395 + char *buf = page;
24396 + int n = 0;
24397 +
24398 + down(&yaffs_context_lock);
24399 +
24400 + /* Locate and print the Nth entry. Order N-squared but N is small. */
24401 + ylist_for_each(item, &yaffs_context_list) {
24402 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
24403 + yaffs_dev_t *dev = dc->dev;
24404 +
24405 + int erasedChunks;
24406 +
24407 + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
24408 +
24409 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
24410 + n, dev->n_free_chunks, erasedChunks,
24411 + dev->bg_gcs, dev->oldest_dirty_gc_count,
24412 + dev->n_obj, dev->n_tnodes);
24413 + }
24414 + up(&yaffs_context_lock);
24415 +
24416 +
24417 + return buf - page < count ? buf - page : count;
24418 +}
24419 +
24420 +/**
24421 + * Set the verbosity of the warnings and error messages.
24422 + *
24423 + * Note that the names can only be a..z or _ with the current code.
24424 + */
24425 +
24426 +static struct {
24427 + char *mask_name;
24428 + unsigned mask_bitfield;
24429 +} mask_flags[] = {
24430 + {"allocate", YAFFS_TRACE_ALLOCATE},
24431 + {"always", YAFFS_TRACE_ALWAYS},
24432 + {"background", YAFFS_TRACE_BACKGROUND},
24433 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
24434 + {"buffers", YAFFS_TRACE_BUFFERS},
24435 + {"bug", YAFFS_TRACE_BUG},
24436 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
24437 + {"deletion", YAFFS_TRACE_DELETION},
24438 + {"erase", YAFFS_TRACE_ERASE},
24439 + {"error", YAFFS_TRACE_ERROR},
24440 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
24441 + {"gc", YAFFS_TRACE_GC},
24442 + {"lock", YAFFS_TRACE_LOCK},
24443 + {"mtd", YAFFS_TRACE_MTD},
24444 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
24445 + {"os", YAFFS_TRACE_OS},
24446 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
24447 + {"scan", YAFFS_TRACE_SCAN},
24448 + {"tracing", YAFFS_TRACE_TRACING},
24449 + {"sync", YAFFS_TRACE_SYNC},
24450 + {"write", YAFFS_TRACE_WRITE},
24451 +
24452 + {"verify", YAFFS_TRACE_VERIFY},
24453 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
24454 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
24455 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
24456 +
24457 + {"all", 0xffffffff},
24458 + {"none", 0},
24459 + {NULL, 0},
24460 +};
24461 +
24462 +#define MAX_MASK_NAME_LENGTH 40
24463 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
24464 + unsigned long count, void *data)
24465 +{
24466 + unsigned rg = 0, mask_bitfield;
24467 + char *end;
24468 + char *mask_name;
24469 + const char *x;
24470 + char substring[MAX_MASK_NAME_LENGTH + 1];
24471 + int i;
24472 + int done = 0;
24473 + int add, len = 0;
24474 + int pos = 0;
24475 +
24476 + rg = yaffs_trace_mask;
24477 +
24478 + while (!done && (pos < count)) {
24479 + done = 1;
24480 + while ((pos < count) && isspace(buf[pos]))
24481 + pos++;
24482 +
24483 + switch (buf[pos]) {
24484 + case '+':
24485 + case '-':
24486 + case '=':
24487 + add = buf[pos];
24488 + pos++;
24489 + break;
24490 +
24491 + default:
24492 + add = ' ';
24493 + break;
24494 + }
24495 + mask_name = NULL;
24496 +
24497 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
24498 +
24499 + if (end > buf + pos) {
24500 + mask_name = "numeral";
24501 + len = end - (buf + pos);
24502 + pos += len;
24503 + done = 0;
24504 + } else {
24505 + for (x = buf + pos, i = 0;
24506 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
24507 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
24508 + substring[i] = *x;
24509 + substring[i] = '\0';
24510 +
24511 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
24512 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
24513 + mask_name = mask_flags[i].mask_name;
24514 + mask_bitfield = mask_flags[i].mask_bitfield;
24515 + done = 0;
24516 + break;
24517 + }
24518 + }
24519 + }
24520 +
24521 + if (mask_name != NULL) {
24522 + done = 0;
24523 + switch (add) {
24524 + case '-':
24525 + rg &= ~mask_bitfield;
24526 + break;
24527 + case '+':
24528 + rg |= mask_bitfield;
24529 + break;
24530 + case '=':
24531 + rg = mask_bitfield;
24532 + break;
24533 + default:
24534 + rg |= mask_bitfield;
24535 + break;
24536 + }
24537 + }
24538 + }
24539 +
24540 + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
24541 +
24542 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
24543 +
24544 + if (rg & YAFFS_TRACE_ALWAYS) {
24545 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
24546 + char flag;
24547 + flag = ((rg & mask_flags[i].mask_bitfield) ==
24548 + mask_flags[i].mask_bitfield) ? '+' : '-';
24549 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
24550 + }
24551 + }
24552 +
24553 + return count;
24554 +}
24555 +
24556 +
24557 +static int yaffs_proc_write(struct file *file, const char *buf,
24558 + unsigned long count, void *data)
24559 +{
24560 + return yaffs_proc_write_trace_options(file, buf, count, data);
24561 +}
24562 +
24563 +/* Stuff to handle installation of file systems */
24564 +struct file_system_to_install {
24565 + struct file_system_type *fst;
24566 + int installed;
24567 +};
24568 +
24569 +static struct file_system_to_install fs_to_install[] = {
24570 + {&yaffs_fs_type, 0},
24571 + {&yaffs2_fs_type, 0},
24572 + {NULL, 0}
24573 +};
24574 +
24575 +static int __init init_yaffs_fs(void)
24576 +{
24577 + int error = 0;
24578 + struct file_system_to_install *fsinst;
24579 +
24580 + T(YAFFS_TRACE_ALWAYS,
24581 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
24582 +
24583 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
24584 + T(YAFFS_TRACE_ALWAYS,
24585 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
24586 +#endif
24587 +
24588 +
24589 +
24590 +
24591 + init_MUTEX(&yaffs_context_lock);
24592 +
24593 + /* Install the proc_fs entries */
24594 + my_proc_entry = create_proc_entry("yaffs",
24595 + S_IRUGO | S_IFREG,
24596 + YPROC_ROOT);
24597 +
24598 + if (my_proc_entry) {
24599 + my_proc_entry->write_proc = yaffs_proc_write;
24600 + my_proc_entry->read_proc = yaffs_proc_read;
24601 + my_proc_entry->data = NULL;
24602 + } else
24603 + return -ENOMEM;
24604 +
24605 + debug_proc_entry = create_proc_entry("yaffs_stats",
24606 + S_IRUGO | S_IFREG,
24607 + YPROC_ROOT);
24608 +
24609 + if (debug_proc_entry) {
24610 + debug_proc_entry->write_proc = NULL;
24611 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
24612 + debug_proc_entry->data = NULL;
24613 + } else
24614 + return -ENOMEM;
24615 +
24616 + /* Now add the file system entries */
24617 +
24618 + fsinst = fs_to_install;
24619 +
24620 + while (fsinst->fst && !error) {
24621 + error = register_filesystem(fsinst->fst);
24622 + if (!error)
24623 + fsinst->installed = 1;
24624 + fsinst++;
24625 + }
24626 +
24627 + /* Any errors? uninstall */
24628 + if (error) {
24629 + fsinst = fs_to_install;
24630 +
24631 + while (fsinst->fst) {
24632 + if (fsinst->installed) {
24633 + unregister_filesystem(fsinst->fst);
24634 + fsinst->installed = 0;
24635 + }
24636 + fsinst++;
24637 + }
24638 + }
24639 +
24640 + return error;
24641 +}
24642 +
24643 +static void __exit exit_yaffs_fs(void)
24644 +{
24645 +
24646 + struct file_system_to_install *fsinst;
24647 +
24648 + T(YAFFS_TRACE_ALWAYS,
24649 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
24650 +
24651 + remove_proc_entry("yaffs", YPROC_ROOT);
24652 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
24653 +
24654 + fsinst = fs_to_install;
24655 +
24656 + while (fsinst->fst) {
24657 + if (fsinst->installed) {
24658 + unregister_filesystem(fsinst->fst);
24659 + fsinst->installed = 0;
24660 + }
24661 + fsinst++;
24662 + }
24663 +}
24664 +
24665 +module_init(init_yaffs_fs)
24666 +module_exit(exit_yaffs_fs)
24667 +
24668 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
24669 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
24670 +MODULE_LICENSE("GPL");
24671 --- /dev/null
24672 +++ b/fs/yaffs2/yaffs_yaffs1.c
24673 @@ -0,0 +1,465 @@
24674 +/*
24675 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
24676 + *
24677 + * Copyright (C) 2002-2010 Aleph One Ltd.
24678 + * for Toby Churchill Ltd and Brightstar Engineering
24679 + *
24680 + * Created by Charles Manning <charles@aleph1.co.uk>
24681 + *
24682 + * This program is free software; you can redistribute it and/or modify
24683 + * it under the terms of the GNU General Public License version 2 as
24684 + * published by the Free Software Foundation.
24685 + */
24686 +#include "yaffs_yaffs1.h"
24687 +#include "yportenv.h"
24688 +#include "yaffs_trace.h"
24689 +#include "yaffs_bitmap.h"
24690 +#include "yaffs_getblockinfo.h"
24691 +#include "yaffs_nand.h"
24692 +
24693 +
24694 +int yaffs1_scan(yaffs_dev_t *dev)
24695 +{
24696 + yaffs_ext_tags tags;
24697 + int blk;
24698 + int blockIterator;
24699 + int startIterator;
24700 + int endIterator;
24701 + int result;
24702 +
24703 + int chunk;
24704 + int c;
24705 + int deleted;
24706 + yaffs_block_state_t state;
24707 + yaffs_obj_t *hard_list = NULL;
24708 + yaffs_block_info_t *bi;
24709 + __u32 seq_number;
24710 + yaffs_obj_header *oh;
24711 + yaffs_obj_t *in;
24712 + yaffs_obj_t *parent;
24713 +
24714 + int alloc_failed = 0;
24715 +
24716 + struct yaffs_shadow_fixer_s *shadowFixerList = NULL;
24717 +
24718 +
24719 + __u8 *chunkData;
24720 +
24721 +
24722 +
24723 + T(YAFFS_TRACE_SCAN,
24724 + (TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
24725 + dev->internal_start_block, dev->internal_end_block));
24726 +
24727 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
24728 +
24729 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
24730 +
24731 + /* Scan all the blocks to determine their state */
24732 + bi = dev->block_info;
24733 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
24734 + yaffs_clear_chunk_bits(dev, blk);
24735 + bi->pages_in_use = 0;
24736 + bi->soft_del_pages = 0;
24737 +
24738 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
24739 +
24740 + bi->block_state = state;
24741 + bi->seq_number = seq_number;
24742 +
24743 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
24744 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
24745 +
24746 + T(YAFFS_TRACE_SCAN_DEBUG,
24747 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
24748 + state, seq_number));
24749 +
24750 + if (state == YAFFS_BLOCK_STATE_DEAD) {
24751 + T(YAFFS_TRACE_BAD_BLOCKS,
24752 + (TSTR("block %d is bad" TENDSTR), blk));
24753 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
24754 + T(YAFFS_TRACE_SCAN_DEBUG,
24755 + (TSTR("Block empty " TENDSTR)));
24756 + dev->n_erased_blocks++;
24757 + dev->n_free_chunks += dev->param.chunks_per_block;
24758 + }
24759 + bi++;
24760 + }
24761 +
24762 + startIterator = dev->internal_start_block;
24763 + endIterator = dev->internal_end_block;
24764 +
24765 + /* For each block.... */
24766 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
24767 + blockIterator++) {
24768 +
24769 + YYIELD();
24770 +
24771 + YYIELD();
24772 +
24773 + blk = blockIterator;
24774 +
24775 + bi = yaffs_get_block_info(dev, blk);
24776 + state = bi->block_state;
24777 +
24778 + deleted = 0;
24779 +
24780 + /* For each chunk in each block that needs scanning....*/
24781 + for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
24782 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
24783 + /* Read the tags and decide what to do */
24784 + chunk = blk * dev->param.chunks_per_block + c;
24785 +
24786 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
24787 + &tags);
24788 +
24789 + /* Let's have a good look at this chunk... */
24790 +
24791 + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) {
24792 + /* YAFFS1 only...
24793 + * A deleted chunk
24794 + */
24795 + deleted++;
24796 + dev->n_free_chunks++;
24797 + /*T((" %d %d deleted\n",blk,c)); */
24798 + } else if (!tags.chunk_used) {
24799 + /* An unassigned chunk in the block
24800 + * This means that either the block is empty or
24801 + * this is the one being allocated from
24802 + */
24803 +
24804 + if (c == 0) {
24805 + /* We're looking at the first chunk in the block so the block is unused */
24806 + state = YAFFS_BLOCK_STATE_EMPTY;
24807 + dev->n_erased_blocks++;
24808 + } else {
24809 + /* this is the block being allocated from */
24810 + T(YAFFS_TRACE_SCAN,
24811 + (TSTR
24812 + (" Allocating from %d %d" TENDSTR),
24813 + blk, c));
24814 + state = YAFFS_BLOCK_STATE_ALLOCATING;
24815 + dev->alloc_block = blk;
24816 + dev->alloc_page = c;
24817 + dev->alloc_block_finder = blk;
24818 + /* Set block finder here to encourage the allocator to go forth from here. */
24819 +
24820 + }
24821 +
24822 + dev->n_free_chunks += (dev->param.chunks_per_block - c);
24823 + } else if (tags.chunk_id > 0) {
24824 + /* chunk_id > 0 so it is a data chunk... */
24825 + unsigned int endpos;
24826 +
24827 + yaffs_set_chunk_bit(dev, blk, c);
24828 + bi->pages_in_use++;
24829 +
24830 + in = yaffs_find_or_create_by_number(dev,
24831 + tags.
24832 + obj_id,
24833 + YAFFS_OBJECT_TYPE_FILE);
24834 + /* PutChunkIntoFile checks for a clash (two data chunks with
24835 + * the same chunk_id).
24836 + */
24837 +
24838 + if (!in)
24839 + alloc_failed = 1;
24840 +
24841 + if (in) {
24842 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1))
24843 + alloc_failed = 1;
24844 + }
24845 +
24846 + endpos =
24847 + (tags.chunk_id - 1) * dev->data_bytes_per_chunk +
24848 + tags.n_bytes;
24849 + if (in &&
24850 + in->variant_type == YAFFS_OBJECT_TYPE_FILE
24851 + && in->variant.file_variant.scanned_size <
24852 + endpos) {
24853 + in->variant.file_variant.
24854 + scanned_size = endpos;
24855 + if (!dev->param.use_header_file_size) {
24856 + in->variant.file_variant.
24857 + file_size =
24858 + in->variant.file_variant.
24859 + scanned_size;
24860 + }
24861 +
24862 + }
24863 + /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
24864 + } else {
24865 + /* chunk_id == 0, so it is an ObjectHeader.
24866 + * Thus, we read in the object header and make the object
24867 + */
24868 + yaffs_set_chunk_bit(dev, blk, c);
24869 + bi->pages_in_use++;
24870 +
24871 + result = yaffs_rd_chunk_tags_nand(dev, chunk,
24872 + chunkData,
24873 + NULL);
24874 +
24875 + oh = (yaffs_obj_header *) chunkData;
24876 +
24877 + in = yaffs_find_by_number(dev,
24878 + tags.obj_id);
24879 + if (in && in->variant_type != oh->type) {
24880 + /* This should not happen, but somehow
24881 + * Wev'e ended up with an obj_id that has been reused but not yet
24882 + * deleted, and worse still it has changed type. Delete the old object.
24883 + */
24884 +
24885 + yaffs_del_obj(in);
24886 +
24887 + in = 0;
24888 + }
24889 +
24890 + in = yaffs_find_or_create_by_number(dev,
24891 + tags.
24892 + obj_id,
24893 + oh->type);
24894 +
24895 + if (!in)
24896 + alloc_failed = 1;
24897 +
24898 + if (in && oh->shadows_obj > 0) {
24899 +
24900 + struct yaffs_shadow_fixer_s *fixer;
24901 + fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s));
24902 + if (fixer) {
24903 + fixer->next = shadowFixerList;
24904 + shadowFixerList = fixer;
24905 + fixer->obj_id = tags.obj_id;
24906 + fixer->shadowed_id = oh->shadows_obj;
24907 + T(YAFFS_TRACE_SCAN,
24908 + (TSTR
24909 + (" Shadow fixer: %d shadows %d" TENDSTR),
24910 + fixer->obj_id, fixer->shadowed_id));
24911 +
24912 + }
24913 +
24914 + }
24915 +
24916 + if (in && in->valid) {
24917 + /* We have already filled this one. We have a duplicate and need to resolve it. */
24918 +
24919 + unsigned existingSerial = in->serial;
24920 + unsigned newSerial = tags.serial_number;
24921 +
24922 + if (((existingSerial + 1) & 3) == newSerial) {
24923 + /* Use new one - destroy the exisiting one */
24924 + yaffs_chunk_del(dev,
24925 + in->hdr_chunk,
24926 + 1, __LINE__);
24927 + in->valid = 0;
24928 + } else {
24929 + /* Use existing - destroy this one. */
24930 + yaffs_chunk_del(dev, chunk, 1,
24931 + __LINE__);
24932 + }
24933 + }
24934 +
24935 + if (in && !in->valid &&
24936 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
24937 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
24938 + /* We only load some info, don't fiddle with directory structure */
24939 + in->valid = 1;
24940 + in->variant_type = oh->type;
24941 +
24942 + in->yst_mode = oh->yst_mode;
24943 +#ifdef CONFIG_YAFFS_WINCE
24944 + in->win_atime[0] = oh->win_atime[0];
24945 + in->win_ctime[0] = oh->win_ctime[0];
24946 + in->win_mtime[0] = oh->win_mtime[0];
24947 + in->win_atime[1] = oh->win_atime[1];
24948 + in->win_ctime[1] = oh->win_ctime[1];
24949 + in->win_mtime[1] = oh->win_mtime[1];
24950 +#else
24951 + in->yst_uid = oh->yst_uid;
24952 + in->yst_gid = oh->yst_gid;
24953 + in->yst_atime = oh->yst_atime;
24954 + in->yst_mtime = oh->yst_mtime;
24955 + in->yst_ctime = oh->yst_ctime;
24956 + in->yst_rdev = oh->yst_rdev;
24957 +#endif
24958 + in->hdr_chunk = chunk;
24959 + in->serial = tags.serial_number;
24960 +
24961 + } else if (in && !in->valid) {
24962 + /* we need to load this info */
24963 +
24964 + in->valid = 1;
24965 + in->variant_type = oh->type;
24966 +
24967 + in->yst_mode = oh->yst_mode;
24968 +#ifdef CONFIG_YAFFS_WINCE
24969 + in->win_atime[0] = oh->win_atime[0];
24970 + in->win_ctime[0] = oh->win_ctime[0];
24971 + in->win_mtime[0] = oh->win_mtime[0];
24972 + in->win_atime[1] = oh->win_atime[1];
24973 + in->win_ctime[1] = oh->win_ctime[1];
24974 + in->win_mtime[1] = oh->win_mtime[1];
24975 +#else
24976 + in->yst_uid = oh->yst_uid;
24977 + in->yst_gid = oh->yst_gid;
24978 + in->yst_atime = oh->yst_atime;
24979 + in->yst_mtime = oh->yst_mtime;
24980 + in->yst_ctime = oh->yst_ctime;
24981 + in->yst_rdev = oh->yst_rdev;
24982 +#endif
24983 + in->hdr_chunk = chunk;
24984 + in->serial = tags.serial_number;
24985 +
24986 + yaffs_set_obj_name_from_oh(in, oh);
24987 + in->dirty = 0;
24988 +
24989 + /* directory stuff...
24990 + * hook up to parent
24991 + */
24992 +
24993 + parent =
24994 + yaffs_find_or_create_by_number
24995 + (dev, oh->parent_obj_id,
24996 + YAFFS_OBJECT_TYPE_DIRECTORY);
24997 + if (!parent)
24998 + alloc_failed = 1;
24999 + if (parent && parent->variant_type ==
25000 + YAFFS_OBJECT_TYPE_UNKNOWN) {
25001 + /* Set up as a directory */
25002 + parent->variant_type =
25003 + YAFFS_OBJECT_TYPE_DIRECTORY;
25004 + YINIT_LIST_HEAD(&parent->variant.
25005 + dir_variant.
25006 + children);
25007 + } else if (!parent || parent->variant_type !=
25008 + YAFFS_OBJECT_TYPE_DIRECTORY) {
25009 + /* Hoosterman, another problem....
25010 + * We're trying to use a non-directory as a directory
25011 + */
25012 +
25013 + T(YAFFS_TRACE_ERROR,
25014 + (TSTR
25015 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
25016 + TENDSTR)));
25017 + parent = dev->lost_n_found;
25018 + }
25019 +
25020 + yaffs_add_obj_to_dir(parent, in);
25021 +
25022 + if (0 && (parent == dev->del_dir ||
25023 + parent == dev->unlinked_dir)) {
25024 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
25025 + dev->n_deleted_files++;
25026 + }
25027 + /* Note re hardlinks.
25028 + * Since we might scan a hardlink before its equivalent object is scanned
25029 + * we put them all in a list.
25030 + * After scanning is complete, we should have all the objects, so we run through this
25031 + * list and fix up all the chains.
25032 + */
25033 +
25034 + switch (in->variant_type) {
25035 + case YAFFS_OBJECT_TYPE_UNKNOWN:
25036 + /* Todo got a problem */
25037 + break;
25038 + case YAFFS_OBJECT_TYPE_FILE:
25039 + if (dev->param.use_header_file_size)
25040 +
25041 + in->variant.file_variant.
25042 + file_size =
25043 + oh->file_size;
25044 +
25045 + break;
25046 + case YAFFS_OBJECT_TYPE_HARDLINK:
25047 + in->variant.hardlink_variant.
25048 + equiv_id =
25049 + oh->equiv_id;
25050 + in->hard_links.next =
25051 + (struct ylist_head *)
25052 + hard_list;
25053 + hard_list = in;
25054 + break;
25055 + case YAFFS_OBJECT_TYPE_DIRECTORY:
25056 + /* Do nothing */
25057 + break;
25058 + case YAFFS_OBJECT_TYPE_SPECIAL:
25059 + /* Do nothing */
25060 + break;
25061 + case YAFFS_OBJECT_TYPE_SYMLINK:
25062 + in->variant.symlink_variant.alias =
25063 + yaffs_clone_str(oh->alias);
25064 + if (!in->variant.symlink_variant.alias)
25065 + alloc_failed = 1;
25066 + break;
25067 + }
25068 +
25069 + }
25070 + }
25071 + }
25072 +
25073 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
25074 + /* If we got this far while scanning, then the block is fully allocated.*/
25075 + state = YAFFS_BLOCK_STATE_FULL;
25076 + }
25077 +
25078 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
25079 + /* If the block was partially allocated then treat it as fully allocated.*/
25080 + state = YAFFS_BLOCK_STATE_FULL;
25081 + dev->alloc_block = -1;
25082 + }
25083 +
25084 + bi->block_state = state;
25085 +
25086 + /* Now let's see if it was dirty */
25087 + if (bi->pages_in_use == 0 &&
25088 + !bi->has_shrink_hdr &&
25089 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
25090 + yaffs_block_became_dirty(dev, blk);
25091 + }
25092 +
25093 + }
25094 +
25095 +
25096 + /* Ok, we've done all the scanning.
25097 + * Fix up the hard link chains.
25098 + * We should now have scanned all the objects, now it's time to add these
25099 + * hardlinks.
25100 + */
25101 +
25102 + yaffs_link_fixup(dev, hard_list);
25103 +
25104 + /* Fix up any shadowed objects */
25105 + {
25106 + struct yaffs_shadow_fixer_s *fixer;
25107 + yaffs_obj_t *obj;
25108 +
25109 + while (shadowFixerList) {
25110 + fixer = shadowFixerList;
25111 + shadowFixerList = fixer->next;
25112 + /* Complete the rename transaction by deleting the shadowed object
25113 + * then setting the object header to unshadowed.
25114 + */
25115 + obj = yaffs_find_by_number(dev, fixer->shadowed_id);
25116 + if (obj)
25117 + yaffs_del_obj(obj);
25118 +
25119 + obj = yaffs_find_by_number(dev, fixer->obj_id);
25120 +
25121 + if (obj)
25122 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
25123 +
25124 + YFREE(fixer);
25125 + }
25126 + }
25127 +
25128 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
25129 +
25130 + if (alloc_failed)
25131 + return YAFFS_FAIL;
25132 +
25133 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
25134 +
25135 +
25136 + return YAFFS_OK;
25137 +}
25138 +
25139 --- /dev/null
25140 +++ b/fs/yaffs2/yaffs_yaffs1.h
25141 @@ -0,0 +1,22 @@
25142 +/*
25143 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
25144 + *
25145 + * Copyright (C) 2002-2010 Aleph One Ltd.
25146 + * for Toby Churchill Ltd and Brightstar Engineering
25147 + *
25148 + * Created by Charles Manning <charles@aleph1.co.uk>
25149 + *
25150 + * This program is free software; you can redistribute it and/or modify
25151 + * it under the terms of the GNU Lesser General Public License version 2.1 as
25152 + * published by the Free Software Foundation.
25153 + *
25154 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
25155 + */
25156 +
25157 +#ifndef __YAFFS_YAFFS1_H__
25158 +#define __YAFFS_YAFFS1_H__
25159 +
25160 +#include "yaffs_guts.h"
25161 +int yaffs1_scan(yaffs_dev_t *dev);
25162 +
25163 +#endif
25164 --- /dev/null
25165 +++ b/fs/yaffs2/yaffs_yaffs2.c
25166 @@ -0,0 +1,1540 @@
25167 +/*
25168 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
25169 + *
25170 + * Copyright (C) 2002-2010 Aleph One Ltd.
25171 + * for Toby Churchill Ltd and Brightstar Engineering
25172 + *
25173 + * Created by Charles Manning <charles@aleph1.co.uk>
25174 + *
25175 + * This program is free software; you can redistribute it and/or modify
25176 + * it under the terms of the GNU General Public License version 2 as
25177 + * published by the Free Software Foundation.
25178 + */
25179 +
25180 +
25181 +#include "yaffs_guts.h"
25182 +#include "yaffs_trace.h"
25183 +#include "yaffs_yaffs2.h"
25184 +#include "yaffs_checkptrw.h"
25185 +#include "yaffs_bitmap.h"
25186 +#include "yaffs_qsort.h"
25187 +#include "yaffs_nand.h"
25188 +#include "yaffs_getblockinfo.h"
25189 +#include "yaffs_verify.h"
25190 +
25191 +/*
25192 + * Checkpoints are really no benefit on very small partitions.
25193 + *
25194 + * To save space on small partitions don't bother with checkpoints unless
25195 + * the partition is at least this big.
25196 + */
25197 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
25198 +
25199 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
25200 +
25201 +
25202 +/*
25203 + * Oldest Dirty Sequence Number handling.
25204 + */
25205 +
25206 +/* yaffs_calc_oldest_dirty_seq()
25207 + * yaffs2_find_oldest_dirty_seq()
25208 + * Calculate the oldest dirty sequence number if we don't know it.
25209 + */
25210 +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev)
25211 +{
25212 + int i;
25213 + unsigned seq;
25214 + unsigned block_no = 0;
25215 + yaffs_block_info_t *b;
25216 +
25217 + if(!dev->param.is_yaffs2)
25218 + return;
25219 +
25220 + /* Find the oldest dirty sequence number. */
25221 + seq = dev->seq_number + 1;
25222 + b = dev->block_info;
25223 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
25224 + if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
25225 + (b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block &&
25226 + b->seq_number < seq) {
25227 + seq = b->seq_number;
25228 + block_no = i;
25229 + }
25230 + b++;
25231 + }
25232 +
25233 + if(block_no){
25234 + dev->oldest_dirty_seq = seq;
25235 + dev->oldest_dirty_block = block_no;
25236 + }
25237 +
25238 +}
25239 +
25240 +
25241 +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev)
25242 +{
25243 + if(!dev->param.is_yaffs2)
25244 + return;
25245 +
25246 + if(!dev->oldest_dirty_seq)
25247 + yaffs_calc_oldest_dirty_seq(dev);
25248 +}
25249 +
25250 +/*
25251 + * yaffs_clear_oldest_dirty_seq()
25252 + * Called when a block is erased or marked bad. (ie. when its seq_number
25253 + * becomes invalid). If the value matches the oldest then we clear
25254 + * dev->oldest_dirty_seq to force its recomputation.
25255 + */
25256 +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi)
25257 +{
25258 +
25259 + if(!dev->param.is_yaffs2)
25260 + return;
25261 +
25262 + if(!bi || bi->seq_number == dev->oldest_dirty_seq){
25263 + dev->oldest_dirty_seq = 0;
25264 + dev->oldest_dirty_block = 0;
25265 + }
25266 +}
25267 +
25268 +/*
25269 + * yaffs2_update_oldest_dirty_seq()
25270 + * Update the oldest dirty sequence number whenever we dirty a block.
25271 + * Only do this if the oldest_dirty_seq is actually being tracked.
25272 + */
25273 +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi)
25274 +{
25275 + if(!dev->param.is_yaffs2)
25276 + return;
25277 +
25278 + if(dev->oldest_dirty_seq){
25279 + if(dev->oldest_dirty_seq > bi->seq_number){
25280 + dev->oldest_dirty_seq = bi->seq_number;
25281 + dev->oldest_dirty_block = block_no;
25282 + }
25283 + }
25284 +}
25285 +
25286 +int yaffs_block_ok_for_gc(yaffs_dev_t *dev,
25287 + yaffs_block_info_t *bi)
25288 +{
25289 +
25290 + if (!dev->param.is_yaffs2)
25291 + return 1; /* disqualification only applies to yaffs2. */
25292 +
25293 + if (!bi->has_shrink_hdr)
25294 + return 1; /* can gc */
25295 +
25296 + yaffs2_find_oldest_dirty_seq(dev);
25297 +
25298 + /* Can't do gc of this block if there are any blocks older than this one that have
25299 + * discarded pages.
25300 + */
25301 + return (bi->seq_number <= dev->oldest_dirty_seq);
25302 +}
25303 +
25304 +/*
25305 + * yaffs2_find_refresh_block()
25306 + * periodically finds the oldest full block by sequence number for refreshing.
25307 + * Only for yaffs2.
25308 + */
25309 +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev)
25310 +{
25311 + __u32 b ;
25312 +
25313 + __u32 oldest = 0;
25314 + __u32 oldestSequence = 0;
25315 +
25316 + yaffs_block_info_t *bi;
25317 +
25318 + if(!dev->param.is_yaffs2)
25319 + return oldest;
25320 +
25321 + /*
25322 + * If refresh period < 10 then refreshing is disabled.
25323 + */
25324 + if(dev->param.refresh_period < 10)
25325 + return oldest;
25326 +
25327 + /*
25328 + * Fix broken values.
25329 + */
25330 + if(dev->refresh_skip > dev->param.refresh_period)
25331 + dev->refresh_skip = dev->param.refresh_period;
25332 +
25333 + if(dev->refresh_skip > 0)
25334 + return oldest;
25335 +
25336 + /*
25337 + * Refresh skip is now zero.
25338 + * We'll do a refresh this time around....
25339 + * Update the refresh skip and find the oldest block.
25340 + */
25341 + dev->refresh_skip = dev->param.refresh_period;
25342 + dev->refresh_count++;
25343 + bi = dev->block_info;
25344 + for (b = dev->internal_start_block; b <=dev->internal_end_block; b++){
25345 +
25346 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL){
25347 +
25348 + if(oldest < 1 ||
25349 + bi->seq_number < oldestSequence){
25350 + oldest = b;
25351 + oldestSequence = bi->seq_number;
25352 + }
25353 + }
25354 + bi++;
25355 + }
25356 +
25357 + if (oldest > 0) {
25358 + T(YAFFS_TRACE_GC,
25359 + (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR),
25360 + dev->refresh_count, oldest, oldestSequence));
25361 + }
25362 +
25363 + return oldest;
25364 +}
25365 +
25366 +int yaffs2_checkpt_required(yaffs_dev_t *dev)
25367 +{
25368 + int nblocks;
25369 +
25370 + if(!dev->param.is_yaffs2)
25371 + return 0;
25372 +
25373 + nblocks = dev->internal_end_block - dev->internal_start_block + 1 ;
25374 +
25375 + return !dev->param.skip_checkpt_wr &&
25376 + !dev->read_only &&
25377 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
25378 +}
25379 +
25380 +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev)
25381 +{
25382 + int retval;
25383 +
25384 + if(!dev->param.is_yaffs2)
25385 + return 0;
25386 +
25387 + if (!dev->checkpoint_blocks_required &&
25388 + yaffs2_checkpt_required(dev)){
25389 + /* Not a valid value so recalculate */
25390 + int n_bytes = 0;
25391 + int nBlocks;
25392 + int devBlocks = (dev->param.end_block - dev->param.start_block + 1);
25393 +
25394 + n_bytes += sizeof(yaffs_checkpt_validty_t);
25395 + n_bytes += sizeof(yaffs_checkpt_dev_t);
25396 + n_bytes += devBlocks * sizeof(yaffs_block_info_t);
25397 + n_bytes += devBlocks * dev->chunk_bit_stride;
25398 + n_bytes += (sizeof(yaffs_checkpt_obj_t) + sizeof(__u32)) * (dev->n_obj);
25399 + n_bytes += (dev->tnode_size + sizeof(__u32)) * (dev->n_tnodes);
25400 + n_bytes += sizeof(yaffs_checkpt_validty_t);
25401 + n_bytes += sizeof(__u32); /* checksum*/
25402 +
25403 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
25404 +
25405 + nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3;
25406 +
25407 + dev->checkpoint_blocks_required = nBlocks;
25408 + }
25409 +
25410 + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
25411 + if(retval < 0)
25412 + retval = 0;
25413 + return retval;
25414 +}
25415 +
25416 +/*--------------------- Checkpointing --------------------*/
25417 +
25418 +
25419 +static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head)
25420 +{
25421 + yaffs_checkpt_validty_t cp;
25422 +
25423 + memset(&cp, 0, sizeof(cp));
25424 +
25425 + cp.struct_type = sizeof(cp);
25426 + cp.magic = YAFFS_MAGIC;
25427 + cp.version = YAFFS_CHECKPOINT_VERSION;
25428 + cp.head = (head) ? 1 : 0;
25429 +
25430 + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
25431 + 1 : 0;
25432 +}
25433 +
25434 +static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head)
25435 +{
25436 + yaffs_checkpt_validty_t cp;
25437 + int ok;
25438 +
25439 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25440 +
25441 + if (ok)
25442 + ok = (cp.struct_type == sizeof(cp)) &&
25443 + (cp.magic == YAFFS_MAGIC) &&
25444 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
25445 + (cp.head == ((head) ? 1 : 0));
25446 + return ok ? 1 : 0;
25447 +}
25448 +
25449 +static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp,
25450 + yaffs_dev_t *dev)
25451 +{
25452 + cp->n_erased_blocks = dev->n_erased_blocks;
25453 + cp->alloc_block = dev->alloc_block;
25454 + cp->alloc_page = dev->alloc_page;
25455 + cp->n_free_chunks = dev->n_free_chunks;
25456 +
25457 + cp->n_deleted_files = dev->n_deleted_files;
25458 + cp->n_unlinked_files = dev->n_unlinked_files;
25459 + cp->n_bg_deletions = dev->n_bg_deletions;
25460 + cp->seq_number = dev->seq_number;
25461 +
25462 +}
25463 +
25464 +static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev,
25465 + yaffs_checkpt_dev_t *cp)
25466 +{
25467 + dev->n_erased_blocks = cp->n_erased_blocks;
25468 + dev->alloc_block = cp->alloc_block;
25469 + dev->alloc_page = cp->alloc_page;
25470 + dev->n_free_chunks = cp->n_free_chunks;
25471 +
25472 + dev->n_deleted_files = cp->n_deleted_files;
25473 + dev->n_unlinked_files = cp->n_unlinked_files;
25474 + dev->n_bg_deletions = cp->n_bg_deletions;
25475 + dev->seq_number = cp->seq_number;
25476 +}
25477 +
25478 +
25479 +static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev)
25480 +{
25481 + yaffs_checkpt_dev_t cp;
25482 + __u32 n_bytes;
25483 + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
25484 +
25485 + int ok;
25486 +
25487 + /* Write device runtime values*/
25488 + yaffs2_dev_to_checkpt_dev(&cp, dev);
25489 + cp.struct_type = sizeof(cp);
25490 +
25491 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25492 +
25493 + /* Write block info */
25494 + if (ok) {
25495 + n_bytes = nBlocks * sizeof(yaffs_block_info_t);
25496 + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
25497 + }
25498 +
25499 + /* Write chunk bits */
25500 + if (ok) {
25501 + n_bytes = nBlocks * dev->chunk_bit_stride;
25502 + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
25503 + }
25504 + return ok ? 1 : 0;
25505 +
25506 +}
25507 +
25508 +static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev)
25509 +{
25510 + yaffs_checkpt_dev_t cp;
25511 + __u32 n_bytes;
25512 + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
25513 +
25514 + int ok;
25515 +
25516 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25517 + if (!ok)
25518 + return 0;
25519 +
25520 + if (cp.struct_type != sizeof(cp))
25521 + return 0;
25522 +
25523 +
25524 + yaffs_checkpt_dev_to_dev(dev, &cp);
25525 +
25526 + n_bytes = nBlocks * sizeof(yaffs_block_info_t);
25527 +
25528 + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
25529 +
25530 + if (!ok)
25531 + return 0;
25532 + n_bytes = nBlocks * dev->chunk_bit_stride;
25533 +
25534 + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
25535 +
25536 + return ok ? 1 : 0;
25537 +}
25538 +
25539 +static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp,
25540 + yaffs_obj_t *obj)
25541 +{
25542 +
25543 + cp->obj_id = obj->obj_id;
25544 + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
25545 + cp->hdr_chunk = obj->hdr_chunk;
25546 + cp->variant_type = obj->variant_type;
25547 + cp->deleted = obj->deleted;
25548 + cp->soft_del = obj->soft_del;
25549 + cp->unlinked = obj->unlinked;
25550 + cp->fake = obj->fake;
25551 + cp->rename_allowed = obj->rename_allowed;
25552 + cp->unlink_allowed = obj->unlink_allowed;
25553 + cp->serial = obj->serial;
25554 + cp->n_data_chunks = obj->n_data_chunks;
25555 +
25556 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25557 + cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
25558 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
25559 + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
25560 +}
25561 +
25562 +static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp)
25563 +{
25564 +
25565 + yaffs_obj_t *parent;
25566 +
25567 + if (obj->variant_type != cp->variant_type) {
25568 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
25569 + TCONT("chunk %d does not match existing object type %d")
25570 + TENDSTR), cp->obj_id, cp->variant_type, cp->hdr_chunk,
25571 + obj->variant_type));
25572 + return 0;
25573 + }
25574 +
25575 + obj->obj_id = cp->obj_id;
25576 +
25577 + if (cp->parent_id)
25578 + parent = yaffs_find_or_create_by_number(
25579 + obj->my_dev,
25580 + cp->parent_id,
25581 + YAFFS_OBJECT_TYPE_DIRECTORY);
25582 + else
25583 + parent = NULL;
25584 +
25585 + if (parent) {
25586 + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
25587 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
25588 + TCONT(" chunk %d Parent type, %d, not directory")
25589 + TENDSTR),
25590 + cp->obj_id, cp->parent_id, cp->variant_type,
25591 + cp->hdr_chunk, parent->variant_type));
25592 + return 0;
25593 + }
25594 + yaffs_add_obj_to_dir(parent, obj);
25595 + }
25596 +
25597 + obj->hdr_chunk = cp->hdr_chunk;
25598 + obj->variant_type = cp->variant_type;
25599 + obj->deleted = cp->deleted;
25600 + obj->soft_del = cp->soft_del;
25601 + obj->unlinked = cp->unlinked;
25602 + obj->fake = cp->fake;
25603 + obj->rename_allowed = cp->rename_allowed;
25604 + obj->unlink_allowed = cp->unlink_allowed;
25605 + obj->serial = cp->serial;
25606 + obj->n_data_chunks = cp->n_data_chunks;
25607 +
25608 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25609 + obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
25610 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
25611 + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
25612 +
25613 + if (obj->hdr_chunk > 0)
25614 + obj->lazy_loaded = 1;
25615 + return 1;
25616 +}
25617 +
25618 +
25619 +
25620 +static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
25621 + __u32 level, int chunk_offset)
25622 +{
25623 + int i;
25624 + yaffs_dev_t *dev = in->my_dev;
25625 + int ok = 1;
25626 +
25627 + if (tn) {
25628 + if (level > 0) {
25629 +
25630 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
25631 + if (tn->internal[i]) {
25632 + ok = yaffs2_checkpt_tnode_worker(in,
25633 + tn->internal[i],
25634 + level - 1,
25635 + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
25636 + }
25637 + }
25638 + } else if (level == 0) {
25639 + __u32 baseOffset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
25640 + ok = (yaffs2_checkpt_wr(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
25641 + if (ok)
25642 + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size);
25643 + }
25644 + }
25645 +
25646 + return ok;
25647 +
25648 +}
25649 +
25650 +static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj)
25651 +{
25652 + __u32 endMarker = ~0;
25653 + int ok = 1;
25654 +
25655 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
25656 + ok = yaffs2_checkpt_tnode_worker(obj,
25657 + obj->variant.file_variant.top,
25658 + obj->variant.file_variant.top_level,
25659 + 0);
25660 + if (ok)
25661 + ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) ==
25662 + sizeof(endMarker));
25663 + }
25664 +
25665 + return ok ? 1 : 0;
25666 +}
25667 +
25668 +static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj)
25669 +{
25670 + __u32 baseChunk;
25671 + int ok = 1;
25672 + yaffs_dev_t *dev = obj->my_dev;
25673 + yaffs_file_s *fileStructPtr = &obj->variant.file_variant;
25674 + yaffs_tnode_t *tn;
25675 + int nread = 0;
25676 +
25677 + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
25678 +
25679 + while (ok && (~baseChunk)) {
25680 + nread++;
25681 + /* Read level 0 tnode */
25682 +
25683 +
25684 + tn = yaffs_get_tnode(dev);
25685 + if (tn){
25686 + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size);
25687 + } else
25688 + ok = 0;
25689 +
25690 + if (tn && ok)
25691 + ok = yaffs_add_find_tnode_0(dev,
25692 + fileStructPtr,
25693 + baseChunk,
25694 + tn) ? 1 : 0;
25695 +
25696 + if (ok)
25697 + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
25698 +
25699 + }
25700 +
25701 + T(YAFFS_TRACE_CHECKPOINT, (
25702 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
25703 + nread, baseChunk, ok));
25704 +
25705 + return ok ? 1 : 0;
25706 +}
25707 +
25708 +
25709 +static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev)
25710 +{
25711 + yaffs_obj_t *obj;
25712 + yaffs_checkpt_obj_t cp;
25713 + int i;
25714 + int ok = 1;
25715 + struct ylist_head *lh;
25716 +
25717 +
25718 + /* Iterate through the objects in each hash entry,
25719 + * dumping them to the checkpointing stream.
25720 + */
25721 +
25722 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
25723 + ylist_for_each(lh, &dev->obj_bucket[i].list) {
25724 + if (lh) {
25725 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
25726 + if (!obj->defered_free) {
25727 + yaffs2_obj_checkpt_obj(&cp, obj);
25728 + cp.struct_type = sizeof(cp);
25729 +
25730 + T(YAFFS_TRACE_CHECKPOINT, (
25731 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
25732 + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk, obj));
25733 +
25734 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25735 +
25736 + if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25737 + ok = yaffs2_wr_checkpt_tnodes(obj);
25738 + }
25739 + }
25740 + }
25741 + }
25742 +
25743 + /* Dump end of list */
25744 + memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t));
25745 + cp.struct_type = sizeof(cp);
25746 +
25747 + if (ok)
25748 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25749 +
25750 + return ok ? 1 : 0;
25751 +}
25752 +
25753 +static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev)
25754 +{
25755 + yaffs_obj_t *obj;
25756 + yaffs_checkpt_obj_t cp;
25757 + int ok = 1;
25758 + int done = 0;
25759 + yaffs_obj_t *hard_list = NULL;
25760 +
25761 + while (ok && !done) {
25762 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25763 + if (cp.struct_type != sizeof(cp)) {
25764 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
25765 + cp.struct_type, (int)sizeof(cp), ok));
25766 + ok = 0;
25767 + }
25768 +
25769 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
25770 + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk));
25771 +
25772 + if (ok && cp.obj_id == ~0)
25773 + done = 1;
25774 + else if (ok) {
25775 + obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type);
25776 + if (obj) {
25777 + ok = taffs2_checkpt_obj_to_obj(obj, &cp);
25778 + if (!ok)
25779 + break;
25780 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
25781 + ok = yaffs2_rd_checkpt_tnodes(obj);
25782 + } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
25783 + obj->hard_links.next =
25784 + (struct ylist_head *) hard_list;
25785 + hard_list = obj;
25786 + }
25787 + } else
25788 + ok = 0;
25789 + }
25790 + }
25791 +
25792 + if (ok)
25793 + yaffs_link_fixup(dev, hard_list);
25794 +
25795 + return ok ? 1 : 0;
25796 +}
25797 +
25798 +static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev)
25799 +{
25800 + __u32 checkpt_sum;
25801 + int ok;
25802 +
25803 + yaffs2_get_checkpt_sum(dev, &checkpt_sum);
25804 +
25805 + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum));
25806 +
25807 + if (!ok)
25808 + return 0;
25809 +
25810 + return 1;
25811 +}
25812 +
25813 +static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev)
25814 +{
25815 + __u32 checkpt_sum0;
25816 + __u32 checkpt_sum1;
25817 + int ok;
25818 +
25819 + yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
25820 +
25821 + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1));
25822 +
25823 + if (!ok)
25824 + return 0;
25825 +
25826 + if (checkpt_sum0 != checkpt_sum1)
25827 + return 0;
25828 +
25829 + return 1;
25830 +}
25831 +
25832 +
25833 +static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev)
25834 +{
25835 + int ok = 1;
25836 +
25837 + if (!yaffs2_checkpt_required(dev)) {
25838 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
25839 + ok = 0;
25840 + }
25841 +
25842 + if (ok)
25843 + ok = yaffs2_checkpt_open(dev, 1);
25844 +
25845 + if (ok) {
25846 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
25847 + ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
25848 + }
25849 + if (ok) {
25850 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
25851 + ok = yaffs2_wr_checkpt_dev(dev);
25852 + }
25853 + if (ok) {
25854 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
25855 + ok = yaffs2_wr_checkpt_objs(dev);
25856 + }
25857 + if (ok) {
25858 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
25859 + ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
25860 + }
25861 +
25862 + if (ok)
25863 + ok = yaffs2_wr_checkpt_sum(dev);
25864 +
25865 + if (!yaffs_checkpt_close(dev))
25866 + ok = 0;
25867 +
25868 + if (ok)
25869 + dev->is_checkpointed = 1;
25870 + else
25871 + dev->is_checkpointed = 0;
25872 +
25873 + return dev->is_checkpointed;
25874 +}
25875 +
25876 +static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev)
25877 +{
25878 + int ok = 1;
25879 +
25880 + if(!dev->param.is_yaffs2)
25881 + ok = 0;
25882 +
25883 + if (ok && dev->param.skip_checkpt_rd) {
25884 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
25885 + ok = 0;
25886 + }
25887 +
25888 + if (ok)
25889 + ok = yaffs2_checkpt_open(dev, 0); /* open for read */
25890 +
25891 + if (ok) {
25892 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
25893 + ok = yaffs2_rd_checkpt_validty_marker(dev, 1);
25894 + }
25895 + if (ok) {
25896 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
25897 + ok = yaffs2_rd_checkpt_dev(dev);
25898 + }
25899 + if (ok) {
25900 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
25901 + ok = yaffs2_rd_checkpt_objs(dev);
25902 + }
25903 + if (ok) {
25904 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
25905 + ok = yaffs2_rd_checkpt_validty_marker(dev, 0);
25906 + }
25907 +
25908 + if (ok) {
25909 + ok = yaffs2_rd_checkpt_sum(dev);
25910 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
25911 + }
25912 +
25913 + if (!yaffs_checkpt_close(dev))
25914 + ok = 0;
25915 +
25916 + if (ok)
25917 + dev->is_checkpointed = 1;
25918 + else
25919 + dev->is_checkpointed = 0;
25920 +
25921 + return ok ? 1 : 0;
25922 +
25923 +}
25924 +
25925 +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev)
25926 +{
25927 + if (dev->is_checkpointed ||
25928 + dev->blocks_in_checkpt > 0) {
25929 + dev->is_checkpointed = 0;
25930 + yaffs2_checkpt_invalidate_stream(dev);
25931 + }
25932 + if (dev->param.sb_dirty_fn)
25933 + dev->param.sb_dirty_fn(dev);
25934 +}
25935 +
25936 +
25937 +int yaffs_checkpoint_save(yaffs_dev_t *dev)
25938 +{
25939 +
25940 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
25941 +
25942 + yaffs_verify_objects(dev);
25943 + yaffs_verify_blocks(dev);
25944 + yaffs_verify_free_chunks(dev);
25945 +
25946 + if (!dev->is_checkpointed) {
25947 + yaffs2_checkpt_invalidate(dev);
25948 + yaffs2_wr_checkpt_data(dev);
25949 + }
25950 +
25951 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
25952 +
25953 + return dev->is_checkpointed;
25954 +}
25955 +
25956 +int yaffs2_checkpt_restore(yaffs_dev_t *dev)
25957 +{
25958 + int retval;
25959 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
25960 +
25961 + retval = yaffs2_rd_checkpt_data(dev);
25962 +
25963 + if (dev->is_checkpointed) {
25964 + yaffs_verify_objects(dev);
25965 + yaffs_verify_blocks(dev);
25966 + yaffs_verify_free_chunks(dev);
25967 + }
25968 +
25969 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
25970 +
25971 + return retval;
25972 +}
25973 +
25974 +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size)
25975 +{
25976 + /* if newsSize > oldFileSize.
25977 + * We're going to be writing a hole.
25978 + * If the hole is small then write zeros otherwise write a start of hole marker.
25979 + */
25980 +
25981 +
25982 + loff_t oldFileSize;
25983 + int increase;
25984 + int smallHole ;
25985 + int result = YAFFS_OK;
25986 + yaffs_dev_t *dev = NULL;
25987 +
25988 + __u8 *localBuffer = NULL;
25989 +
25990 + int smallIncreaseOk = 0;
25991 +
25992 + if(!obj)
25993 + return YAFFS_FAIL;
25994 +
25995 + if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
25996 + return YAFFS_FAIL;
25997 +
25998 + dev = obj->my_dev;
25999 +
26000 + /* Bail out if not yaffs2 mode */
26001 + if(!dev->param.is_yaffs2)
26002 + return YAFFS_OK;
26003 +
26004 + oldFileSize = obj->variant.file_variant.file_size;
26005 +
26006 + if (new_size <= oldFileSize)
26007 + return YAFFS_OK;
26008 +
26009 + increase = new_size - oldFileSize;
26010 +
26011 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
26012 + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
26013 + smallHole = 1;
26014 + else
26015 + smallHole = 0;
26016 +
26017 + if(smallHole)
26018 + localBuffer= yaffs_get_temp_buffer(dev, __LINE__);
26019 +
26020 + if(localBuffer){
26021 + /* fill hole with zero bytes */
26022 + int pos = oldFileSize;
26023 + int thisWrite;
26024 + int written;
26025 + memset(localBuffer,0,dev->data_bytes_per_chunk);
26026 + smallIncreaseOk = 1;
26027 +
26028 + while(increase > 0 && smallIncreaseOk){
26029 + thisWrite = increase;
26030 + if(thisWrite > dev->data_bytes_per_chunk)
26031 + thisWrite = dev->data_bytes_per_chunk;
26032 + written = yaffs_do_file_wr(obj,localBuffer,pos,thisWrite,0);
26033 + if(written == thisWrite){
26034 + pos += thisWrite;
26035 + increase -= thisWrite;
26036 + } else
26037 + smallIncreaseOk = 0;
26038 + }
26039 +
26040 + yaffs_release_temp_buffer(dev,localBuffer,__LINE__);
26041 +
26042 + /* If we were out of space then reverse any chunks we've added */
26043 + if(!smallIncreaseOk)
26044 + yaffs_resize_file_down(obj, oldFileSize);
26045 + }
26046 +
26047 + if (!smallIncreaseOk &&
26048 + obj->parent &&
26049 + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
26050 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED){
26051 + /* Write a hole start header with the old file size */
26052 + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
26053 + }
26054 +
26055 + return result;
26056 +
26057 +}
26058 +
26059 +
26060 +typedef struct {
26061 + int seq;
26062 + int block;
26063 +} yaffs_BlockIndex;
26064 +
26065 +
26066 +static int yaffs2_ybicmp(const void *a, const void *b)
26067 +{
26068 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
26069 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
26070 + register int ablock = ((yaffs_BlockIndex *)a)->block;
26071 + register int bblock = ((yaffs_BlockIndex *)b)->block;
26072 + if (aseq == bseq)
26073 + return ablock - bblock;
26074 + else
26075 + return aseq - bseq;
26076 +}
26077 +
26078 +int yaffs2_scan_backwards(yaffs_dev_t *dev)
26079 +{
26080 + yaffs_ext_tags tags;
26081 + int blk;
26082 + int blockIterator;
26083 + int startIterator;
26084 + int endIterator;
26085 + int nBlocksToScan = 0;
26086 +
26087 + int chunk;
26088 + int result;
26089 + int c;
26090 + int deleted;
26091 + yaffs_block_state_t state;
26092 + yaffs_obj_t *hard_list = NULL;
26093 + yaffs_block_info_t *bi;
26094 + __u32 seq_number;
26095 + yaffs_obj_header *oh;
26096 + yaffs_obj_t *in;
26097 + yaffs_obj_t *parent;
26098 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
26099 + int itsUnlinked;
26100 + __u8 *chunkData;
26101 +
26102 + int file_size;
26103 + int is_shrink;
26104 + int foundChunksInBlock;
26105 + int equiv_id;
26106 + int alloc_failed = 0;
26107 +
26108 +
26109 + yaffs_BlockIndex *blockIndex = NULL;
26110 + int altBlockIndex = 0;
26111 +
26112 + T(YAFFS_TRACE_SCAN,
26113 + (TSTR
26114 + ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
26115 + TENDSTR), dev->internal_start_block, dev->internal_end_block));
26116 +
26117 +
26118 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
26119 +
26120 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
26121 +
26122 + if (!blockIndex) {
26123 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
26124 + altBlockIndex = 1;
26125 + }
26126 +
26127 + if (!blockIndex) {
26128 + T(YAFFS_TRACE_SCAN,
26129 + (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR)));
26130 + return YAFFS_FAIL;
26131 + }
26132 +
26133 + dev->blocks_in_checkpt = 0;
26134 +
26135 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
26136 +
26137 + /* Scan all the blocks to determine their state */
26138 + bi = dev->block_info;
26139 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
26140 + yaffs_clear_chunk_bits(dev, blk);
26141 + bi->pages_in_use = 0;
26142 + bi->soft_del_pages = 0;
26143 +
26144 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
26145 +
26146 + bi->block_state = state;
26147 + bi->seq_number = seq_number;
26148 +
26149 + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
26150 + bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
26151 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
26152 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
26153 +
26154 + T(YAFFS_TRACE_SCAN_DEBUG,
26155 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
26156 + state, seq_number));
26157 +
26158 +
26159 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
26160 + dev->blocks_in_checkpt++;
26161 +
26162 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
26163 + T(YAFFS_TRACE_BAD_BLOCKS,
26164 + (TSTR("block %d is bad" TENDSTR), blk));
26165 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
26166 + T(YAFFS_TRACE_SCAN_DEBUG,
26167 + (TSTR("Block empty " TENDSTR)));
26168 + dev->n_erased_blocks++;
26169 + dev->n_free_chunks += dev->param.chunks_per_block;
26170 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
26171 +
26172 + /* Determine the highest sequence number */
26173 + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
26174 + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
26175 +
26176 + blockIndex[nBlocksToScan].seq = seq_number;
26177 + blockIndex[nBlocksToScan].block = blk;
26178 +
26179 + nBlocksToScan++;
26180 +
26181 + if (seq_number >= dev->seq_number)
26182 + dev->seq_number = seq_number;
26183 + } else {
26184 + /* TODO: Nasty sequence number! */
26185 + T(YAFFS_TRACE_SCAN,
26186 + (TSTR
26187 + ("Block scanning block %d has bad sequence number %d"
26188 + TENDSTR), blk, seq_number));
26189 +
26190 + }
26191 + }
26192 + bi++;
26193 + }
26194 +
26195 + T(YAFFS_TRACE_SCAN,
26196 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
26197 +
26198 +
26199 +
26200 + YYIELD();
26201 +
26202 + /* Sort the blocks by sequence number*/
26203 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
26204 +
26205 + YYIELD();
26206 +
26207 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
26208 +
26209 + /* Now scan the blocks looking at the data. */
26210 + startIterator = 0;
26211 + endIterator = nBlocksToScan - 1;
26212 + T(YAFFS_TRACE_SCAN_DEBUG,
26213 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
26214 +
26215 + /* For each block.... backwards */
26216 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
26217 + blockIterator--) {
26218 + /* Cooperative multitasking! This loop can run for so
26219 + long that watchdog timers expire. */
26220 + YYIELD();
26221 +
26222 + /* get the block to scan in the correct order */
26223 + blk = blockIndex[blockIterator].block;
26224 +
26225 + bi = yaffs_get_block_info(dev, blk);
26226 +
26227 +
26228 + state = bi->block_state;
26229 +
26230 + deleted = 0;
26231 +
26232 + /* For each chunk in each block that needs scanning.... */
26233 + foundChunksInBlock = 0;
26234 + for (c = dev->param.chunks_per_block - 1;
26235 + !alloc_failed && c >= 0 &&
26236 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
26237 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
26238 + /* Scan backwards...
26239 + * Read the tags and decide what to do
26240 + */
26241 +
26242 + chunk = blk * dev->param.chunks_per_block + c;
26243 +
26244 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
26245 + &tags);
26246 +
26247 + /* Let's have a good look at this chunk... */
26248 +
26249 + if (!tags.chunk_used) {
26250 + /* An unassigned chunk in the block.
26251 + * If there are used chunks after this one, then
26252 + * it is a chunk that was skipped due to failing the erased
26253 + * check. Just skip it so that it can be deleted.
26254 + * But, more typically, We get here when this is an unallocated
26255 + * chunk and his means that either the block is empty or
26256 + * this is the one being allocated from
26257 + */
26258 +
26259 + if (foundChunksInBlock) {
26260 + /* This is a chunk that was skipped due to failing the erased check */
26261 + } else if (c == 0) {
26262 + /* We're looking at the first chunk in the block so the block is unused */
26263 + state = YAFFS_BLOCK_STATE_EMPTY;
26264 + dev->n_erased_blocks++;
26265 + } else {
26266 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
26267 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
26268 + if (dev->seq_number == bi->seq_number) {
26269 + /* this is the block being allocated from */
26270 +
26271 + T(YAFFS_TRACE_SCAN,
26272 + (TSTR
26273 + (" Allocating from %d %d"
26274 + TENDSTR), blk, c));
26275 +
26276 + state = YAFFS_BLOCK_STATE_ALLOCATING;
26277 + dev->alloc_block = blk;
26278 + dev->alloc_page = c;
26279 + dev->alloc_block_finder = blk;
26280 + } else {
26281 + /* This is a partially written block that is not
26282 + * the current allocation block.
26283 + */
26284 +
26285 + T(YAFFS_TRACE_SCAN,
26286 + (TSTR("Partially written block %d detected" TENDSTR),
26287 + blk));
26288 + }
26289 + }
26290 + }
26291 +
26292 + dev->n_free_chunks++;
26293 +
26294 + } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
26295 + T(YAFFS_TRACE_SCAN,
26296 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
26297 + blk, c));
26298 +
26299 + dev->n_free_chunks++;
26300 +
26301 + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
26302 + tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
26303 + (tags.chunk_id > 0 && tags.n_bytes > dev->data_bytes_per_chunk) ||
26304 + tags.seq_number != bi->seq_number ) {
26305 + T(YAFFS_TRACE_SCAN,
26306 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR),
26307 + blk, c,tags.obj_id, tags.chunk_id, tags.n_bytes));
26308 +
26309 + dev->n_free_chunks++;
26310 +
26311 + } else if (tags.chunk_id > 0) {
26312 + /* chunk_id > 0 so it is a data chunk... */
26313 + unsigned int endpos;
26314 + __u32 chunkBase =
26315 + (tags.chunk_id - 1) * dev->data_bytes_per_chunk;
26316 +
26317 + foundChunksInBlock = 1;
26318 +
26319 +
26320 + yaffs_set_chunk_bit(dev, blk, c);
26321 + bi->pages_in_use++;
26322 +
26323 + in = yaffs_find_or_create_by_number(dev,
26324 + tags.
26325 + obj_id,
26326 + YAFFS_OBJECT_TYPE_FILE);
26327 + if (!in) {
26328 + /* Out of memory */
26329 + alloc_failed = 1;
26330 + }
26331 +
26332 + if (in &&
26333 + in->variant_type == YAFFS_OBJECT_TYPE_FILE
26334 + && chunkBase < in->variant.file_variant.shrink_size) {
26335 + /* This has not been invalidated by a resize */
26336 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, -1)) {
26337 + alloc_failed = 1;
26338 + }
26339 +
26340 + /* File size is calculated by looking at the data chunks if we have not
26341 + * seen an object header yet. Stop this practice once we find an object header.
26342 + */
26343 + endpos = chunkBase + tags.n_bytes;
26344 +
26345 + if (!in->valid && /* have not got an object header yet */
26346 + in->variant.file_variant.scanned_size < endpos) {
26347 + in->variant.file_variant.scanned_size = endpos;
26348 + in->variant.file_variant.file_size = endpos;
26349 + }
26350 +
26351 + } else if (in) {
26352 + /* This chunk has been invalidated by a resize, or a past file deletion
26353 + * so delete the chunk*/
26354 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
26355 +
26356 + }
26357 + } else {
26358 + /* chunk_id == 0, so it is an ObjectHeader.
26359 + * Thus, we read in the object header and make the object
26360 + */
26361 + foundChunksInBlock = 1;
26362 +
26363 + yaffs_set_chunk_bit(dev, blk, c);
26364 + bi->pages_in_use++;
26365 +
26366 + oh = NULL;
26367 + in = NULL;
26368 +
26369 + if (tags.extra_available) {
26370 + in = yaffs_find_or_create_by_number(dev,
26371 + tags.obj_id,
26372 + tags.extra_obj_type);
26373 + if (!in)
26374 + alloc_failed = 1;
26375 + }
26376 +
26377 + if (!in ||
26378 + (!in->valid && dev->param.disable_lazy_load) ||
26379 + tags.extra_shadows ||
26380 + (!in->valid &&
26381 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
26382 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
26383 +
26384 + /* If we don't have valid info then we need to read the chunk
26385 + * TODO In future we can probably defer reading the chunk and
26386 + * living with invalid data until needed.
26387 + */
26388 +
26389 + result = yaffs_rd_chunk_tags_nand(dev,
26390 + chunk,
26391 + chunkData,
26392 + NULL);
26393 +
26394 + oh = (yaffs_obj_header *) chunkData;
26395 +
26396 + if (dev->param.inband_tags) {
26397 + /* Fix up the header if they got corrupted by inband tags */
26398 + oh->shadows_obj = oh->inband_shadowed_obj_id;
26399 + oh->is_shrink = oh->inband_is_shrink;
26400 + }
26401 +
26402 + if (!in) {
26403 + in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
26404 + if (!in)
26405 + alloc_failed = 1;
26406 + }
26407 +
26408 + }
26409 +
26410 + if (!in) {
26411 + /* TODO Hoosterman we have a problem! */
26412 + T(YAFFS_TRACE_ERROR,
26413 + (TSTR
26414 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
26415 + TENDSTR), tags.obj_id, chunk));
26416 + continue;
26417 + }
26418 +
26419 + if (in->valid) {
26420 + /* We have already filled this one.
26421 + * We have a duplicate that will be discarded, but
26422 + * we first have to suck out resize info if it is a file.
26423 + */
26424 +
26425 + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
26426 + ((oh &&
26427 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
26428 + (tags.extra_available &&
26429 + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) {
26430 + __u32 thisSize =
26431 + (oh) ? oh->file_size : tags.
26432 + extra_length;
26433 + __u32 parent_obj_id =
26434 + (oh) ? oh->
26435 + parent_obj_id : tags.
26436 + extra_parent_id;
26437 +
26438 +
26439 + is_shrink =
26440 + (oh) ? oh->is_shrink : tags.
26441 + extra_is_shrink;
26442 +
26443 + /* If it is deleted (unlinked at start also means deleted)
26444 + * we treat the file size as being zeroed at this point.
26445 + */
26446 + if (parent_obj_id ==
26447 + YAFFS_OBJECTID_DELETED
26448 + || parent_obj_id ==
26449 + YAFFS_OBJECTID_UNLINKED) {
26450 + thisSize = 0;
26451 + is_shrink = 1;
26452 + }
26453 +
26454 + if (is_shrink && in->variant.file_variant.shrink_size > thisSize)
26455 + in->variant.file_variant.shrink_size = thisSize;
26456 +
26457 + if (is_shrink)
26458 + bi->has_shrink_hdr = 1;
26459 +
26460 + }
26461 + /* Use existing - destroy this one. */
26462 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
26463 +
26464 + }
26465 +
26466 + if (!in->valid && in->variant_type !=
26467 + (oh ? oh->type : tags.extra_obj_type))
26468 + T(YAFFS_TRACE_ERROR, (
26469 + TSTR("yaffs tragedy: Bad object type, "
26470 + TCONT("%d != %d, for object %d at chunk ")
26471 + TCONT("%d during scan")
26472 + TENDSTR), oh ?
26473 + oh->type : tags.extra_obj_type,
26474 + in->variant_type, tags.obj_id,
26475 + chunk));
26476 +
26477 + if (!in->valid &&
26478 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
26479 + tags.obj_id ==
26480 + YAFFS_OBJECTID_LOSTNFOUND)) {
26481 + /* We only load some info, don't fiddle with directory structure */
26482 + in->valid = 1;
26483 +
26484 + if (oh) {
26485 +
26486 + in->yst_mode = oh->yst_mode;
26487 +#ifdef CONFIG_YAFFS_WINCE
26488 + in->win_atime[0] = oh->win_atime[0];
26489 + in->win_ctime[0] = oh->win_ctime[0];
26490 + in->win_mtime[0] = oh->win_mtime[0];
26491 + in->win_atime[1] = oh->win_atime[1];
26492 + in->win_ctime[1] = oh->win_ctime[1];
26493 + in->win_mtime[1] = oh->win_mtime[1];
26494 +#else
26495 + in->yst_uid = oh->yst_uid;
26496 + in->yst_gid = oh->yst_gid;
26497 + in->yst_atime = oh->yst_atime;
26498 + in->yst_mtime = oh->yst_mtime;
26499 + in->yst_ctime = oh->yst_ctime;
26500 + in->yst_rdev = oh->yst_rdev;
26501 +
26502 + in->lazy_loaded = 0;
26503 +
26504 +#endif
26505 + } else
26506 + in->lazy_loaded = 1;
26507 +
26508 + in->hdr_chunk = chunk;
26509 +
26510 + } else if (!in->valid) {
26511 + /* we need to load this info */
26512 +
26513 + in->valid = 1;
26514 + in->hdr_chunk = chunk;
26515 +
26516 + if (oh) {
26517 + in->variant_type = oh->type;
26518 +
26519 + in->yst_mode = oh->yst_mode;
26520 +#ifdef CONFIG_YAFFS_WINCE
26521 + in->win_atime[0] = oh->win_atime[0];
26522 + in->win_ctime[0] = oh->win_ctime[0];
26523 + in->win_mtime[0] = oh->win_mtime[0];
26524 + in->win_atime[1] = oh->win_atime[1];
26525 + in->win_ctime[1] = oh->win_ctime[1];
26526 + in->win_mtime[1] = oh->win_mtime[1];
26527 +#else
26528 + in->yst_uid = oh->yst_uid;
26529 + in->yst_gid = oh->yst_gid;
26530 + in->yst_atime = oh->yst_atime;
26531 + in->yst_mtime = oh->yst_mtime;
26532 + in->yst_ctime = oh->yst_ctime;
26533 + in->yst_rdev = oh->yst_rdev;
26534 +#endif
26535 +
26536 + if (oh->shadows_obj > 0)
26537 + yaffs_handle_shadowed_obj(dev,
26538 + oh->
26539 + shadows_obj,
26540 + 1);
26541 +
26542 +
26543 +
26544 + yaffs_set_obj_name_from_oh(in, oh);
26545 + parent =
26546 + yaffs_find_or_create_by_number
26547 + (dev, oh->parent_obj_id,
26548 + YAFFS_OBJECT_TYPE_DIRECTORY);
26549 +
26550 + file_size = oh->file_size;
26551 + is_shrink = oh->is_shrink;
26552 + equiv_id = oh->equiv_id;
26553 +
26554 + } else {
26555 + in->variant_type = tags.extra_obj_type;
26556 + parent =
26557 + yaffs_find_or_create_by_number
26558 + (dev, tags.extra_parent_id,
26559 + YAFFS_OBJECT_TYPE_DIRECTORY);
26560 + file_size = tags.extra_length;
26561 + is_shrink = tags.extra_is_shrink;
26562 + equiv_id = tags.extra_equiv_id;
26563 + in->lazy_loaded = 1;
26564 +
26565 + }
26566 + in->dirty = 0;
26567 +
26568 + if (!parent)
26569 + alloc_failed = 1;
26570 +
26571 + /* directory stuff...
26572 + * hook up to parent
26573 + */
26574 +
26575 + if (parent && parent->variant_type ==
26576 + YAFFS_OBJECT_TYPE_UNKNOWN) {
26577 + /* Set up as a directory */
26578 + parent->variant_type =
26579 + YAFFS_OBJECT_TYPE_DIRECTORY;
26580 + YINIT_LIST_HEAD(&parent->variant.
26581 + dir_variant.
26582 + children);
26583 + } else if (!parent || parent->variant_type !=
26584 + YAFFS_OBJECT_TYPE_DIRECTORY) {
26585 + /* Hoosterman, another problem....
26586 + * We're trying to use a non-directory as a directory
26587 + */
26588 +
26589 + T(YAFFS_TRACE_ERROR,
26590 + (TSTR
26591 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
26592 + TENDSTR)));
26593 + parent = dev->lost_n_found;
26594 + }
26595 +
26596 + yaffs_add_obj_to_dir(parent, in);
26597 +
26598 + itsUnlinked = (parent == dev->del_dir) ||
26599 + (parent == dev->unlinked_dir);
26600 +
26601 + if (is_shrink) {
26602 + /* Mark the block as having a shrinkHeader */
26603 + bi->has_shrink_hdr = 1;
26604 + }
26605 +
26606 + /* Note re hardlinks.
26607 + * Since we might scan a hardlink before its equivalent object is scanned
26608 + * we put them all in a list.
26609 + * After scanning is complete, we should have all the objects, so we run
26610 + * through this list and fix up all the chains.
26611 + */
26612 +
26613 + switch (in->variant_type) {
26614 + case YAFFS_OBJECT_TYPE_UNKNOWN:
26615 + /* Todo got a problem */
26616 + break;
26617 + case YAFFS_OBJECT_TYPE_FILE:
26618 +
26619 + if (in->variant.file_variant.
26620 + scanned_size < file_size) {
26621 + /* This covers the case where the file size is greater
26622 + * than where the data is
26623 + * This will happen if the file is resized to be larger
26624 + * than its current data extents.
26625 + */
26626 + in->variant.file_variant.file_size = file_size;
26627 + in->variant.file_variant.scanned_size = file_size;
26628 + }
26629 +
26630 + if (in->variant.file_variant.shrink_size > file_size)
26631 + in->variant.file_variant.shrink_size = file_size;
26632 +
26633 +
26634 + break;
26635 + case YAFFS_OBJECT_TYPE_HARDLINK:
26636 + if (!itsUnlinked) {
26637 + in->variant.hardlink_variant.equiv_id =
26638 + equiv_id;
26639 + in->hard_links.next =
26640 + (struct ylist_head *) hard_list;
26641 + hard_list = in;
26642 + }
26643 + break;
26644 + case YAFFS_OBJECT_TYPE_DIRECTORY:
26645 + /* Do nothing */
26646 + break;
26647 + case YAFFS_OBJECT_TYPE_SPECIAL:
26648 + /* Do nothing */
26649 + break;
26650 + case YAFFS_OBJECT_TYPE_SYMLINK:
26651 + if (oh) {
26652 + in->variant.symlink_variant.alias =
26653 + yaffs_clone_str(oh->alias);
26654 + if (!in->variant.symlink_variant.alias)
26655 + alloc_failed = 1;
26656 + }
26657 + break;
26658 + }
26659 +
26660 + }
26661 +
26662 + }
26663 +
26664 + } /* End of scanning for each chunk */
26665 +
26666 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
26667 + /* If we got this far while scanning, then the block is fully allocated. */
26668 + state = YAFFS_BLOCK_STATE_FULL;
26669 + }
26670 +
26671 +
26672 + bi->block_state = state;
26673 +
26674 + /* Now let's see if it was dirty */
26675 + if (bi->pages_in_use == 0 &&
26676 + !bi->has_shrink_hdr &&
26677 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
26678 + yaffs_block_became_dirty(dev, blk);
26679 + }
26680 +
26681 + }
26682 +
26683 + yaffs_skip_rest_of_block(dev);
26684 +
26685 + if (altBlockIndex)
26686 + YFREE_ALT(blockIndex);
26687 + else
26688 + YFREE(blockIndex);
26689 +
26690 + /* Ok, we've done all the scanning.
26691 + * Fix up the hard link chains.
26692 + * We should now have scanned all the objects, now it's time to add these
26693 + * hardlinks.
26694 + */
26695 + yaffs_link_fixup(dev, hard_list);
26696 +
26697 +
26698 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
26699 +
26700 + if (alloc_failed)
26701 + return YAFFS_FAIL;
26702 +
26703 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
26704 +
26705 + return YAFFS_OK;
26706 +}
26707 --- /dev/null
26708 +++ b/fs/yaffs2/yaffs_yaffs2.h
26709 @@ -0,0 +1,36 @@
26710 +/*
26711 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
26712 + *
26713 + * Copyright (C) 2002-2010 Aleph One Ltd.
26714 + * for Toby Churchill Ltd and Brightstar Engineering
26715 + *
26716 + * Created by Charles Manning <charles@aleph1.co.uk>
26717 + *
26718 + * This program is free software; you can redistribute it and/or modify
26719 + * it under the terms of the GNU General Public License version 2 as
26720 + * published by the Free Software Foundation.
26721 + */
26722 +
26723 +#ifndef __YAFFS_YAFFS2_H__
26724 +#define __YAFFS_YAFFS2_H__
26725 +
26726 +#include "yaffs_guts.h"
26727 +
26728 +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev);
26729 +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev);
26730 +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi);
26731 +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi);
26732 +int yaffs_block_ok_for_gc(yaffs_dev_t *dev, yaffs_block_info_t *bi);
26733 +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev);
26734 +int yaffs2_checkpt_required(yaffs_dev_t *dev);
26735 +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev);
26736 +
26737 +
26738 +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev);
26739 +int yaffs2_checkpt_save(yaffs_dev_t *dev);
26740 +int yaffs2_checkpt_restore(yaffs_dev_t *dev);
26741 +
26742 +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size);
26743 +int yaffs2_scan_backwards(yaffs_dev_t *dev);
26744 +
26745 +#endif
26746 --- a/fs/yaffs2/yportenv.h
26747 +++ b/fs/yaffs2/yportenv.h
26748 @@ -1,7 +1,7 @@
26749 /*
26750 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
26751 *
26752 - * Copyright (C) 2002-2007 Aleph One Ltd.
26753 + * Copyright (C) 2002-2010 Aleph One Ltd.
26754 * for Toby Churchill Ltd and Brightstar Engineering
26755 *
26756 * Created by Charles Manning <charles@aleph1.co.uk>
26757 @@ -41,12 +41,14 @@
26758 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
26759 #include <linux/config.h>
26760 #endif
26761 +
26762 #include <linux/kernel.h>
26763 #include <linux/mm.h>
26764 #include <linux/sched.h>
26765 #include <linux/string.h>
26766 #include <linux/slab.h>
26767 #include <linux/vmalloc.h>
26768 +#include <linux/xattr.h>
26769
26770 #define YCHAR char
26771 #define YUCHAR unsigned char
26772 @@ -55,11 +57,11 @@
26773 #define yaffs_strcpy(a, b) strcpy(a, b)
26774 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
26775 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
26776 -#define yaffs_strlen(s) strlen(s)
26777 +#define yaffs_strnlen(s,m) strnlen(s,m)
26778 #define yaffs_sprintf sprintf
26779 #define yaffs_toupper(a) toupper(a)
26780
26781 -#define Y_INLINE inline
26782 +#define Y_INLINE __inline__
26783
26784 #define YAFFS_LOSTNFOUND_NAME "lost+found"
26785 #define YAFFS_LOSTNFOUND_PREFIX "obj"
26786 @@ -71,11 +73,11 @@
26787 #define YFREE_ALT(x) vfree(x)
26788 #define YMALLOC_DMA(x) YMALLOC(x)
26789
26790 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
26791 #define YYIELD() schedule()
26792 +#define Y_DUMP_STACK() dump_stack()
26793
26794 -#define YAFFS_ROOT_MODE 0666
26795 -#define YAFFS_LOSTNFOUND_MODE 0666
26796 +#define YAFFS_ROOT_MODE 0755
26797 +#define YAFFS_LOSTNFOUND_MODE 0700
26798
26799 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
26800 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
26801 @@ -85,19 +87,14 @@
26802 #define Y_TIME_CONVERT(x) (x)
26803 #endif
26804
26805 -#define yaffs_SumCompare(x, y) ((x) == (y))
26806 +#define yaffs_sum_cmp(x, y) ((x) == (y))
26807 #define yaffs_strcmp(a, b) strcmp(a, b)
26808
26809 #define TENDSTR "\n"
26810 -#define TSTR(x) KERN_WARNING x
26811 +#define TSTR(x) KERN_DEBUG x
26812 #define TCONT(x) x
26813 #define TOUT(p) printk p
26814
26815 -#define yaffs_trace(mask, fmt, args...) \
26816 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
26817 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
26818 - } while (0)
26819 -
26820 #define compile_time_assertion(assertion) \
26821 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
26822
26823 @@ -116,7 +113,6 @@
26824 #include "stdio.h"
26825 #include "string.h"
26826
26827 -#include "devextras.h"
26828
26829 #define YMALLOC(x) malloc(x)
26830 #define YFREE(x) free(x)
26831 @@ -129,7 +125,7 @@
26832 #define yaffs_strcat(a, b) strcat(a, b)
26833 #define yaffs_strcpy(a, b) strcpy(a, b)
26834 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
26835 -#define yaffs_strlen(s) strlen(s)
26836 +#define yaffs_strnlen(s,m) strnlen(s,m)
26837 #define yaffs_sprintf sprintf
26838 #define yaffs_toupper(a) toupper(a)
26839
26840 @@ -146,10 +142,10 @@
26841 #define YAFFS_LOSTNFOUND_PREFIX "obj"
26842 /* #define YPRINTF(x) printf x */
26843
26844 -#define YAFFS_ROOT_MODE 0666
26845 -#define YAFFS_LOSTNFOUND_MODE 0666
26846 +#define YAFFS_ROOT_MODE 0755
26847 +#define YAFFS_LOSTNFOUND_MODE 0700
26848
26849 -#define yaffs_SumCompare(x, y) ((x) == (y))
26850 +#define yaffs_sum_cmp(x, y) ((x) == (y))
26851 #define yaffs_strcmp(a, b) strcmp(a, b)
26852
26853 #else
26854 @@ -158,46 +154,180 @@
26855
26856 #endif
26857
26858 -/* see yaffs_fs.c */
26859 -extern unsigned int yaffs_traceMask;
26860 -extern unsigned int yaffs_wr_attempts;
26861 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
26862
26863 -/*
26864 - * Tracing flags.
26865 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
26866 - */
26867 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
26868 +
26869 +#ifndef O_RDONLY
26870 +#define O_RDONLY 00
26871 +#endif
26872 +
26873 +#ifndef O_WRONLY
26874 +#define O_WRONLY 01
26875 +#endif
26876 +
26877 +#ifndef O_RDWR
26878 +#define O_RDWR 02
26879 +#endif
26880 +
26881 +#ifndef O_CREAT
26882 +#define O_CREAT 0100
26883 +#endif
26884 +
26885 +#ifndef O_EXCL
26886 +#define O_EXCL 0200
26887 +#endif
26888 +
26889 +#ifndef O_TRUNC
26890 +#define O_TRUNC 01000
26891 +#endif
26892 +
26893 +#ifndef O_APPEND
26894 +#define O_APPEND 02000
26895 +#endif
26896 +
26897 +#ifndef SEEK_SET
26898 +#define SEEK_SET 0
26899 +#endif
26900 +
26901 +#ifndef SEEK_CUR
26902 +#define SEEK_CUR 1
26903 +#endif
26904 +
26905 +#ifndef SEEK_END
26906 +#define SEEK_END 2
26907 +#endif
26908 +
26909 +#ifndef EBUSY
26910 +#define EBUSY 16
26911 +#endif
26912 +
26913 +#ifndef ENODEV
26914 +#define ENODEV 19
26915 +#endif
26916 +
26917 +#ifndef EINVAL
26918 +#define EINVAL 22
26919 +#endif
26920 +
26921 +#ifndef EBADF
26922 +#define EBADF 9
26923 +#endif
26924 +
26925 +#ifndef EACCES
26926 +#define EACCES 13
26927 +#endif
26928 +
26929 +#ifndef EXDEV
26930 +#define EXDEV 18
26931 +#endif
26932 +
26933 +#ifndef ENOENT
26934 +#define ENOENT 2
26935 +#endif
26936 +
26937 +#ifndef ENOSPC
26938 +#define ENOSPC 28
26939 +#endif
26940 +
26941 +#ifndef ERANGE
26942 +#define ERANGE 34
26943 +#endif
26944 +
26945 +#ifndef ENODATA
26946 +#define ENODATA 61
26947 +#endif
26948 +
26949 +#ifndef ENOTEMPTY
26950 +#define ENOTEMPTY 39
26951 +#endif
26952 +
26953 +#ifndef ENAMETOOLONG
26954 +#define ENAMETOOLONG 36
26955 +#endif
26956 +
26957 +#ifndef ENOMEM
26958 +#define ENOMEM 12
26959 +#endif
26960 +
26961 +#ifndef EEXIST
26962 +#define EEXIST 17
26963 +#endif
26964 +
26965 +#ifndef ENOTDIR
26966 +#define ENOTDIR 20
26967 +#endif
26968 +
26969 +#ifndef EISDIR
26970 +#define EISDIR 21
26971 +#endif
26972 +
26973 +
26974 +// Mode flags
26975 +
26976 +#ifndef S_IFMT
26977 +#define S_IFMT 0170000
26978 +#endif
26979 +
26980 +#ifndef S_IFLNK
26981 +#define S_IFLNK 0120000
26982 +#endif
26983
26984 -#define YAFFS_TRACE_OS 0x00000002
26985 -#define YAFFS_TRACE_ALLOCATE 0x00000004
26986 -#define YAFFS_TRACE_SCAN 0x00000008
26987 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
26988 -#define YAFFS_TRACE_ERASE 0x00000020
26989 -#define YAFFS_TRACE_GC 0x00000040
26990 -#define YAFFS_TRACE_WRITE 0x00000080
26991 -#define YAFFS_TRACE_TRACING 0x00000100
26992 -#define YAFFS_TRACE_DELETION 0x00000200
26993 -#define YAFFS_TRACE_BUFFERS 0x00000400
26994 -#define YAFFS_TRACE_NANDACCESS 0x00000800
26995 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
26996 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
26997 -#define YAFFS_TRACE_MTD 0x00004000
26998 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
26999 -
27000 -#define YAFFS_TRACE_VERIFY 0x00010000
27001 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
27002 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
27003 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
27004 -
27005 -
27006 -#define YAFFS_TRACE_ERROR 0x40000000
27007 -#define YAFFS_TRACE_BUG 0x80000000
27008 -#define YAFFS_TRACE_ALWAYS 0xF0000000
27009 +#ifndef S_IFDIR
27010 +#define S_IFDIR 0040000
27011 +#endif
27012 +
27013 +#ifndef S_IFREG
27014 +#define S_IFREG 0100000
27015 +#endif
27016
27017 +#ifndef S_IREAD
27018 +#define S_IREAD 0000400
27019 +#endif
27020 +
27021 +#ifndef S_IWRITE
27022 +#define S_IWRITE 0000200
27023 +#endif
27024
27025 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
27026 +#ifndef S_IEXEC
27027 +#define S_IEXEC 0000100
27028 +#endif
27029 +
27030 +#ifndef XATTR_CREATE
27031 +#define XATTR_CREATE 1
27032 +#endif
27033 +
27034 +#ifndef XATTR_REPLACE
27035 +#define XATTR_REPLACE 2
27036 +#endif
27037 +
27038 +#ifndef R_OK
27039 +#define R_OK 4
27040 +#define W_OK 2
27041 +#define X_OK 1
27042 +#define F_OK 0
27043 +#endif
27044 +
27045 +#else
27046 +#include <errno.h>
27047 +#include <sys/stat.h>
27048 +#include <fcntl.h>
27049 +#endif
27050 +
27051 +#endif
27052 +
27053 +#ifndef Y_DUMP_STACK
27054 +#define Y_DUMP_STACK() do { } while (0)
27055 +#endif
27056
27057 #ifndef YBUG
27058 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
27059 +#define YBUG() do {\
27060 + T(YAFFS_TRACE_BUG,\
27061 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
27062 + __LINE__));\
27063 + Y_DUMP_STACK();\
27064 +} while (0)
27065 #endif
27066
27067 +
27068 #endif