linux/generic: sync to todays yaffs tree
[openwrt/staging/yousong.git] / target / linux / generic / patches-2.6.36 / 511-yaffs-git-2010-10-20.patch
1 diff -Nrup linux-2.6.36-rc8/fs/Kconfig linux-2.6.36-rc8.new/fs/Kconfig
2 --- linux-2.6.36-rc8/fs/Kconfig 2010-10-20 13:11:25.295000294 +0300
3 +++ linux-2.6.36-rc8.new/fs/Kconfig 2010-10-20 13:28:15.952000294 +0300
4 @@ -44,7 +44,6 @@ source "fs/gfs2/Kconfig"
5 source "fs/ocfs2/Kconfig"
6 source "fs/btrfs/Kconfig"
7 source "fs/nilfs2/Kconfig"
8 -source "fs/yaffs2/Kconfig"
9
10 endif # BLOCK
11
12 @@ -175,6 +174,10 @@ source "fs/hfsplus/Kconfig"
13 source "fs/befs/Kconfig"
14 source "fs/bfs/Kconfig"
15 source "fs/efs/Kconfig"
16 +
17 +# Patched by YAFFS
18 +source "fs/yaffs2/Kconfig"
19 +
20 source "fs/jffs2/Kconfig"
21 # UBIFS File system configuration
22 source "fs/ubifs/Kconfig"
23 diff -Nrup linux-2.6.36-rc8/fs/Makefile linux-2.6.36-rc8.new/fs/Makefile
24 --- linux-2.6.36-rc8/fs/Makefile 2010-10-20 13:11:25.295000294 +0300
25 +++ linux-2.6.36-rc8.new/fs/Makefile 2010-10-20 13:28:15.953000294 +0300
26 @@ -127,5 +127,6 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/
27 obj-$(CONFIG_GFS2_FS) += gfs2/
28 obj-$(CONFIG_EXOFS_FS) += exofs/
29 obj-$(CONFIG_CEPH_FS) += ceph/
30 -obj-$(CONFIG_YAFFS_FS) += yaffs2/
31
32 +# Patched by YAFFS
33 +obj-$(CONFIG_YAFFS_FS) += yaffs2/
34 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/devextras.h linux-2.6.36-rc8.new/fs/yaffs2/devextras.h
35 --- linux-2.6.36-rc8/fs/yaffs2/devextras.h 2010-10-20 13:17:58.937000294 +0300
36 +++ linux-2.6.36-rc8.new/fs/yaffs2/devextras.h 2010-10-20 13:28:16.050000294 +0300
37 @@ -1,7 +1,7 @@
38 /*
39 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
40 *
41 - * Copyright (C) 2002-2007 Aleph One Ltd.
42 + * Copyright (C) 2002-2010 Aleph One Ltd.
43 * for Toby Churchill Ltd and Brightstar Engineering
44 *
45 * Created by Charles Manning <charles@aleph1.co.uk>
46 @@ -24,6 +24,8 @@
47 #define __EXTRAS_H__
48
49
50 +#include "yportenv.h"
51 +
52 #if !(defined __KERNEL__)
53
54 /* Definition of types */
55 @@ -33,103 +35,6 @@ typedef unsigned __u32;
56
57 #endif
58
59 -/*
60 - * This is a simple doubly linked list implementation that matches the
61 - * way the Linux kernel doubly linked list implementation works.
62 - */
63 -
64 -struct ylist_head {
65 - struct ylist_head *next; /* next in chain */
66 - struct ylist_head *prev; /* previous in chain */
67 -};
68 -
69 -
70 -/* Initialise a static list */
71 -#define YLIST_HEAD(name) \
72 -struct ylist_head name = { &(name), &(name)}
73 -
74 -
75 -
76 -/* Initialise a list head to an empty list */
77 -#define YINIT_LIST_HEAD(p) \
78 -do { \
79 - (p)->next = (p);\
80 - (p)->prev = (p); \
81 -} while (0)
82 -
83 -
84 -/* Add an element to a list */
85 -static __inline__ void ylist_add(struct ylist_head *newEntry,
86 - struct ylist_head *list)
87 -{
88 - struct ylist_head *listNext = list->next;
89 -
90 - list->next = newEntry;
91 - newEntry->prev = list;
92 - newEntry->next = listNext;
93 - listNext->prev = newEntry;
94 -
95 -}
96 -
97 -static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
98 - struct ylist_head *list)
99 -{
100 - struct ylist_head *listPrev = list->prev;
101 -
102 - list->prev = newEntry;
103 - newEntry->next = list;
104 - newEntry->prev = listPrev;
105 - listPrev->next = newEntry;
106 -
107 -}
108 -
109 -
110 -/* Take an element out of its current list, with or without
111 - * reinitialising the links.of the entry*/
112 -static __inline__ void ylist_del(struct ylist_head *entry)
113 -{
114 - struct ylist_head *listNext = entry->next;
115 - struct ylist_head *listPrev = entry->prev;
116 -
117 - listNext->prev = listPrev;
118 - listPrev->next = listNext;
119 -
120 -}
121 -
122 -static __inline__ void ylist_del_init(struct ylist_head *entry)
123 -{
124 - ylist_del(entry);
125 - entry->next = entry->prev = entry;
126 -}
127 -
128 -
129 -/* Test if the list is empty */
130 -static __inline__ int ylist_empty(struct ylist_head *entry)
131 -{
132 - return (entry->next == entry);
133 -}
134 -
135 -
136 -/* ylist_entry takes a pointer to a list entry and offsets it to that
137 - * we can find a pointer to the object it is embedded in.
138 - */
139 -
140 -
141 -#define ylist_entry(entry, type, member) \
142 - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
143 -
144 -
145 -/* ylist_for_each and list_for_each_safe iterate over lists.
146 - * ylist_for_each_safe uses temporary storage to make the list delete safe
147 - */
148 -
149 -#define ylist_for_each(itervar, list) \
150 - for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
151 -
152 -#define ylist_for_each_safe(itervar, saveVar, list) \
153 - for (itervar = (list)->next, saveVar = (list)->next->next; \
154 - itervar != (list); itervar = saveVar, saveVar = saveVar->next)
155 -
156
157 #if !(defined __KERNEL__)
158
159 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/Kconfig linux-2.6.36-rc8.new/fs/yaffs2/Kconfig
160 --- linux-2.6.36-rc8/fs/yaffs2/Kconfig 2010-10-20 13:17:58.937000294 +0300
161 +++ linux-2.6.36-rc8.new/fs/yaffs2/Kconfig 2010-10-20 13:28:15.993000294 +0300
162 @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
163
164 If unsure, say Y.
165
166 -config YAFFS_DISABLE_LAZY_LOAD
167 - bool "Disable lazy loading"
168 - depends on YAFFS_YAFFS2
169 +config YAFFS_DISABLE_TAGS_ECC
170 + bool "Disable YAFFS from doing ECC on tags by default"
171 + depends on YAFFS_FS && YAFFS_YAFFS2
172 default n
173 help
174 - "Lazy loading" defers loading file details until they are
175 - required. This saves mount time, but makes the first look-up
176 - a bit longer.
177 -
178 - Lazy loading will only happen if enabled by this option being 'n'
179 - and if the appropriate tags are available, else yaffs2 will
180 - automatically fall back to immediate loading and do the right
181 - thing.
182 -
183 - Lazy laoding will be required by checkpointing.
184 -
185 - Setting this to 'y' will disable lazy loading.
186 + This defaults Yaffs to using its own ECC calculations on tags instead of
187 + just relying on the MTD.
188 + This behavior can also be overridden with tags_ecc_on and
189 + tags_ecc_off mount options.
190
191 If unsure, say N.
192
193 @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
194 but makes look-ups faster.
195
196 If unsure, say Y.
197 +
198 +config YAFFS_EMPTY_LOST_AND_FOUND
199 + bool "Empty lost and found on boot"
200 + depends on YAFFS_FS
201 + default n
202 + help
203 + If this is enabled then the contents of lost and found is
204 + automatically dumped at mount.
205 +
206 + If unsure, say N.
207 +
208 +config YAFFS_DISABLE_BLOCK_REFRESHING
209 + bool "Disable yaffs2 block refreshing"
210 + depends on YAFFS_FS
211 + default n
212 + help
213 + If this is set, then block refreshing is disabled.
214 + Block refreshing infrequently refreshes the oldest block in
215 + a yaffs2 file system. This mechanism helps to refresh flash to
216 + mitigate against data loss. This is particularly useful for MLC.
217 +
218 + If unsure, say N.
219 +
220 +config YAFFS_DISABLE_BACKGROUND
221 + bool "Disable yaffs2 background processing"
222 + depends on YAFFS_FS
223 + default n
224 + help
225 + If this is set, then background processing is disabled.
226 + Background processing makes many foreground activities faster.
227 +
228 + If unsure, say N.
229 +
230 +config YAFFS_XATTR
231 + bool "Enable yaffs2 xattr support"
232 + depends on YAFFS_FS
233 + default y
234 + help
235 + If this is set then yaffs2 will provide xattr support.
236 + If unsure, say Y.
237 +
238 +
239 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/Makefile linux-2.6.36-rc8.new/fs/yaffs2/Makefile
240 --- linux-2.6.36-rc8/fs/yaffs2/Makefile 2010-10-20 13:17:58.937000294 +0300
241 +++ linux-2.6.36-rc8.new/fs/yaffs2/Makefile 2010-10-20 13:28:15.989000294 +0300
242 @@ -4,7 +4,14 @@
243
244 obj-$(CONFIG_YAFFS_FS) += yaffs.o
245
246 -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
247 -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
248 +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
249 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
250 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
251 yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
252 +yaffs-y += yaffs_nameval.o
253 +yaffs-y += yaffs_allocator.o
254 +yaffs-y += yaffs_yaffs1.o
255 +yaffs-y += yaffs_yaffs2.o
256 +yaffs-y += yaffs_bitmap.o
257 +yaffs-y += yaffs_verify.o
258 +
259 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/moduleconfig.h linux-2.6.36-rc8.new/fs/yaffs2/moduleconfig.h
260 --- linux-2.6.36-rc8/fs/yaffs2/moduleconfig.h 2010-10-20 13:17:58.938000294 +0300
261 +++ linux-2.6.36-rc8.new/fs/yaffs2/moduleconfig.h 2010-10-20 13:28:16.055000294 +0300
262 @@ -1,7 +1,7 @@
263 /*
264 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
265 *
266 - * Copyright (C) 2002-2007 Aleph One Ltd.
267 + * Copyright (C) 2002-2010 Aleph One Ltd.
268 * for Toby Churchill Ltd and Brightstar Engineering
269 *
270 * Created by Martin Fouts <Martin.Fouts@palmsource.com>
271 @@ -29,25 +29,46 @@
272 /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
273 /* #define CONFIG_YAFFS_DOES_ECC */
274
275 +/* Default: Selected */
276 +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
277 +#define CONFIG_YAFFS_DOES_TAGS_ECC
278 +
279 /* Default: Not selected */
280 /* Meaning: ECC byte order is 'wrong'. Only meaningful if */
281 /* CONFIG_YAFFS_DOES_ECC is set */
282 /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
283
284 -/* Default: Selected */
285 -/* Meaning: Disables testing whether chunks are erased before writing to them*/
286 -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
287 +/* Default: Not selected */
288 +/* Meaning: Always test whether chunks are erased before writing to them.
289 + Use during mtd debugging and init. */
290 +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
291 +
292 +/* Default: Not Selected */
293 +/* Meaning: At mount automatically empty all files from lost and found. */
294 +/* This is done to fix an old problem where rmdir was not checking for an */
295 +/* empty directory. This can also be achieved with a mount option. */
296 +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
297
298 /* Default: Selected */
299 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
300 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
301
302 -/* Default: 10 */
303 -/* Meaning: set the count of blocks to reserve for checkpointing */
304 -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
305 +/* Default: Unselected */
306 +/* Meaning: Select to disable block refreshing. */
307 +/* Block Refreshing periodically rewrites the oldest block. */
308 +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
309 +
310 +/* Default: Unselected */
311 +/* Meaning: Select to disable background processing */
312 +/* #define CONFIG_DISABLE_BACKGROUND */
313 +
314 +
315 +/* Default: Selected */
316 +/* Meaning: Enable XATTR support */
317 +#define CONFIG_YAFFS_XATTR
318
319 /*
320 -Older-style on-NAND data format has a "pageStatus" byte to record
321 +Older-style on-NAND data format has a "page_status" byte to record
322 chunk/page state. This byte is zeroed when the page is discarded.
323 Choose this option if you have existing on-NAND data in this format
324 that you need to continue to support. New data written also uses the
325 @@ -57,7 +78,7 @@ adjusted to use the older-style format.
326 MTD versions in yaffs_mtdif1.c.
327 */
328 /* Default: Not selected */
329 -/* Meaning: Use older-style on-NAND data format with pageStatus byte */
330 +/* Meaning: Use older-style on-NAND data format with page_status byte */
331 /* #define CONFIG_YAFFS_9BYTE_TAGS */
332
333 #endif /* YAFFS_OUT_OF_TREE */
334 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.c
335 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.c 1970-01-01 02:00:00.000000000 +0200
336 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.c 2010-10-20 13:28:15.998000294 +0300
337 @@ -0,0 +1,409 @@
338 +/*
339 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
340 + *
341 + * Copyright (C) 2002-2010 Aleph One Ltd.
342 + * for Toby Churchill Ltd and Brightstar Engineering
343 + *
344 + * Created by Charles Manning <charles@aleph1.co.uk>
345 + *
346 + * This program is free software; you can redistribute it and/or modify
347 + * it under the terms of the GNU Lesser General Public License version 2.1 as
348 + * published by the Free Software Foundation.
349 + *
350 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
351 + */
352 +
353 +
354 +#include "yaffs_allocator.h"
355 +#include "yaffs_guts.h"
356 +#include "yaffs_trace.h"
357 +#include "yportenv.h"
358 +
359 +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
360 +
361 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
362 +{
363 + dev = dev;
364 +}
365 +
366 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
367 +{
368 + dev = dev;
369 +}
370 +
371 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
372 +{
373 + return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
374 +}
375 +
376 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
377 +{
378 + dev = dev;
379 + YFREE(tn);
380 +}
381 +
382 +void yaffs_init_raw_objs(yaffs_dev_t *dev)
383 +{
384 + dev = dev;
385 +}
386 +
387 +void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
388 +{
389 + dev = dev;
390 +}
391 +
392 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
393 +{
394 + dev = dev;
395 + return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
396 +}
397 +
398 +
399 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
400 +{
401 +
402 + dev = dev;
403 + YFREE(obj);
404 +}
405 +
406 +#else
407 +
408 +struct yaffs_tnode_list {
409 + struct yaffs_tnode_list *next;
410 + yaffs_tnode_t *tnodes;
411 +};
412 +
413 +typedef struct yaffs_tnode_list yaffs_tnodelist_t;
414 +
415 +struct yaffs_obj_tList_struct {
416 + yaffs_obj_t *objects;
417 + struct yaffs_obj_tList_struct *next;
418 +};
419 +
420 +typedef struct yaffs_obj_tList_struct yaffs_obj_tList;
421 +
422 +
423 +struct yaffs_AllocatorStruct {
424 + int n_tnodesCreated;
425 + yaffs_tnode_t *freeTnodes;
426 + int nFreeTnodes;
427 + yaffs_tnodelist_t *allocatedTnodeList;
428 +
429 + int n_objCreated;
430 + yaffs_obj_t *freeObjects;
431 + int nFreeObjects;
432 +
433 + yaffs_obj_tList *allocatedObjectList;
434 +};
435 +
436 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
437 +
438 +
439 +static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
440 +{
441 +
442 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
443 +
444 + yaffs_tnodelist_t *tmp;
445 +
446 + if(!allocator){
447 + YBUG();
448 + return;
449 + }
450 +
451 + while (allocator->allocatedTnodeList) {
452 + tmp = allocator->allocatedTnodeList->next;
453 +
454 + YFREE(allocator->allocatedTnodeList->tnodes);
455 + YFREE(allocator->allocatedTnodeList);
456 + allocator->allocatedTnodeList = tmp;
457 +
458 + }
459 +
460 + allocator->freeTnodes = NULL;
461 + allocator->nFreeTnodes = 0;
462 + allocator->n_tnodesCreated = 0;
463 +}
464 +
465 +static void yaffs_init_raw_tnodes(yaffs_dev_t *dev)
466 +{
467 + yaffs_Allocator *allocator = dev->allocator;
468 +
469 + if(allocator){
470 + allocator->allocatedTnodeList = NULL;
471 + allocator->freeTnodes = NULL;
472 + allocator->nFreeTnodes = 0;
473 + allocator->n_tnodesCreated = 0;
474 + } else
475 + YBUG();
476 +}
477 +
478 +static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes)
479 +{
480 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
481 + int i;
482 + yaffs_tnode_t *newTnodes;
483 + __u8 *mem;
484 + yaffs_tnode_t *curr;
485 + yaffs_tnode_t *next;
486 + yaffs_tnodelist_t *tnl;
487 +
488 + if(!allocator){
489 + YBUG();
490 + return YAFFS_FAIL;
491 + }
492 +
493 + if (n_tnodes < 1)
494 + return YAFFS_OK;
495 +
496 +
497 + /* make these things */
498 +
499 + newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
500 + mem = (__u8 *)newTnodes;
501 +
502 + if (!newTnodes) {
503 + T(YAFFS_TRACE_ERROR,
504 + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
505 + return YAFFS_FAIL;
506 + }
507 +
508 + /* New hookup for wide tnodes */
509 + for (i = 0; i < n_tnodes - 1; i++) {
510 + curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
511 + next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
512 + curr->internal[0] = next;
513 + }
514 +
515 + curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
516 + curr->internal[0] = allocator->freeTnodes;
517 + allocator->freeTnodes = (yaffs_tnode_t *)mem;
518 +
519 + allocator->nFreeTnodes += n_tnodes;
520 + allocator->n_tnodesCreated += n_tnodes;
521 +
522 + /* Now add this bunch of tnodes to a list for freeing up.
523 + * NB If we can't add this to the management list it isn't fatal
524 + * but it just means we can't free this bunch of tnodes later.
525 + */
526 +
527 + tnl = YMALLOC(sizeof(yaffs_tnodelist_t));
528 + if (!tnl) {
529 + T(YAFFS_TRACE_ERROR,
530 + (TSTR
531 + ("yaffs: Could not add tnodes to management list" TENDSTR)));
532 + return YAFFS_FAIL;
533 + } else {
534 + tnl->tnodes = newTnodes;
535 + tnl->next = allocator->allocatedTnodeList;
536 + allocator->allocatedTnodeList = tnl;
537 + }
538 +
539 + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
540 +
541 + return YAFFS_OK;
542 +}
543 +
544 +
545 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
546 +{
547 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
548 + yaffs_tnode_t *tn = NULL;
549 +
550 + if(!allocator){
551 + YBUG();
552 + return NULL;
553 + }
554 +
555 + /* If there are none left make more */
556 + if (!allocator->freeTnodes)
557 + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
558 +
559 + if (allocator->freeTnodes) {
560 + tn = allocator->freeTnodes;
561 + allocator->freeTnodes = allocator->freeTnodes->internal[0];
562 + allocator->nFreeTnodes--;
563 + }
564 +
565 + return tn;
566 +}
567 +
568 +/* FreeTnode frees up a tnode and puts it back on the free list */
569 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
570 +{
571 + yaffs_Allocator *allocator = dev->allocator;
572 +
573 + if(!allocator){
574 + YBUG();
575 + return;
576 + }
577 +
578 + if (tn) {
579 + tn->internal[0] = allocator->freeTnodes;
580 + allocator->freeTnodes = tn;
581 + allocator->nFreeTnodes++;
582 + }
583 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
584 +}
585 +
586 +
587 +
588 +static void yaffs_init_raw_objs(yaffs_dev_t *dev)
589 +{
590 + yaffs_Allocator *allocator = dev->allocator;
591 +
592 + if(allocator) {
593 + allocator->allocatedObjectList = NULL;
594 + allocator->freeObjects = NULL;
595 + allocator->nFreeObjects = 0;
596 + } else
597 + YBUG();
598 +}
599 +
600 +static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
601 +{
602 + yaffs_Allocator *allocator = dev->allocator;
603 + yaffs_obj_tList *tmp;
604 +
605 + if(!allocator){
606 + YBUG();
607 + return;
608 + }
609 +
610 + while (allocator->allocatedObjectList) {
611 + tmp = allocator->allocatedObjectList->next;
612 + YFREE(allocator->allocatedObjectList->objects);
613 + YFREE(allocator->allocatedObjectList);
614 +
615 + allocator->allocatedObjectList = tmp;
616 + }
617 +
618 + allocator->freeObjects = NULL;
619 + allocator->nFreeObjects = 0;
620 + allocator->n_objCreated = 0;
621 +}
622 +
623 +
624 +static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
625 +{
626 + yaffs_Allocator *allocator = dev->allocator;
627 +
628 + int i;
629 + yaffs_obj_t *newObjects;
630 + yaffs_obj_tList *list;
631 +
632 + if(!allocator){
633 + YBUG();
634 + return YAFFS_FAIL;
635 + }
636 +
637 + if (n_obj < 1)
638 + return YAFFS_OK;
639 +
640 + /* make these things */
641 + newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
642 + list = YMALLOC(sizeof(yaffs_obj_tList));
643 +
644 + if (!newObjects || !list) {
645 + if (newObjects){
646 + YFREE(newObjects);
647 + newObjects = NULL;
648 + }
649 + if (list){
650 + YFREE(list);
651 + list = NULL;
652 + }
653 + T(YAFFS_TRACE_ALLOCATE,
654 + (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
655 + return YAFFS_FAIL;
656 + }
657 +
658 + /* Hook them into the free list */
659 + for (i = 0; i < n_obj - 1; i++) {
660 + newObjects[i].siblings.next =
661 + (struct ylist_head *)(&newObjects[i + 1]);
662 + }
663 +
664 + newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
665 + allocator->freeObjects = newObjects;
666 + allocator->nFreeObjects += n_obj;
667 + allocator->n_objCreated += n_obj;
668 +
669 + /* Now add this bunch of Objects to a list for freeing up. */
670 +
671 + list->objects = newObjects;
672 + list->next = allocator->allocatedObjectList;
673 + allocator->allocatedObjectList = list;
674 +
675 + return YAFFS_OK;
676 +}
677 +
678 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
679 +{
680 + yaffs_obj_t *obj = NULL;
681 + yaffs_Allocator *allocator = dev->allocator;
682 +
683 + if(!allocator) {
684 + YBUG();
685 + return obj;
686 + }
687 +
688 + /* If there are none left make more */
689 + if (!allocator->freeObjects)
690 + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
691 +
692 + if (allocator->freeObjects) {
693 + obj = allocator->freeObjects;
694 + allocator->freeObjects =
695 + (yaffs_obj_t *) (allocator->freeObjects->siblings.next);
696 + allocator->nFreeObjects--;
697 + }
698 +
699 + return obj;
700 +}
701 +
702 +
703 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
704 +{
705 +
706 + yaffs_Allocator *allocator = dev->allocator;
707 +
708 + if(!allocator)
709 + YBUG();
710 + else {
711 + /* Link into the free list. */
712 + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
713 + allocator->freeObjects = obj;
714 + allocator->nFreeObjects++;
715 + }
716 +}
717 +
718 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
719 +{
720 + if(dev->allocator){
721 + yaffs_deinit_raw_tnodes(dev);
722 + yaffs_deinit_raw_objs(dev);
723 +
724 + YFREE(dev->allocator);
725 + dev->allocator=NULL;
726 + } else
727 + YBUG();
728 +}
729 +
730 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
731 +{
732 + yaffs_Allocator *allocator;
733 +
734 + if(!dev->allocator){
735 + allocator = YMALLOC(sizeof(yaffs_Allocator));
736 + if(allocator){
737 + dev->allocator = allocator;
738 + yaffs_init_raw_tnodes(dev);
739 + yaffs_init_raw_objs(dev);
740 + }
741 + } else
742 + YBUG();
743 +}
744 +
745 +
746 +#endif
747 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.h
748 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_allocator.h 1970-01-01 02:00:00.000000000 +0200
749 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_allocator.h 2010-10-20 13:28:16.058000294 +0300
750 @@ -0,0 +1,30 @@
751 +/*
752 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
753 + *
754 + * Copyright (C) 2002-2010 Aleph One Ltd.
755 + * for Toby Churchill Ltd and Brightstar Engineering
756 + *
757 + * Created by Charles Manning <charles@aleph1.co.uk>
758 + *
759 + * This program is free software; you can redistribute it and/or modify
760 + * it under the terms of the GNU Lesser General Public License version 2.1 as
761 + * published by the Free Software Foundation.
762 + *
763 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
764 + */
765 +
766 +#ifndef __YAFFS_ALLOCATOR_H__
767 +#define __YAFFS_ALLOCATOR_H__
768 +
769 +#include "yaffs_guts.h"
770 +
771 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev);
772 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev);
773 +
774 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev);
775 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn);
776 +
777 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev);
778 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj);
779 +
780 +#endif
781 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.c
782 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.c 1970-01-01 02:00:00.000000000 +0200
783 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.c 2010-10-20 13:28:15.998000294 +0300
784 @@ -0,0 +1,105 @@
785 +/*
786 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
787 + *
788 + * Copyright (C) 2002-2010 Aleph One Ltd.
789 + * for Toby Churchill Ltd and Brightstar Engineering
790 + *
791 + * Created by Charles Manning <charles@aleph1.co.uk>
792 + *
793 + * This program is free software; you can redistribute it and/or modify
794 + * it under the terms of the GNU General Public License version 2 as
795 + * published by the Free Software Foundation.
796 + */
797 +
798 +#include "yaffs_bitmap.h"
799 +#include "yaffs_trace.h"
800 +/*
801 + * Chunk bitmap manipulations
802 + */
803 +
804 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_dev_t *dev, int blk)
805 +{
806 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
807 + T(YAFFS_TRACE_ERROR,
808 + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
809 + blk));
810 + YBUG();
811 + }
812 + return dev->chunk_bits +
813 + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
814 +}
815 +
816 +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk)
817 +{
818 + if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
819 + chunk < 0 || chunk >= dev->param.chunks_per_block) {
820 + T(YAFFS_TRACE_ERROR,
821 + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
822 + blk, chunk));
823 + YBUG();
824 + }
825 +}
826 +
827 +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk)
828 +{
829 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
830 +
831 + memset(blkBits, 0, dev->chunk_bit_stride);
832 +}
833 +
834 +void yaffs_clear_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 +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
844 +{
845 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
846 +
847 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
848 +
849 + blkBits[chunk / 8] |= (1 << (chunk & 7));
850 +}
851 +
852 +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
853 +{
854 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
855 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
856 +
857 + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
858 +}
859 +
860 +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk)
861 +{
862 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
863 + int i;
864 + for (i = 0; i < dev->chunk_bit_stride; i++) {
865 + if (*blkBits)
866 + return 1;
867 + blkBits++;
868 + }
869 + return 0;
870 +}
871 +
872 +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk)
873 +{
874 + __u8 *blkBits = yaffs_BlockBits(dev, blk);
875 + int i;
876 + int n = 0;
877 + for (i = 0; i < dev->chunk_bit_stride; i++) {
878 + __u8 x = *blkBits;
879 + while (x) {
880 + if (x & 1)
881 + n++;
882 + x >>= 1;
883 + }
884 +
885 + blkBits++;
886 + }
887 + return n;
888 +}
889 +
890 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.h
891 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_bitmap.h 1970-01-01 02:00:00.000000000 +0200
892 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_bitmap.h 2010-10-20 13:28:16.058000294 +0300
893 @@ -0,0 +1,31 @@
894 +/*
895 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
896 + *
897 + * Copyright (C) 2002-2010 Aleph One Ltd.
898 + * for Toby Churchill Ltd and Brightstar Engineering
899 + *
900 + * Created by Charles Manning <charles@aleph1.co.uk>
901 + *
902 + * This program is free software; you can redistribute it and/or modify
903 + * it under the terms of the GNU General Public License version 2 as
904 + * published by the Free Software Foundation.
905 + */
906 +
907 +/*
908 + * Chunk bitmap manipulations
909 + */
910 +
911 +#ifndef __YAFFS_BITMAP_H__
912 +#define __YAFFS_BITMAP_H__
913 +
914 +#include "yaffs_guts.h"
915 +
916 +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk);
917 +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk);
918 +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
919 +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
920 +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
921 +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk);
922 +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk);
923 +
924 +#endif
925 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.c
926 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.c 2010-10-20 13:17:58.941000294 +0300
927 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.c 2010-10-20 13:28:15.999000294 +0300
928 @@ -1,7 +1,7 @@
929 /*
930 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
931 *
932 - * Copyright (C) 2002-2007 Aleph One Ltd.
933 + * Copyright (C) 2002-2010 Aleph One Ltd.
934 * for Toby Churchill Ltd and Brightstar Engineering
935 *
936 * Created by Charles Manning <charles@aleph1.co.uk>
937 @@ -11,16 +11,12 @@
938 * published by the Free Software Foundation.
939 */
940
941 -const char *yaffs_checkptrw_c_version =
942 - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
943 -
944 -
945 #include "yaffs_checkptrw.h"
946 #include "yaffs_getblockinfo.h"
947
948 -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
949 +static int yaffs2_checkpt_space_ok(yaffs_dev_t *dev)
950 {
951 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
952 + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
953
954 T(YAFFS_TRACE_CHECKPOINT,
955 (TSTR("checkpt blocks available = %d" TENDSTR),
956 @@ -30,53 +26,56 @@ static int yaffs_CheckpointSpaceOk(yaffs
957 }
958
959
960 -static int yaffs_CheckpointErase(yaffs_Device *dev)
961 +static int yaffs_checkpt_erase(yaffs_dev_t *dev)
962 {
963 int i;
964
965 - if (!dev->eraseBlockInNAND)
966 + if (!dev->param.erase_fn)
967 return 0;
968 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
969 - dev->internalStartBlock, dev->internalEndBlock));
970 + dev->internal_start_block, dev->internal_end_block));
971
972 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
973 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
974 - if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
975 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
976 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
977 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
978 T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
979 - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
980 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
981 - dev->nErasedBlocks++;
982 - dev->nFreeChunks += dev->nChunksPerBlock;
983 +
984 + dev->n_erasures++;
985 +
986 + if (dev->param.erase_fn(dev, i - dev->block_offset /* realign */)) {
987 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
988 + dev->n_erased_blocks++;
989 + dev->n_free_chunks += dev->param.chunks_per_block;
990 } else {
991 - dev->markNANDBlockBad(dev, i);
992 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
993 + dev->param.bad_block_fn(dev, i);
994 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
995 }
996 }
997 }
998
999 - dev->blocksInCheckpoint = 0;
1000 + dev->blocks_in_checkpt = 0;
1001
1002 return 1;
1003 }
1004
1005
1006 -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
1007 +static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
1008 {
1009 int i;
1010 - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
1011 + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
1012 T(YAFFS_TRACE_CHECKPOINT,
1013 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
1014 - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
1015 + dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block));
1016
1017 - if (dev->checkpointNextBlock >= 0 &&
1018 - dev->checkpointNextBlock <= dev->internalEndBlock &&
1019 + if (dev->checkpt_next_block >= 0 &&
1020 + dev->checkpt_next_block <= dev->internal_end_block &&
1021 blocksAvailable > 0) {
1022
1023 - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
1024 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
1025 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
1026 - dev->checkpointNextBlock = i + 1;
1027 - dev->checkpointCurrentBlock = i;
1028 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
1029 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
1030 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
1031 + dev->checkpt_next_block = i + 1;
1032 + dev->checkpt_cur_block = i;
1033 T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
1034 return;
1035 }
1036 @@ -84,34 +83,34 @@ static void yaffs_CheckpointFindNextEras
1037 }
1038 T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
1039
1040 - dev->checkpointNextBlock = -1;
1041 - dev->checkpointCurrentBlock = -1;
1042 + dev->checkpt_next_block = -1;
1043 + dev->checkpt_cur_block = -1;
1044 }
1045
1046 -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
1047 +static void yaffs2_checkpt_find_block(yaffs_dev_t *dev)
1048 {
1049 int i;
1050 - yaffs_ExtendedTags tags;
1051 + yaffs_ext_tags tags;
1052
1053 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
1054 - dev->blocksInCheckpoint, dev->checkpointNextBlock));
1055 + dev->blocks_in_checkpt, dev->checkpt_next_block));
1056
1057 - if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
1058 - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
1059 - int chunk = i * dev->nChunksPerBlock;
1060 - int realignedChunk = chunk - dev->chunkOffset;
1061 + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
1062 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
1063 + int chunk = i * dev->param.chunks_per_block;
1064 + int realignedChunk = chunk - dev->chunk_offset;
1065
1066 - dev->readChunkWithTagsFromNAND(dev, realignedChunk,
1067 + dev->param.read_chunk_tags_fn(dev, realignedChunk,
1068 NULL, &tags);
1069 T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
1070 - i, tags.objectId, tags.sequenceNumber, tags.eccResult));
1071 + i, tags.obj_id, tags.seq_number, tags.ecc_result));
1072
1073 - if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1074 + if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1075 /* Right kind of block */
1076 - dev->checkpointNextBlock = tags.objectId;
1077 - dev->checkpointCurrentBlock = i;
1078 - dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
1079 - dev->blocksInCheckpoint++;
1080 + dev->checkpt_next_block = tags.obj_id;
1081 + dev->checkpt_cur_block = i;
1082 + dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
1083 + dev->blocks_in_checkpt++;
1084 T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
1085 return;
1086 }
1087 @@ -119,122 +118,127 @@ static void yaffs_CheckpointFindNextChec
1088
1089 T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
1090
1091 - dev->checkpointNextBlock = -1;
1092 - dev->checkpointCurrentBlock = -1;
1093 + dev->checkpt_next_block = -1;
1094 + dev->checkpt_cur_block = -1;
1095 }
1096
1097
1098 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
1099 +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
1100 {
1101
1102 +
1103 + dev->checkpt_open_write = forWriting;
1104 +
1105 /* Got the functions we need? */
1106 - if (!dev->writeChunkWithTagsToNAND ||
1107 - !dev->readChunkWithTagsFromNAND ||
1108 - !dev->eraseBlockInNAND ||
1109 - !dev->markNANDBlockBad)
1110 + if (!dev->param.write_chunk_tags_fn ||
1111 + !dev->param.read_chunk_tags_fn ||
1112 + !dev->param.erase_fn ||
1113 + !dev->param.bad_block_fn)
1114 return 0;
1115
1116 - if (forWriting && !yaffs_CheckpointSpaceOk(dev))
1117 + if (forWriting && !yaffs2_checkpt_space_ok(dev))
1118 return 0;
1119
1120 - if (!dev->checkpointBuffer)
1121 - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
1122 - if (!dev->checkpointBuffer)
1123 + if (!dev->checkpt_buffer)
1124 + dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
1125 + if (!dev->checkpt_buffer)
1126 return 0;
1127
1128
1129 - dev->checkpointPageSequence = 0;
1130 -
1131 - dev->checkpointOpenForWrite = forWriting;
1132 -
1133 - dev->checkpointByteCount = 0;
1134 - dev->checkpointSum = 0;
1135 - dev->checkpointXor = 0;
1136 - dev->checkpointCurrentBlock = -1;
1137 - dev->checkpointCurrentChunk = -1;
1138 - dev->checkpointNextBlock = dev->internalStartBlock;
1139 + dev->checkpt_page_seq = 0;
1140 + dev->checkpt_byte_count = 0;
1141 + dev->checkpt_sum = 0;
1142 + dev->checkpt_xor = 0;
1143 + dev->checkpt_cur_block = -1;
1144 + dev->checkpt_cur_chunk = -1;
1145 + dev->checkpt_next_block = dev->internal_start_block;
1146
1147 /* Erase all the blocks in the checkpoint area */
1148 if (forWriting) {
1149 - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1150 - dev->checkpointByteOffset = 0;
1151 - return yaffs_CheckpointErase(dev);
1152 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1153 + dev->checkpt_byte_offs = 0;
1154 + return yaffs_checkpt_erase(dev);
1155 } else {
1156 int i;
1157 /* Set to a value that will kick off a read */
1158 - dev->checkpointByteOffset = dev->nDataBytesPerChunk;
1159 + dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
1160 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
1161 * going to be way more than we need */
1162 - dev->blocksInCheckpoint = 0;
1163 - dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
1164 - dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
1165 - for (i = 0; i < dev->checkpointMaxBlocks; i++)
1166 - dev->checkpointBlockList[i] = -1;
1167 + dev->blocks_in_checkpt = 0;
1168 + dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2;
1169 + dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
1170 + if(!dev->checkpt_block_list)
1171 + return 0;
1172 +
1173 + for (i = 0; i < dev->checkpt_max_blocks; i++)
1174 + dev->checkpt_block_list[i] = -1;
1175 }
1176
1177 return 1;
1178 }
1179
1180 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
1181 +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum)
1182 {
1183 __u32 compositeSum;
1184 - compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
1185 + compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
1186 *sum = compositeSum;
1187 return 1;
1188 }
1189
1190 -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
1191 +static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
1192 {
1193 int chunk;
1194 int realignedChunk;
1195
1196 - yaffs_ExtendedTags tags;
1197 + yaffs_ext_tags tags;
1198
1199 - if (dev->checkpointCurrentBlock < 0) {
1200 - yaffs_CheckpointFindNextErasedBlock(dev);
1201 - dev->checkpointCurrentChunk = 0;
1202 + if (dev->checkpt_cur_block < 0) {
1203 + yaffs2_checkpt_find_erased_block(dev);
1204 + dev->checkpt_cur_chunk = 0;
1205 }
1206
1207 - if (dev->checkpointCurrentBlock < 0)
1208 + if (dev->checkpt_cur_block < 0)
1209 return 0;
1210
1211 - tags.chunkDeleted = 0;
1212 - tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
1213 - tags.chunkId = dev->checkpointPageSequence + 1;
1214 - tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1215 - tags.byteCount = dev->nDataBytesPerChunk;
1216 - if (dev->checkpointCurrentChunk == 0) {
1217 + tags.is_deleted = 0;
1218 + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
1219 + tags.chunk_id = dev->checkpt_page_seq + 1;
1220 + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1221 + tags.n_bytes = dev->data_bytes_per_chunk;
1222 + if (dev->checkpt_cur_chunk == 0) {
1223 /* First chunk we write for the block? Set block state to
1224 checkpoint */
1225 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
1226 - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1227 - dev->blocksInCheckpoint++;
1228 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block);
1229 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1230 + dev->blocks_in_checkpt++;
1231 }
1232
1233 - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
1234 + chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk;
1235
1236
1237 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
1238 - chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
1239 + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id));
1240
1241 - realignedChunk = chunk - dev->chunkOffset;
1242 + realignedChunk = chunk - dev->chunk_offset;
1243
1244 - dev->writeChunkWithTagsToNAND(dev, realignedChunk,
1245 - dev->checkpointBuffer, &tags);
1246 - dev->checkpointByteOffset = 0;
1247 - dev->checkpointPageSequence++;
1248 - dev->checkpointCurrentChunk++;
1249 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
1250 - dev->checkpointCurrentChunk = 0;
1251 - dev->checkpointCurrentBlock = -1;
1252 + dev->n_page_writes++;
1253 +
1254 + dev->param.write_chunk_tags_fn(dev, realignedChunk,
1255 + dev->checkpt_buffer, &tags);
1256 + dev->checkpt_byte_offs = 0;
1257 + dev->checkpt_page_seq++;
1258 + dev->checkpt_cur_chunk++;
1259 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
1260 + dev->checkpt_cur_chunk = 0;
1261 + dev->checkpt_cur_block = -1;
1262 }
1263 - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
1264 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1265
1266 return 1;
1267 }
1268
1269
1270 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
1271 +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes)
1272 {
1273 int i = 0;
1274 int ok = 1;
1275 @@ -244,36 +248,36 @@ int yaffs_CheckpointWrite(yaffs_Device *
1276
1277
1278
1279 - if (!dev->checkpointBuffer)
1280 + if (!dev->checkpt_buffer)
1281 return 0;
1282
1283 - if (!dev->checkpointOpenForWrite)
1284 + if (!dev->checkpt_open_write)
1285 return -1;
1286
1287 - while (i < nBytes && ok) {
1288 - dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
1289 - dev->checkpointSum += *dataBytes;
1290 - dev->checkpointXor ^= *dataBytes;
1291 + while (i < n_bytes && ok) {
1292 + dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes;
1293 + dev->checkpt_sum += *dataBytes;
1294 + dev->checkpt_xor ^= *dataBytes;
1295
1296 - dev->checkpointByteOffset++;
1297 + dev->checkpt_byte_offs++;
1298 i++;
1299 dataBytes++;
1300 - dev->checkpointByteCount++;
1301 + dev->checkpt_byte_count++;
1302
1303
1304 - if (dev->checkpointByteOffset < 0 ||
1305 - dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
1306 - ok = yaffs_CheckpointFlushBuffer(dev);
1307 + if (dev->checkpt_byte_offs < 0 ||
1308 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
1309 + ok = yaffs2_checkpt_flush_buffer(dev);
1310 }
1311
1312 return i;
1313 }
1314
1315 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
1316 +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes)
1317 {
1318 int i = 0;
1319 int ok = 1;
1320 - yaffs_ExtendedTags tags;
1321 + yaffs_ext_tags tags;
1322
1323
1324 int chunk;
1325 @@ -281,113 +285,116 @@ int yaffs_CheckpointRead(yaffs_Device *d
1326
1327 __u8 *dataBytes = (__u8 *)data;
1328
1329 - if (!dev->checkpointBuffer)
1330 + if (!dev->checkpt_buffer)
1331 return 0;
1332
1333 - if (dev->checkpointOpenForWrite)
1334 + if (dev->checkpt_open_write)
1335 return -1;
1336
1337 - while (i < nBytes && ok) {
1338 + while (i < n_bytes && ok) {
1339
1340
1341 - if (dev->checkpointByteOffset < 0 ||
1342 - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
1343 + if (dev->checkpt_byte_offs < 0 ||
1344 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
1345
1346 - if (dev->checkpointCurrentBlock < 0) {
1347 - yaffs_CheckpointFindNextCheckpointBlock(dev);
1348 - dev->checkpointCurrentChunk = 0;
1349 + if (dev->checkpt_cur_block < 0) {
1350 + yaffs2_checkpt_find_block(dev);
1351 + dev->checkpt_cur_chunk = 0;
1352 }
1353
1354 - if (dev->checkpointCurrentBlock < 0)
1355 + if (dev->checkpt_cur_block < 0)
1356 ok = 0;
1357 else {
1358 - chunk = dev->checkpointCurrentBlock *
1359 - dev->nChunksPerBlock +
1360 - dev->checkpointCurrentChunk;
1361 -
1362 - realignedChunk = chunk - dev->chunkOffset;
1363 + chunk = dev->checkpt_cur_block *
1364 + dev->param.chunks_per_block +
1365 + dev->checkpt_cur_chunk;
1366 +
1367 + realignedChunk = chunk - dev->chunk_offset;
1368 +
1369 + dev->n_page_reads++;
1370
1371 /* read in the next chunk */
1372 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
1373 - dev->readChunkWithTagsFromNAND(dev,
1374 + dev->param.read_chunk_tags_fn(dev,
1375 realignedChunk,
1376 - dev->checkpointBuffer,
1377 + dev->checkpt_buffer,
1378 &tags);
1379
1380 - if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
1381 - tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
1382 - tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1383 + if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
1384 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
1385 + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1386 ok = 0;
1387
1388 - dev->checkpointByteOffset = 0;
1389 - dev->checkpointPageSequence++;
1390 - dev->checkpointCurrentChunk++;
1391 + dev->checkpt_byte_offs = 0;
1392 + dev->checkpt_page_seq++;
1393 + dev->checkpt_cur_chunk++;
1394
1395 - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
1396 - dev->checkpointCurrentBlock = -1;
1397 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
1398 + dev->checkpt_cur_block = -1;
1399 }
1400 }
1401
1402 if (ok) {
1403 - *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
1404 - dev->checkpointSum += *dataBytes;
1405 - dev->checkpointXor ^= *dataBytes;
1406 - dev->checkpointByteOffset++;
1407 + *dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
1408 + dev->checkpt_sum += *dataBytes;
1409 + dev->checkpt_xor ^= *dataBytes;
1410 + dev->checkpt_byte_offs++;
1411 i++;
1412 dataBytes++;
1413 - dev->checkpointByteCount++;
1414 + dev->checkpt_byte_count++;
1415 }
1416 }
1417
1418 return i;
1419 }
1420
1421 -int yaffs_CheckpointClose(yaffs_Device *dev)
1422 +int yaffs_checkpt_close(yaffs_dev_t *dev)
1423 {
1424
1425 - if (dev->checkpointOpenForWrite) {
1426 - if (dev->checkpointByteOffset != 0)
1427 - yaffs_CheckpointFlushBuffer(dev);
1428 - } else {
1429 + if (dev->checkpt_open_write) {
1430 + if (dev->checkpt_byte_offs != 0)
1431 + yaffs2_checkpt_flush_buffer(dev);
1432 + } else if(dev->checkpt_block_list){
1433 int i;
1434 - for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
1435 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
1436 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1437 - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
1438 + for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) {
1439 + int blk = dev->checkpt_block_list[i];
1440 + yaffs_block_info_t *bi = NULL;
1441 + if( dev->internal_start_block <= blk && blk <= dev->internal_end_block)
1442 + bi = yaffs_get_block_info(dev, blk);
1443 + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
1444 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1445 else {
1446 /* Todo this looks odd... */
1447 }
1448 }
1449 - YFREE(dev->checkpointBlockList);
1450 - dev->checkpointBlockList = NULL;
1451 + YFREE(dev->checkpt_block_list);
1452 + dev->checkpt_block_list = NULL;
1453 }
1454
1455 - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
1456 - dev->nErasedBlocks -= dev->blocksInCheckpoint;
1457 + dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block;
1458 + dev->n_erased_blocks -= dev->blocks_in_checkpt;
1459
1460
1461 T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
1462 - dev->checkpointByteCount));
1463 + dev->checkpt_byte_count));
1464
1465 - if (dev->checkpointBuffer) {
1466 + if (dev->checkpt_buffer) {
1467 /* free the buffer */
1468 - YFREE(dev->checkpointBuffer);
1469 - dev->checkpointBuffer = NULL;
1470 + YFREE(dev->checkpt_buffer);
1471 + dev->checkpt_buffer = NULL;
1472 return 1;
1473 } else
1474 return 0;
1475 }
1476
1477 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
1478 +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev)
1479 {
1480 - /* Erase the first checksum block */
1481 -
1482 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
1483 + /* Erase the checkpoint data */
1484
1485 - if (!yaffs_CheckpointSpaceOk(dev))
1486 - return 0;
1487 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
1488 + dev->blocks_in_checkpt));
1489
1490 - return yaffs_CheckpointErase(dev);
1491 + return yaffs_checkpt_erase(dev);
1492 }
1493
1494
1495 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.h
1496 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_checkptrw.h 2010-10-20 13:17:58.941000294 +0300
1497 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_checkptrw.h 2010-10-20 13:28:16.058000294 +0300
1498 @@ -1,7 +1,7 @@
1499 /*
1500 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1501 *
1502 - * Copyright (C) 2002-2007 Aleph One Ltd.
1503 + * Copyright (C) 2002-2010 Aleph One Ltd.
1504 * for Toby Churchill Ltd and Brightstar Engineering
1505 *
1506 * Created by Charles Manning <charles@aleph1.co.uk>
1507 @@ -18,18 +18,17 @@
1508
1509 #include "yaffs_guts.h"
1510
1511 -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
1512 +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting);
1513
1514 -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
1515 +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes);
1516
1517 -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
1518 +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes);
1519
1520 -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
1521 +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum);
1522
1523 -int yaffs_CheckpointClose(yaffs_Device *dev);
1524 +int yaffs_checkpt_close(yaffs_dev_t *dev);
1525
1526 -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1527 +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev);
1528
1529
1530 #endif
1531 -
1532 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.c
1533 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.c 2010-10-20 13:17:58.942000294 +0300
1534 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.c 2010-10-20 13:28:16.025000294 +0300
1535 @@ -1,7 +1,7 @@
1536 /*
1537 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1538 *
1539 - * Copyright (C) 2002-2007 Aleph One Ltd.
1540 + * Copyright (C) 2002-2010 Aleph One Ltd.
1541 * for Toby Churchill Ltd and Brightstar Engineering
1542 *
1543 * Created by Charles Manning <charles@aleph1.co.uk>
1544 @@ -28,9 +28,6 @@
1545 * this bytes influence on the line parity.
1546 */
1547
1548 -const char *yaffs_ecc_c_version =
1549 - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
1550 -
1551 #include "yportenv.h"
1552
1553 #include "yaffs_ecc.h"
1554 @@ -72,7 +69,7 @@ static const unsigned char column_parity
1555
1556 /* Count the bits in an unsigned char or a U32 */
1557
1558 -static int yaffs_CountBits(unsigned char x)
1559 +static int yaffs_count_bits(unsigned char x)
1560 {
1561 int r = 0;
1562 while (x) {
1563 @@ -83,7 +80,7 @@ static int yaffs_CountBits(unsigned char
1564 return r;
1565 }
1566
1567 -static int yaffs_CountBits32(unsigned x)
1568 +static int yaffs_count_bits32(unsigned x)
1569 {
1570 int r = 0;
1571 while (x) {
1572 @@ -95,7 +92,7 @@ static int yaffs_CountBits32(unsigned x)
1573 }
1574
1575 /* Calculate the ECC for a 256-byte block of data */
1576 -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
1577 +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
1578 {
1579 unsigned int i;
1580
1581 @@ -166,7 +163,7 @@ void yaffs_ECCCalculate(const unsigned c
1582
1583 /* Correct the ECC on a 256 byte block of data */
1584
1585 -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1586 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1587 const unsigned char *test_ecc)
1588 {
1589 unsigned char d0, d1, d2; /* deltas */
1590 @@ -226,9 +223,9 @@ int yaffs_ECCCorrect(unsigned char *data
1591 return 1; /* Corrected the error */
1592 }
1593
1594 - if ((yaffs_CountBits(d0) +
1595 - yaffs_CountBits(d1) +
1596 - yaffs_CountBits(d2)) == 1) {
1597 + if ((yaffs_count_bits(d0) +
1598 + yaffs_count_bits(d1) +
1599 + yaffs_count_bits(d2)) == 1) {
1600 /* Reccoverable error in ecc */
1601
1602 read_ecc[0] = test_ecc[0];
1603 @@ -248,7 +245,7 @@ int yaffs_ECCCorrect(unsigned char *data
1604 /*
1605 * ECCxxxOther does ECC calcs on arbitrary n bytes of data
1606 */
1607 -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1608 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1609 yaffs_ECCOther *eccOther)
1610 {
1611 unsigned int i;
1612 @@ -258,7 +255,7 @@ void yaffs_ECCCalculateOther(const unsig
1613 unsigned line_parity_prime = 0;
1614 unsigned char b;
1615
1616 - for (i = 0; i < nBytes; i++) {
1617 + for (i = 0; i < n_bytes; i++) {
1618 b = column_parity_table[*data++];
1619 col_parity ^= b;
1620
1621 @@ -275,7 +272,7 @@ void yaffs_ECCCalculateOther(const unsig
1622 eccOther->lineParityPrime = line_parity_prime;
1623 }
1624
1625 -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1626 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1627 yaffs_ECCOther *read_ecc,
1628 const yaffs_ECCOther *test_ecc)
1629 {
1630 @@ -304,7 +301,7 @@ int yaffs_ECCCorrectOther(unsigned char
1631 if (cDelta & 0x02)
1632 bit |= 0x01;
1633
1634 - if (lDelta >= nBytes)
1635 + if (lDelta >= n_bytes)
1636 return -1;
1637
1638 data[lDelta] ^= (1 << bit);
1639 @@ -312,8 +309,8 @@ int yaffs_ECCCorrectOther(unsigned char
1640 return 1; /* corrected */
1641 }
1642
1643 - if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
1644 - yaffs_CountBits(cDelta)) == 1) {
1645 + if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) +
1646 + yaffs_count_bits(cDelta)) == 1) {
1647 /* Reccoverable error in ecc */
1648
1649 *read_ecc = *test_ecc;
1650 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.h
1651 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_ecc.h 2010-10-20 13:17:58.942000294 +0300
1652 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_ecc.h 2010-10-20 13:28:16.058000294 +0300
1653 @@ -1,7 +1,7 @@
1654 /*
1655 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1656 *
1657 - * Copyright (C) 2002-2007 Aleph One Ltd.
1658 + * Copyright (C) 2002-2010 Aleph One Ltd.
1659 * for Toby Churchill Ltd and Brightstar Engineering
1660 *
1661 * Created by Charles Manning <charles@aleph1.co.uk>
1662 @@ -32,13 +32,13 @@ typedef struct {
1663 unsigned lineParityPrime;
1664 } yaffs_ECCOther;
1665
1666 -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
1667 -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1668 +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
1669 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1670 const unsigned char *test_ecc);
1671
1672 -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1673 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1674 yaffs_ECCOther *ecc);
1675 -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1676 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1677 yaffs_ECCOther *read_ecc,
1678 const yaffs_ECCOther *test_ecc);
1679 #endif
1680 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_fs.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_fs.c
1681 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_fs.c 2010-10-20 13:17:58.944000294 +0300
1682 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_fs.c 1970-01-01 02:00:00.000000000 +0200
1683 @@ -1,2529 +0,0 @@
1684 -/*
1685 - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1686 - *
1687 - * Copyright (C) 2002-2009 Aleph One Ltd.
1688 - * for Toby Churchill Ltd and Brightstar Engineering
1689 - *
1690 - * Created by Charles Manning <charles@aleph1.co.uk>
1691 - * Acknowledgements:
1692 - * Luc van OostenRyck for numerous patches.
1693 - * Nick Bane for numerous patches.
1694 - * Nick Bane for 2.5/2.6 integration.
1695 - * Andras Toth for mknod rdev issue.
1696 - * Michael Fischer for finding the problem with inode inconsistency.
1697 - * Some code bodily lifted from JFFS
1698 - *
1699 - * This program is free software; you can redistribute it and/or modify
1700 - * it under the terms of the GNU General Public License version 2 as
1701 - * published by the Free Software Foundation.
1702 - */
1703 -
1704 -/*
1705 - *
1706 - * This is the file system front-end to YAFFS that hooks it up to
1707 - * the VFS.
1708 - *
1709 - * Special notes:
1710 - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1711 - * this superblock
1712 - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1713 - * superblock
1714 - * >> inode->u.generic_ip points to the associated yaffs_Object.
1715 - */
1716 -
1717 -const char *yaffs_fs_c_version =
1718 - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
1719 -extern const char *yaffs_guts_c_version;
1720 -
1721 -#include <linux/version.h>
1722 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1723 -#include <linux/config.h>
1724 -#endif
1725 -#include <linux/kernel.h>
1726 -#include <linux/module.h>
1727 -#include <linux/slab.h>
1728 -#include <linux/init.h>
1729 -#include <linux/fs.h>
1730 -#include <linux/proc_fs.h>
1731 -#include <linux/smp_lock.h>
1732 -#include <linux/pagemap.h>
1733 -#include <linux/mtd/mtd.h>
1734 -#include <linux/interrupt.h>
1735 -#include <linux/string.h>
1736 -#include <linux/ctype.h>
1737 -
1738 -#include "asm/div64.h"
1739 -
1740 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1741 -
1742 -#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1743 -#include <linux/statfs.h>
1744 -#define UnlockPage(p) unlock_page(p)
1745 -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1746 -
1747 -/* FIXME: use sb->s_id instead ? */
1748 -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1749 -
1750 -#else
1751 -
1752 -#include <linux/locks.h>
1753 -#define BDEVNAME_SIZE 0
1754 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1755 -
1756 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
1757 -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1758 -#define __user
1759 -#endif
1760 -
1761 -#endif
1762 -
1763 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
1764 -#define YPROC_ROOT (&proc_root)
1765 -#else
1766 -#define YPROC_ROOT NULL
1767 -#endif
1768 -
1769 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1770 -#define WRITE_SIZE_STR "writesize"
1771 -#define WRITE_SIZE(mtd) ((mtd)->writesize)
1772 -#else
1773 -#define WRITE_SIZE_STR "oobblock"
1774 -#define WRITE_SIZE(mtd) ((mtd)->oobblock)
1775 -#endif
1776 -
1777 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
1778 -#define YAFFS_USE_WRITE_BEGIN_END 1
1779 -#else
1780 -#define YAFFS_USE_WRITE_BEGIN_END 0
1781 -#endif
1782 -
1783 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
1784 -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
1785 -{
1786 - uint64_t result = partition_size;
1787 - do_div(result, block_size);
1788 - return (uint32_t)result;
1789 -}
1790 -#else
1791 -#define YCALCBLOCKS(s, b) ((s)/(b))
1792 -#endif
1793 -
1794 -#include <linux/uaccess.h>
1795 -
1796 -#include "yportenv.h"
1797 -#include "yaffs_guts.h"
1798 -
1799 -#include <linux/mtd/mtd.h>
1800 -#include "yaffs_mtdif.h"
1801 -#include "yaffs_mtdif1.h"
1802 -#include "yaffs_mtdif2.h"
1803 -
1804 -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1805 -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1806 -unsigned int yaffs_auto_checkpoint = 1;
1807 -
1808 -/* Module Parameters */
1809 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1810 -module_param(yaffs_traceMask, uint, 0644);
1811 -module_param(yaffs_wr_attempts, uint, 0644);
1812 -module_param(yaffs_auto_checkpoint, uint, 0644);
1813 -#else
1814 -MODULE_PARM(yaffs_traceMask, "i");
1815 -MODULE_PARM(yaffs_wr_attempts, "i");
1816 -MODULE_PARM(yaffs_auto_checkpoint, "i");
1817 -#endif
1818 -
1819 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
1820 -/* use iget and read_inode */
1821 -#define Y_IGET(sb, inum) iget((sb), (inum))
1822 -static void yaffs_read_inode(struct inode *inode);
1823 -
1824 -#else
1825 -/* Call local equivalent */
1826 -#define YAFFS_USE_OWN_IGET
1827 -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
1828 -
1829 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
1830 -#endif
1831 -
1832 -/*#define T(x) printk x */
1833 -
1834 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1835 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
1836 -#else
1837 -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
1838 -#endif
1839 -
1840 -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1841 -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1842 -
1843 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1844 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1845 -#else
1846 -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1847 -#endif
1848 -
1849 -static void yaffs_put_super(struct super_block *sb);
1850 -
1851 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1852 - loff_t *pos);
1853 -static ssize_t yaffs_hold_space(struct file *f);
1854 -static void yaffs_release_space(struct file *f);
1855 -
1856 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1857 -static int yaffs_file_flush(struct file *file, fl_owner_t id);
1858 -#else
1859 -static int yaffs_file_flush(struct file *file);
1860 -#endif
1861 -
1862 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1863 - int datasync);
1864 -
1865 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1866 -
1867 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1868 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1869 - struct nameidata *n);
1870 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1871 - struct nameidata *n);
1872 -#else
1873 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1874 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1875 -#endif
1876 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1877 - struct dentry *dentry);
1878 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1879 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1880 - const char *symname);
1881 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1882 -
1883 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1884 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1885 - dev_t dev);
1886 -#else
1887 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1888 - int dev);
1889 -#endif
1890 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1891 - struct inode *new_dir, struct dentry *new_dentry);
1892 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1893 -
1894 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1895 -static int yaffs_sync_fs(struct super_block *sb, int wait);
1896 -static void yaffs_write_super(struct super_block *sb);
1897 -#else
1898 -static int yaffs_sync_fs(struct super_block *sb);
1899 -static int yaffs_write_super(struct super_block *sb);
1900 -#endif
1901 -
1902 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1903 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1904 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1905 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1906 -#else
1907 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1908 -#endif
1909 -
1910 -#ifdef YAFFS_HAS_PUT_INODE
1911 -static void yaffs_put_inode(struct inode *inode);
1912 -#endif
1913 -
1914 -static void yaffs_delete_inode(struct inode *);
1915 -static void yaffs_clear_inode(struct inode *);
1916 -
1917 -static int yaffs_readpage(struct file *file, struct page *page);
1918 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1919 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1920 -#else
1921 -static int yaffs_writepage(struct page *page);
1922 -#endif
1923 -
1924 -
1925 -#if (YAFFS_USE_WRITE_BEGIN_END != 0)
1926 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1927 - loff_t pos, unsigned len, unsigned flags,
1928 - struct page **pagep, void **fsdata);
1929 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1930 - loff_t pos, unsigned len, unsigned copied,
1931 - struct page *pg, void *fsdadata);
1932 -#else
1933 -static int yaffs_prepare_write(struct file *f, struct page *pg,
1934 - unsigned offset, unsigned to);
1935 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1936 - unsigned to);
1937 -
1938 -#endif
1939 -
1940 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
1941 - int buflen);
1942 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
1943 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1944 -#else
1945 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1946 -#endif
1947 -
1948 -static struct address_space_operations yaffs_file_address_operations = {
1949 - .readpage = yaffs_readpage,
1950 - .writepage = yaffs_writepage,
1951 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
1952 - .write_begin = yaffs_write_begin,
1953 - .write_end = yaffs_write_end,
1954 -#else
1955 - .prepare_write = yaffs_prepare_write,
1956 - .commit_write = yaffs_commit_write,
1957 -#endif
1958 -};
1959 -
1960 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
1961 -static const struct file_operations yaffs_file_operations = {
1962 - .read = do_sync_read,
1963 - .write = do_sync_write,
1964 - .aio_read = generic_file_aio_read,
1965 - .aio_write = generic_file_aio_write,
1966 - .mmap = generic_file_mmap,
1967 - .flush = yaffs_file_flush,
1968 - .fsync = yaffs_sync_object,
1969 - .splice_read = generic_file_splice_read,
1970 - .splice_write = generic_file_splice_write,
1971 - .llseek = generic_file_llseek,
1972 -};
1973 -
1974 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
1975 -
1976 -static const struct file_operations yaffs_file_operations = {
1977 - .read = do_sync_read,
1978 - .write = do_sync_write,
1979 - .aio_read = generic_file_aio_read,
1980 - .aio_write = generic_file_aio_write,
1981 - .mmap = generic_file_mmap,
1982 - .flush = yaffs_file_flush,
1983 - .fsync = yaffs_sync_object,
1984 - .sendfile = generic_file_sendfile,
1985 -};
1986 -
1987 -#else
1988 -
1989 -static const struct file_operations yaffs_file_operations = {
1990 - .read = generic_file_read,
1991 - .write = generic_file_write,
1992 - .mmap = generic_file_mmap,
1993 - .flush = yaffs_file_flush,
1994 - .fsync = yaffs_sync_object,
1995 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1996 - .sendfile = generic_file_sendfile,
1997 -#endif
1998 -};
1999 -#endif
2000 -
2001 -static const struct inode_operations yaffs_file_inode_operations = {
2002 - .setattr = yaffs_setattr,
2003 -};
2004 -
2005 -static const struct inode_operations yaffs_symlink_inode_operations = {
2006 - .readlink = yaffs_readlink,
2007 - .follow_link = yaffs_follow_link,
2008 - .setattr = yaffs_setattr,
2009 -};
2010 -
2011 -static const struct inode_operations yaffs_dir_inode_operations = {
2012 - .create = yaffs_create,
2013 - .lookup = yaffs_lookup,
2014 - .link = yaffs_link,
2015 - .unlink = yaffs_unlink,
2016 - .symlink = yaffs_symlink,
2017 - .mkdir = yaffs_mkdir,
2018 - .rmdir = yaffs_unlink,
2019 - .mknod = yaffs_mknod,
2020 - .rename = yaffs_rename,
2021 - .setattr = yaffs_setattr,
2022 -};
2023 -
2024 -static const struct file_operations yaffs_dir_operations = {
2025 - .read = generic_read_dir,
2026 - .readdir = yaffs_readdir,
2027 - .fsync = yaffs_sync_object,
2028 -};
2029 -
2030 -static const struct super_operations yaffs_super_ops = {
2031 - .statfs = yaffs_statfs,
2032 -
2033 -#ifndef YAFFS_USE_OWN_IGET
2034 - .read_inode = yaffs_read_inode,
2035 -#endif
2036 -#ifdef YAFFS_HAS_PUT_INODE
2037 - .put_inode = yaffs_put_inode,
2038 -#endif
2039 - .put_super = yaffs_put_super,
2040 - .delete_inode = yaffs_delete_inode,
2041 - .clear_inode = yaffs_clear_inode,
2042 - .sync_fs = yaffs_sync_fs,
2043 - .write_super = yaffs_write_super,
2044 -};
2045 -
2046 -static void yaffs_GrossLock(yaffs_Device *dev)
2047 -{
2048 - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
2049 - down(&dev->grossLock);
2050 - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
2051 -}
2052 -
2053 -static void yaffs_GrossUnlock(yaffs_Device *dev)
2054 -{
2055 - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
2056 - up(&dev->grossLock);
2057 -}
2058 -
2059 -static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
2060 - int buflen)
2061 -{
2062 - unsigned char *alias;
2063 - int ret;
2064 -
2065 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2066 -
2067 - yaffs_GrossLock(dev);
2068 -
2069 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
2070 -
2071 - yaffs_GrossUnlock(dev);
2072 -
2073 - if (!alias)
2074 - return -ENOMEM;
2075 -
2076 - ret = vfs_readlink(dentry, buffer, buflen, alias);
2077 - kfree(alias);
2078 - return ret;
2079 -}
2080 -
2081 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2082 -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
2083 -#else
2084 -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
2085 -#endif
2086 -{
2087 - unsigned char *alias;
2088 - int ret;
2089 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2090 -
2091 - yaffs_GrossLock(dev);
2092 -
2093 - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
2094 -
2095 - yaffs_GrossUnlock(dev);
2096 -
2097 - if (!alias) {
2098 - ret = -ENOMEM;
2099 - goto out;
2100 - }
2101 -
2102 - ret = vfs_follow_link(nd, alias);
2103 - kfree(alias);
2104 -out:
2105 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2106 - return ERR_PTR(ret);
2107 -#else
2108 - return ret;
2109 -#endif
2110 -}
2111 -
2112 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2113 - yaffs_Object *obj);
2114 -
2115 -/*
2116 - * Lookup is used to find objects in the fs
2117 - */
2118 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2119 -
2120 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
2121 - struct nameidata *n)
2122 -#else
2123 -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
2124 -#endif
2125 -{
2126 - yaffs_Object *obj;
2127 - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
2128 -
2129 - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
2130 -
2131 - yaffs_GrossLock(dev);
2132 -
2133 - T(YAFFS_TRACE_OS,
2134 - ("yaffs_lookup for %d:%s\n",
2135 - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
2136 -
2137 - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
2138 - dentry->d_name.name);
2139 -
2140 - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
2141 -
2142 - /* Can't hold gross lock when calling yaffs_get_inode() */
2143 - yaffs_GrossUnlock(dev);
2144 -
2145 - if (obj) {
2146 - T(YAFFS_TRACE_OS,
2147 - ("yaffs_lookup found %d\n", obj->objectId));
2148 -
2149 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2150 -
2151 - if (inode) {
2152 - T(YAFFS_TRACE_OS,
2153 - ("yaffs_loookup dentry \n"));
2154 -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
2155 - * d_add even if NULL inode */
2156 -#if 0
2157 - /*dget(dentry); // try to solve directory bug */
2158 - d_add(dentry, inode);
2159 -
2160 - /* return dentry; */
2161 - return NULL;
2162 -#endif
2163 - }
2164 -
2165 - } else {
2166 - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
2167 -
2168 - }
2169 -
2170 -/* added NCB for 2.5/6 compatability - forces add even if inode is
2171 - * NULL which creates dentry hash */
2172 - d_add(dentry, inode);
2173 -
2174 - return NULL;
2175 -}
2176 -
2177 -
2178 -#ifdef YAFFS_HAS_PUT_INODE
2179 -
2180 -/* For now put inode is just for debugging
2181 - * Put inode is called when the inode **structure** is put.
2182 - */
2183 -static void yaffs_put_inode(struct inode *inode)
2184 -{
2185 - T(YAFFS_TRACE_OS,
2186 - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
2187 - atomic_read(&inode->i_count)));
2188 -
2189 -}
2190 -#endif
2191 -
2192 -/* clear is called to tell the fs to release any per-inode data it holds */
2193 -static void yaffs_clear_inode(struct inode *inode)
2194 -{
2195 - yaffs_Object *obj;
2196 - yaffs_Device *dev;
2197 -
2198 - obj = yaffs_InodeToObject(inode);
2199 -
2200 - T(YAFFS_TRACE_OS,
2201 - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
2202 - atomic_read(&inode->i_count),
2203 - obj ? "object exists" : "null object"));
2204 -
2205 - if (obj) {
2206 - dev = obj->myDev;
2207 - yaffs_GrossLock(dev);
2208 -
2209 - /* Clear the association between the inode and
2210 - * the yaffs_Object.
2211 - */
2212 - obj->myInode = NULL;
2213 - yaffs_InodeToObjectLV(inode) = NULL;
2214 -
2215 - /* If the object freeing was deferred, then the real
2216 - * free happens now.
2217 - * This should fix the inode inconsistency problem.
2218 - */
2219 -
2220 - yaffs_HandleDeferedFree(obj);
2221 -
2222 - yaffs_GrossUnlock(dev);
2223 - }
2224 -
2225 -}
2226 -
2227 -/* delete is called when the link count is zero and the inode
2228 - * is put (ie. nobody wants to know about it anymore, time to
2229 - * delete the file).
2230 - * NB Must call clear_inode()
2231 - */
2232 -static void yaffs_delete_inode(struct inode *inode)
2233 -{
2234 - yaffs_Object *obj = yaffs_InodeToObject(inode);
2235 - yaffs_Device *dev;
2236 -
2237 - T(YAFFS_TRACE_OS,
2238 - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
2239 - atomic_read(&inode->i_count),
2240 - obj ? "object exists" : "null object"));
2241 -
2242 - if (obj) {
2243 - dev = obj->myDev;
2244 - yaffs_GrossLock(dev);
2245 - yaffs_DeleteObject(obj);
2246 - yaffs_GrossUnlock(dev);
2247 - }
2248 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
2249 - truncate_inode_pages(&inode->i_data, 0);
2250 -#endif
2251 - clear_inode(inode);
2252 -}
2253 -
2254 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2255 -static int yaffs_file_flush(struct file *file, fl_owner_t id)
2256 -#else
2257 -static int yaffs_file_flush(struct file *file)
2258 -#endif
2259 -{
2260 - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
2261 -
2262 - yaffs_Device *dev = obj->myDev;
2263 -
2264 - T(YAFFS_TRACE_OS,
2265 - ("yaffs_file_flush object %d (%s)\n", obj->objectId,
2266 - obj->dirty ? "dirty" : "clean"));
2267 -
2268 - yaffs_GrossLock(dev);
2269 -
2270 - yaffs_FlushFile(obj, 1);
2271 -
2272 - yaffs_GrossUnlock(dev);
2273 -
2274 - return 0;
2275 -}
2276 -
2277 -static int yaffs_readpage_nolock(struct file *f, struct page *pg)
2278 -{
2279 - /* Lifted from jffs2 */
2280 -
2281 - yaffs_Object *obj;
2282 - unsigned char *pg_buf;
2283 - int ret;
2284 -
2285 - yaffs_Device *dev;
2286 -
2287 - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
2288 - (unsigned)(pg->index << PAGE_CACHE_SHIFT),
2289 - (unsigned)PAGE_CACHE_SIZE));
2290 -
2291 - obj = yaffs_DentryToObject(f->f_dentry);
2292 -
2293 - dev = obj->myDev;
2294 -
2295 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2296 - BUG_ON(!PageLocked(pg));
2297 -#else
2298 - if (!PageLocked(pg))
2299 - PAGE_BUG(pg);
2300 -#endif
2301 -
2302 - pg_buf = kmap(pg);
2303 - /* FIXME: Can kmap fail? */
2304 -
2305 - yaffs_GrossLock(dev);
2306 -
2307 - ret = yaffs_ReadDataFromFile(obj, pg_buf,
2308 - pg->index << PAGE_CACHE_SHIFT,
2309 - PAGE_CACHE_SIZE);
2310 -
2311 - yaffs_GrossUnlock(dev);
2312 -
2313 - if (ret >= 0)
2314 - ret = 0;
2315 -
2316 - if (ret) {
2317 - ClearPageUptodate(pg);
2318 - SetPageError(pg);
2319 - } else {
2320 - SetPageUptodate(pg);
2321 - ClearPageError(pg);
2322 - }
2323 -
2324 - flush_dcache_page(pg);
2325 - kunmap(pg);
2326 -
2327 - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
2328 - return ret;
2329 -}
2330 -
2331 -static int yaffs_readpage_unlock(struct file *f, struct page *pg)
2332 -{
2333 - int ret = yaffs_readpage_nolock(f, pg);
2334 - UnlockPage(pg);
2335 - return ret;
2336 -}
2337 -
2338 -static int yaffs_readpage(struct file *f, struct page *pg)
2339 -{
2340 - return yaffs_readpage_unlock(f, pg);
2341 -}
2342 -
2343 -/* writepage inspired by/stolen from smbfs */
2344 -
2345 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2346 -static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
2347 -#else
2348 -static int yaffs_writepage(struct page *page)
2349 -#endif
2350 -{
2351 - struct address_space *mapping = page->mapping;
2352 - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
2353 - struct inode *inode;
2354 - unsigned long end_index;
2355 - char *buffer;
2356 - yaffs_Object *obj;
2357 - int nWritten = 0;
2358 - unsigned nBytes;
2359 -
2360 - if (!mapping)
2361 - BUG();
2362 - inode = mapping->host;
2363 - if (!inode)
2364 - BUG();
2365 -
2366 - if (offset > inode->i_size) {
2367 - T(YAFFS_TRACE_OS,
2368 - ("yaffs_writepage at %08x, inode size = %08x!!!\n",
2369 - (unsigned)(page->index << PAGE_CACHE_SHIFT),
2370 - (unsigned)inode->i_size));
2371 - T(YAFFS_TRACE_OS,
2372 - (" -> don't care!!\n"));
2373 - unlock_page(page);
2374 - return 0;
2375 - }
2376 -
2377 - end_index = inode->i_size >> PAGE_CACHE_SHIFT;
2378 -
2379 - /* easy case */
2380 - if (page->index < end_index)
2381 - nBytes = PAGE_CACHE_SIZE;
2382 - else
2383 - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
2384 -
2385 - get_page(page);
2386 -
2387 - buffer = kmap(page);
2388 -
2389 - obj = yaffs_InodeToObject(inode);
2390 - yaffs_GrossLock(obj->myDev);
2391 -
2392 - T(YAFFS_TRACE_OS,
2393 - ("yaffs_writepage at %08x, size %08x\n",
2394 - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
2395 - T(YAFFS_TRACE_OS,
2396 - ("writepag0: obj = %05x, ino = %05x\n",
2397 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2398 -
2399 - nWritten = yaffs_WriteDataToFile(obj, buffer,
2400 - page->index << PAGE_CACHE_SHIFT, nBytes, 0);
2401 -
2402 - T(YAFFS_TRACE_OS,
2403 - ("writepag1: obj = %05x, ino = %05x\n",
2404 - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2405 -
2406 - yaffs_GrossUnlock(obj->myDev);
2407 -
2408 - kunmap(page);
2409 - SetPageUptodate(page);
2410 - UnlockPage(page);
2411 - put_page(page);
2412 -
2413 - return (nWritten == nBytes) ? 0 : -ENOSPC;
2414 -}
2415 -
2416 -
2417 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2418 -static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
2419 - loff_t pos, unsigned len, unsigned flags,
2420 - struct page **pagep, void **fsdata)
2421 -{
2422 - struct page *pg = NULL;
2423 - pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2424 - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
2425 - uint32_t to = offset + len;
2426 -
2427 - int ret = 0;
2428 - int space_held = 0;
2429 -
2430 - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
2431 - /* Get a page */
2432 -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
2433 - pg = grab_cache_page_write_begin(mapping, index, flags);
2434 -#else
2435 - pg = __grab_cache_page(mapping, index);
2436 -#endif
2437 -
2438 - *pagep = pg;
2439 - if (!pg) {
2440 - ret = -ENOMEM;
2441 - goto out;
2442 - }
2443 - /* Get fs space */
2444 - space_held = yaffs_hold_space(filp);
2445 -
2446 - if (!space_held) {
2447 - ret = -ENOSPC;
2448 - goto out;
2449 - }
2450 -
2451 - /* Update page if required */
2452 -
2453 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2454 - ret = yaffs_readpage_nolock(filp, pg);
2455 -
2456 - if (ret)
2457 - goto out;
2458 -
2459 - /* Happy path return */
2460 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
2461 -
2462 - return 0;
2463 -
2464 -out:
2465 - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
2466 - if (space_held)
2467 - yaffs_release_space(filp);
2468 - if (pg) {
2469 - unlock_page(pg);
2470 - page_cache_release(pg);
2471 - }
2472 - return ret;
2473 -}
2474 -
2475 -#else
2476 -
2477 -static int yaffs_prepare_write(struct file *f, struct page *pg,
2478 - unsigned offset, unsigned to)
2479 -{
2480 - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
2481 -
2482 - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2483 - return yaffs_readpage_nolock(f, pg);
2484 - return 0;
2485 -}
2486 -#endif
2487 -
2488 -#if (YAFFS_USE_WRITE_BEGIN_END > 0)
2489 -static int yaffs_write_end(struct file *filp, struct address_space *mapping,
2490 - loff_t pos, unsigned len, unsigned copied,
2491 - struct page *pg, void *fsdadata)
2492 -{
2493 - int ret = 0;
2494 - void *addr, *kva;
2495 - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
2496 -
2497 - kva = kmap(pg);
2498 - addr = kva + offset_into_page;
2499 -
2500 - T(YAFFS_TRACE_OS,
2501 - ("yaffs_write_end addr %x pos %x nBytes %d\n",
2502 - (unsigned) addr,
2503 - (int)pos, copied));
2504 -
2505 - ret = yaffs_file_write(filp, addr, copied, &pos);
2506 -
2507 - if (ret != copied) {
2508 - T(YAFFS_TRACE_OS,
2509 - ("yaffs_write_end not same size ret %d copied %d\n",
2510 - ret, copied));
2511 - SetPageError(pg);
2512 - ClearPageUptodate(pg);
2513 - } else {
2514 - SetPageUptodate(pg);
2515 - }
2516 -
2517 - kunmap(pg);
2518 -
2519 - yaffs_release_space(filp);
2520 - unlock_page(pg);
2521 - page_cache_release(pg);
2522 - return ret;
2523 -}
2524 -#else
2525 -
2526 -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2527 - unsigned to)
2528 -{
2529 - void *addr, *kva;
2530 -
2531 - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2532 - int nBytes = to - offset;
2533 - int nWritten;
2534 -
2535 - unsigned spos = pos;
2536 - unsigned saddr;
2537 -
2538 - kva = kmap(pg);
2539 - addr = kva + offset;
2540 -
2541 - saddr = (unsigned) addr;
2542 -
2543 - T(YAFFS_TRACE_OS,
2544 - ("yaffs_commit_write addr %x pos %x nBytes %d\n",
2545 - saddr, spos, nBytes));
2546 -
2547 - nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2548 -
2549 - if (nWritten != nBytes) {
2550 - T(YAFFS_TRACE_OS,
2551 - ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
2552 - nWritten, nBytes));
2553 - SetPageError(pg);
2554 - ClearPageUptodate(pg);
2555 - } else {
2556 - SetPageUptodate(pg);
2557 - }
2558 -
2559 - kunmap(pg);
2560 -
2561 - T(YAFFS_TRACE_OS,
2562 - ("yaffs_commit_write returning %d\n",
2563 - nWritten == nBytes ? 0 : nWritten));
2564 -
2565 - return nWritten == nBytes ? 0 : nWritten;
2566 -}
2567 -#endif
2568 -
2569 -
2570 -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
2571 -{
2572 - if (inode && obj) {
2573 -
2574 -
2575 - /* Check mode against the variant type and attempt to repair if broken. */
2576 - __u32 mode = obj->yst_mode;
2577 - switch (obj->variantType) {
2578 - case YAFFS_OBJECT_TYPE_FILE:
2579 - if (!S_ISREG(mode)) {
2580 - obj->yst_mode &= ~S_IFMT;
2581 - obj->yst_mode |= S_IFREG;
2582 - }
2583 -
2584 - break;
2585 - case YAFFS_OBJECT_TYPE_SYMLINK:
2586 - if (!S_ISLNK(mode)) {
2587 - obj->yst_mode &= ~S_IFMT;
2588 - obj->yst_mode |= S_IFLNK;
2589 - }
2590 -
2591 - break;
2592 - case YAFFS_OBJECT_TYPE_DIRECTORY:
2593 - if (!S_ISDIR(mode)) {
2594 - obj->yst_mode &= ~S_IFMT;
2595 - obj->yst_mode |= S_IFDIR;
2596 - }
2597 -
2598 - break;
2599 - case YAFFS_OBJECT_TYPE_UNKNOWN:
2600 - case YAFFS_OBJECT_TYPE_HARDLINK:
2601 - case YAFFS_OBJECT_TYPE_SPECIAL:
2602 - default:
2603 - /* TODO? */
2604 - break;
2605 - }
2606 -
2607 - inode->i_flags |= S_NOATIME;
2608 -
2609 - inode->i_ino = obj->objectId;
2610 - inode->i_mode = obj->yst_mode;
2611 - inode->i_uid = obj->yst_uid;
2612 - inode->i_gid = obj->yst_gid;
2613 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
2614 - inode->i_blksize = inode->i_sb->s_blocksize;
2615 -#endif
2616 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2617 -
2618 - inode->i_rdev = old_decode_dev(obj->yst_rdev);
2619 - inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2620 - inode->i_atime.tv_nsec = 0;
2621 - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2622 - inode->i_mtime.tv_nsec = 0;
2623 - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2624 - inode->i_ctime.tv_nsec = 0;
2625 -#else
2626 - inode->i_rdev = obj->yst_rdev;
2627 - inode->i_atime = obj->yst_atime;
2628 - inode->i_mtime = obj->yst_mtime;
2629 - inode->i_ctime = obj->yst_ctime;
2630 -#endif
2631 - inode->i_size = yaffs_GetObjectFileLength(obj);
2632 - inode->i_blocks = (inode->i_size + 511) >> 9;
2633 -
2634 - inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2635 -
2636 - T(YAFFS_TRACE_OS,
2637 - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2638 - inode->i_mode, inode->i_uid, inode->i_gid,
2639 - (int)inode->i_size, atomic_read(&inode->i_count)));
2640 -
2641 - switch (obj->yst_mode & S_IFMT) {
2642 - default: /* fifo, device or socket */
2643 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2644 - init_special_inode(inode, obj->yst_mode,
2645 - old_decode_dev(obj->yst_rdev));
2646 -#else
2647 - init_special_inode(inode, obj->yst_mode,
2648 - (dev_t) (obj->yst_rdev));
2649 -#endif
2650 - break;
2651 - case S_IFREG: /* file */
2652 - inode->i_op = &yaffs_file_inode_operations;
2653 - inode->i_fop = &yaffs_file_operations;
2654 - inode->i_mapping->a_ops =
2655 - &yaffs_file_address_operations;
2656 - break;
2657 - case S_IFDIR: /* directory */
2658 - inode->i_op = &yaffs_dir_inode_operations;
2659 - inode->i_fop = &yaffs_dir_operations;
2660 - break;
2661 - case S_IFLNK: /* symlink */
2662 - inode->i_op = &yaffs_symlink_inode_operations;
2663 - break;
2664 - }
2665 -
2666 - yaffs_InodeToObjectLV(inode) = obj;
2667 -
2668 - obj->myInode = inode;
2669 -
2670 - } else {
2671 - T(YAFFS_TRACE_OS,
2672 - ("yaffs_FileInode invalid parameters\n"));
2673 - }
2674 -
2675 -}
2676 -
2677 -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2678 - yaffs_Object *obj)
2679 -{
2680 - struct inode *inode;
2681 -
2682 - if (!sb) {
2683 - T(YAFFS_TRACE_OS,
2684 - ("yaffs_get_inode for NULL super_block!!\n"));
2685 - return NULL;
2686 -
2687 - }
2688 -
2689 - if (!obj) {
2690 - T(YAFFS_TRACE_OS,
2691 - ("yaffs_get_inode for NULL object!!\n"));
2692 - return NULL;
2693 -
2694 - }
2695 -
2696 - T(YAFFS_TRACE_OS,
2697 - ("yaffs_get_inode for object %d\n", obj->objectId));
2698 -
2699 - inode = Y_IGET(sb, obj->objectId);
2700 - if (IS_ERR(inode))
2701 - return NULL;
2702 -
2703 - /* NB Side effect: iget calls back to yaffs_read_inode(). */
2704 - /* iget also increments the inode's i_count */
2705 - /* NB You can't be holding grossLock or deadlock will happen! */
2706 -
2707 - return inode;
2708 -}
2709 -
2710 -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2711 - loff_t *pos)
2712 -{
2713 - yaffs_Object *obj;
2714 - int nWritten, ipos;
2715 - struct inode *inode;
2716 - yaffs_Device *dev;
2717 -
2718 - obj = yaffs_DentryToObject(f->f_dentry);
2719 -
2720 - dev = obj->myDev;
2721 -
2722 - yaffs_GrossLock(dev);
2723 -
2724 - inode = f->f_dentry->d_inode;
2725 -
2726 - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
2727 - ipos = inode->i_size;
2728 - else
2729 - ipos = *pos;
2730 -
2731 - if (!obj)
2732 - T(YAFFS_TRACE_OS,
2733 - ("yaffs_file_write: hey obj is null!\n"));
2734 - else
2735 - T(YAFFS_TRACE_OS,
2736 - ("yaffs_file_write about to write writing %zu bytes"
2737 - "to object %d at %d\n",
2738 - n, obj->objectId, ipos));
2739 -
2740 - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2741 -
2742 - T(YAFFS_TRACE_OS,
2743 - ("yaffs_file_write writing %zu bytes, %d written at %d\n",
2744 - n, nWritten, ipos));
2745 -
2746 - if (nWritten > 0) {
2747 - ipos += nWritten;
2748 - *pos = ipos;
2749 - if (ipos > inode->i_size) {
2750 - inode->i_size = ipos;
2751 - inode->i_blocks = (ipos + 511) >> 9;
2752 -
2753 - T(YAFFS_TRACE_OS,
2754 - ("yaffs_file_write size updated to %d bytes, "
2755 - "%d blocks\n",
2756 - ipos, (int)(inode->i_blocks)));
2757 - }
2758 -
2759 - }
2760 - yaffs_GrossUnlock(dev);
2761 - return nWritten == 0 ? -ENOSPC : nWritten;
2762 -}
2763 -
2764 -/* Space holding and freeing is done to ensure we have space available for write_begin/end */
2765 -/* For now we just assume few parallel writes and check against a small number. */
2766 -/* Todo: need to do this with a counter to handle parallel reads better */
2767 -
2768 -static ssize_t yaffs_hold_space(struct file *f)
2769 -{
2770 - yaffs_Object *obj;
2771 - yaffs_Device *dev;
2772 -
2773 - int nFreeChunks;
2774 -
2775 -
2776 - obj = yaffs_DentryToObject(f->f_dentry);
2777 -
2778 - dev = obj->myDev;
2779 -
2780 - yaffs_GrossLock(dev);
2781 -
2782 - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
2783 -
2784 - yaffs_GrossUnlock(dev);
2785 -
2786 - return (nFreeChunks > 20) ? 1 : 0;
2787 -}
2788 -
2789 -static void yaffs_release_space(struct file *f)
2790 -{
2791 - yaffs_Object *obj;
2792 - yaffs_Device *dev;
2793 -
2794 -
2795 - obj = yaffs_DentryToObject(f->f_dentry);
2796 -
2797 - dev = obj->myDev;
2798 -
2799 - yaffs_GrossLock(dev);
2800 -
2801 -
2802 - yaffs_GrossUnlock(dev);
2803 -}
2804 -
2805 -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2806 -{
2807 - yaffs_Object *obj;
2808 - yaffs_Device *dev;
2809 - struct inode *inode = f->f_dentry->d_inode;
2810 - unsigned long offset, curoffs;
2811 - struct ylist_head *i;
2812 - yaffs_Object *l;
2813 -
2814 - char name[YAFFS_MAX_NAME_LENGTH + 1];
2815 -
2816 - obj = yaffs_DentryToObject(f->f_dentry);
2817 - dev = obj->myDev;
2818 -
2819 - yaffs_GrossLock(dev);
2820 -
2821 - offset = f->f_pos;
2822 -
2823 - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2824 -
2825 - if (offset == 0) {
2826 - T(YAFFS_TRACE_OS,
2827 - ("yaffs_readdir: entry . ino %d \n",
2828 - (int)inode->i_ino));
2829 - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
2830 - goto out;
2831 - offset++;
2832 - f->f_pos++;
2833 - }
2834 - if (offset == 1) {
2835 - T(YAFFS_TRACE_OS,
2836 - ("yaffs_readdir: entry .. ino %d \n",
2837 - (int)f->f_dentry->d_parent->d_inode->i_ino));
2838 - if (filldir(dirent, "..", 2, offset,
2839 - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
2840 - goto out;
2841 - offset++;
2842 - f->f_pos++;
2843 - }
2844 -
2845 - curoffs = 1;
2846 -
2847 - /* If the directory has changed since the open or last call to
2848 - readdir, rewind to after the 2 canned entries. */
2849 -
2850 - if (f->f_version != inode->i_version) {
2851 - offset = 2;
2852 - f->f_pos = offset;
2853 - f->f_version = inode->i_version;
2854 - }
2855 -
2856 - ylist_for_each(i, &obj->variant.directoryVariant.children) {
2857 - curoffs++;
2858 - if (curoffs >= offset) {
2859 - l = ylist_entry(i, yaffs_Object, siblings);
2860 -
2861 - yaffs_GetObjectName(l, name,
2862 - YAFFS_MAX_NAME_LENGTH + 1);
2863 - T(YAFFS_TRACE_OS,
2864 - ("yaffs_readdir: %s inode %d\n", name,
2865 - yaffs_GetObjectInode(l)));
2866 -
2867 - if (filldir(dirent,
2868 - name,
2869 - strlen(name),
2870 - offset,
2871 - yaffs_GetObjectInode(l),
2872 - yaffs_GetObjectType(l)) < 0)
2873 - goto up_and_out;
2874 -
2875 - offset++;
2876 - f->f_pos++;
2877 - }
2878 - }
2879 -
2880 -up_and_out:
2881 -out:
2882 - yaffs_GrossUnlock(dev);
2883 -
2884 - return 0;
2885 -}
2886 -
2887 -/*
2888 - * File creation. Allocate an inode, and we're done..
2889 - */
2890 -
2891 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2892 -#define YCRED(x) x
2893 -#else
2894 -#define YCRED(x) (x->cred)
2895 -#endif
2896 -
2897 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2898 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2899 - dev_t rdev)
2900 -#else
2901 -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2902 - int rdev)
2903 -#endif
2904 -{
2905 - struct inode *inode;
2906 -
2907 - yaffs_Object *obj = NULL;
2908 - yaffs_Device *dev;
2909 -
2910 - yaffs_Object *parent = yaffs_InodeToObject(dir);
2911 -
2912 - int error = -ENOSPC;
2913 - uid_t uid = YCRED(current)->fsuid;
2914 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
2915 -
2916 - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2917 - mode |= S_ISGID;
2918 -
2919 - if (parent) {
2920 - T(YAFFS_TRACE_OS,
2921 - ("yaffs_mknod: parent object %d type %d\n",
2922 - parent->objectId, parent->variantType));
2923 - } else {
2924 - T(YAFFS_TRACE_OS,
2925 - ("yaffs_mknod: could not get parent object\n"));
2926 - return -EPERM;
2927 - }
2928 -
2929 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2930 - "mode %x dev %x\n",
2931 - dentry->d_name.name, mode, rdev));
2932 -
2933 - dev = parent->myDev;
2934 -
2935 - yaffs_GrossLock(dev);
2936 -
2937 - switch (mode & S_IFMT) {
2938 - default:
2939 - /* Special (socket, fifo, device...) */
2940 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
2941 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2942 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2943 - gid, old_encode_dev(rdev));
2944 -#else
2945 - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2946 - gid, rdev);
2947 -#endif
2948 - break;
2949 - case S_IFREG: /* file */
2950 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
2951 - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2952 - gid);
2953 - break;
2954 - case S_IFDIR: /* directory */
2955 - T(YAFFS_TRACE_OS,
2956 - ("yaffs_mknod: making directory\n"));
2957 - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2958 - uid, gid);
2959 - break;
2960 - case S_IFLNK: /* symlink */
2961 - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
2962 - obj = NULL; /* Do we ever get here? */
2963 - break;
2964 - }
2965 -
2966 - /* Can not call yaffs_get_inode() with gross lock held */
2967 - yaffs_GrossUnlock(dev);
2968 -
2969 - if (obj) {
2970 - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2971 - d_instantiate(dentry, inode);
2972 - T(YAFFS_TRACE_OS,
2973 - ("yaffs_mknod created object %d count = %d\n",
2974 - obj->objectId, atomic_read(&inode->i_count)));
2975 - error = 0;
2976 - } else {
2977 - T(YAFFS_TRACE_OS,
2978 - ("yaffs_mknod failed making object\n"));
2979 - error = -ENOMEM;
2980 - }
2981 -
2982 - return error;
2983 -}
2984 -
2985 -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2986 -{
2987 - int retVal;
2988 - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
2989 - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2990 - return retVal;
2991 -}
2992 -
2993 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2994 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2995 - struct nameidata *n)
2996 -#else
2997 -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2998 -#endif
2999 -{
3000 - T(YAFFS_TRACE_OS, ("yaffs_create\n"));
3001 - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
3002 -}
3003 -
3004 -static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
3005 -{
3006 - int retVal;
3007 -
3008 - yaffs_Device *dev;
3009 -
3010 - T(YAFFS_TRACE_OS,
3011 - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
3012 - dentry->d_name.name));
3013 -
3014 - dev = yaffs_InodeToObject(dir)->myDev;
3015 -
3016 - yaffs_GrossLock(dev);
3017 -
3018 - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
3019 -
3020 - if (retVal == YAFFS_OK) {
3021 - dentry->d_inode->i_nlink--;
3022 - dir->i_version++;
3023 - yaffs_GrossUnlock(dev);
3024 - mark_inode_dirty(dentry->d_inode);
3025 - return 0;
3026 - }
3027 - yaffs_GrossUnlock(dev);
3028 - return -ENOTEMPTY;
3029 -}
3030 -
3031 -/*
3032 - * Create a link...
3033 - */
3034 -static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
3035 - struct dentry *dentry)
3036 -{
3037 - struct inode *inode = old_dentry->d_inode;
3038 - yaffs_Object *obj = NULL;
3039 - yaffs_Object *link = NULL;
3040 - yaffs_Device *dev;
3041 -
3042 - T(YAFFS_TRACE_OS, ("yaffs_link\n"));
3043 -
3044 - obj = yaffs_InodeToObject(inode);
3045 - dev = obj->myDev;
3046 -
3047 - yaffs_GrossLock(dev);
3048 -
3049 - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
3050 - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
3051 - obj);
3052 -
3053 - if (link) {
3054 - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
3055 - d_instantiate(dentry, old_dentry->d_inode);
3056 - atomic_inc(&old_dentry->d_inode->i_count);
3057 - T(YAFFS_TRACE_OS,
3058 - ("yaffs_link link count %d i_count %d\n",
3059 - old_dentry->d_inode->i_nlink,
3060 - atomic_read(&old_dentry->d_inode->i_count)));
3061 - }
3062 -
3063 - yaffs_GrossUnlock(dev);
3064 -
3065 - if (link)
3066 - return 0;
3067 -
3068 - return -EPERM;
3069 -}
3070 -
3071 -static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
3072 - const char *symname)
3073 -{
3074 - yaffs_Object *obj;
3075 - yaffs_Device *dev;
3076 - uid_t uid = YCRED(current)->fsuid;
3077 - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
3078 -
3079 - T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
3080 -
3081 - dev = yaffs_InodeToObject(dir)->myDev;
3082 - yaffs_GrossLock(dev);
3083 - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
3084 - S_IFLNK | S_IRWXUGO, uid, gid, symname);
3085 - yaffs_GrossUnlock(dev);
3086 -
3087 - if (obj) {
3088 - struct inode *inode;
3089 -
3090 - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
3091 - d_instantiate(dentry, inode);
3092 - T(YAFFS_TRACE_OS, ("symlink created OK\n"));
3093 - return 0;
3094 - } else {
3095 - T(YAFFS_TRACE_OS, ("symlink not created\n"));
3096 - }
3097 -
3098 - return -ENOMEM;
3099 -}
3100 -
3101 -static int yaffs_sync_object(struct file *file, struct dentry *dentry,
3102 - int datasync)
3103 -{
3104 -
3105 - yaffs_Object *obj;
3106 - yaffs_Device *dev;
3107 -
3108 - obj = yaffs_DentryToObject(dentry);
3109 -
3110 - dev = obj->myDev;
3111 -
3112 - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
3113 - yaffs_GrossLock(dev);
3114 - yaffs_FlushFile(obj, 1);
3115 - yaffs_GrossUnlock(dev);
3116 - return 0;
3117 -}
3118 -
3119 -/*
3120 - * The VFS layer already does all the dentry stuff for rename.
3121 - *
3122 - * NB: POSIX says you can rename an object over an old object of the same name
3123 - */
3124 -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
3125 - struct inode *new_dir, struct dentry *new_dentry)
3126 -{
3127 - yaffs_Device *dev;
3128 - int retVal = YAFFS_FAIL;
3129 - yaffs_Object *target;
3130 -
3131 - T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
3132 - dev = yaffs_InodeToObject(old_dir)->myDev;
3133 -
3134 - yaffs_GrossLock(dev);
3135 -
3136 - /* Check if the target is an existing directory that is not empty. */
3137 - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
3138 - new_dentry->d_name.name);
3139 -
3140 -
3141 -
3142 - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
3143 - !ylist_empty(&target->variant.directoryVariant.children)) {
3144 -
3145 - T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
3146 -
3147 - retVal = YAFFS_FAIL;
3148 - } else {
3149 - /* Now does unlinking internally using shadowing mechanism */
3150 - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
3151 -
3152 - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
3153 - old_dentry->d_name.name,
3154 - yaffs_InodeToObject(new_dir),
3155 - new_dentry->d_name.name);
3156 - }
3157 - yaffs_GrossUnlock(dev);
3158 -
3159 - if (retVal == YAFFS_OK) {
3160 - if (target) {
3161 - new_dentry->d_inode->i_nlink--;
3162 - mark_inode_dirty(new_dentry->d_inode);
3163 - }
3164 -
3165 - return 0;
3166 - } else {
3167 - return -ENOTEMPTY;
3168 - }
3169 -}
3170 -
3171 -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
3172 -{
3173 - struct inode *inode = dentry->d_inode;
3174 - int error;
3175 - yaffs_Device *dev;
3176 -
3177 - T(YAFFS_TRACE_OS,
3178 - ("yaffs_setattr of object %d\n",
3179 - yaffs_InodeToObject(inode)->objectId));
3180 -
3181 - error = inode_change_ok(inode, attr);
3182 - if (error == 0) {
3183 - dev = yaffs_InodeToObject(inode)->myDev;
3184 - yaffs_GrossLock(dev);
3185 - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
3186 - YAFFS_OK) {
3187 - error = 0;
3188 - } else {
3189 - error = -EPERM;
3190 - }
3191 - yaffs_GrossUnlock(dev);
3192 - if (!error)
3193 - error = inode_setattr(inode, attr);
3194 - }
3195 - return error;
3196 -}
3197 -
3198 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3199 -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
3200 -{
3201 - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
3202 - struct super_block *sb = dentry->d_sb;
3203 -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3204 -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
3205 -{
3206 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3207 -#else
3208 -static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
3209 -{
3210 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3211 -#endif
3212 -
3213 - T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
3214 -
3215 - yaffs_GrossLock(dev);
3216 -
3217 - buf->f_type = YAFFS_MAGIC;
3218 - buf->f_bsize = sb->s_blocksize;
3219 - buf->f_namelen = 255;
3220 -
3221 - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
3222 - /* Do this if chunk size is not a power of 2 */
3223 -
3224 - uint64_t bytesInDev;
3225 - uint64_t bytesFree;
3226 -
3227 - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
3228 - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
3229 -
3230 - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
3231 - buf->f_blocks = bytesInDev;
3232 -
3233 - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
3234 - ((uint64_t)(dev->nDataBytesPerChunk));
3235 -
3236 - do_div(bytesFree, sb->s_blocksize);
3237 -
3238 - buf->f_bfree = bytesFree;
3239 -
3240 - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
3241 -
3242 - buf->f_blocks =
3243 - (dev->endBlock - dev->startBlock + 1) *
3244 - dev->nChunksPerBlock /
3245 - (sb->s_blocksize / dev->nDataBytesPerChunk);
3246 - buf->f_bfree =
3247 - yaffs_GetNumberOfFreeChunks(dev) /
3248 - (sb->s_blocksize / dev->nDataBytesPerChunk);
3249 - } else {
3250 - buf->f_blocks =
3251 - (dev->endBlock - dev->startBlock + 1) *
3252 - dev->nChunksPerBlock *
3253 - (dev->nDataBytesPerChunk / sb->s_blocksize);
3254 -
3255 - buf->f_bfree =
3256 - yaffs_GetNumberOfFreeChunks(dev) *
3257 - (dev->nDataBytesPerChunk / sb->s_blocksize);
3258 - }
3259 -
3260 - buf->f_files = 0;
3261 - buf->f_ffree = 0;
3262 - buf->f_bavail = buf->f_bfree;
3263 -
3264 - yaffs_GrossUnlock(dev);
3265 - return 0;
3266 -}
3267 -
3268 -
3269 -static int yaffs_do_sync_fs(struct super_block *sb)
3270 -{
3271 -
3272 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3273 - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
3274 -
3275 - if (sb->s_dirt) {
3276 - yaffs_GrossLock(dev);
3277 -
3278 - if (dev) {
3279 - yaffs_FlushEntireDeviceCache(dev);
3280 - yaffs_CheckpointSave(dev);
3281 - }
3282 -
3283 - yaffs_GrossUnlock(dev);
3284 -
3285 - sb->s_dirt = 0;
3286 - }
3287 - return 0;
3288 -}
3289 -
3290 -
3291 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3292 -static void yaffs_write_super(struct super_block *sb)
3293 -#else
3294 -static int yaffs_write_super(struct super_block *sb)
3295 -#endif
3296 -{
3297 -
3298 - T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
3299 - if (yaffs_auto_checkpoint >= 2)
3300 - yaffs_do_sync_fs(sb);
3301 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
3302 - return 0;
3303 -#endif
3304 -}
3305 -
3306 -
3307 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3308 -static int yaffs_sync_fs(struct super_block *sb, int wait)
3309 -#else
3310 -static int yaffs_sync_fs(struct super_block *sb)
3311 -#endif
3312 -{
3313 - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
3314 -
3315 - if (yaffs_auto_checkpoint >= 1)
3316 - yaffs_do_sync_fs(sb);
3317 -
3318 - return 0;
3319 -}
3320 -
3321 -#ifdef YAFFS_USE_OWN_IGET
3322 -
3323 -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
3324 -{
3325 - struct inode *inode;
3326 - yaffs_Object *obj;
3327 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3328 -
3329 - T(YAFFS_TRACE_OS,
3330 - ("yaffs_iget for %lu\n", ino));
3331 -
3332 - inode = iget_locked(sb, ino);
3333 - if (!inode)
3334 - return ERR_PTR(-ENOMEM);
3335 - if (!(inode->i_state & I_NEW))
3336 - return inode;
3337 -
3338 - /* NB This is called as a side effect of other functions, but
3339 - * we had to release the lock to prevent deadlocks, so
3340 - * need to lock again.
3341 - */
3342 -
3343 - yaffs_GrossLock(dev);
3344 -
3345 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
3346 -
3347 - yaffs_FillInodeFromObject(inode, obj);
3348 -
3349 - yaffs_GrossUnlock(dev);
3350 -
3351 - unlock_new_inode(inode);
3352 - return inode;
3353 -}
3354 -
3355 -#else
3356 -
3357 -static void yaffs_read_inode(struct inode *inode)
3358 -{
3359 - /* NB This is called as a side effect of other functions, but
3360 - * we had to release the lock to prevent deadlocks, so
3361 - * need to lock again.
3362 - */
3363 -
3364 - yaffs_Object *obj;
3365 - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
3366 -
3367 - T(YAFFS_TRACE_OS,
3368 - ("yaffs_read_inode for %d\n", (int)inode->i_ino));
3369 -
3370 - yaffs_GrossLock(dev);
3371 -
3372 - obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
3373 -
3374 - yaffs_FillInodeFromObject(inode, obj);
3375 -
3376 - yaffs_GrossUnlock(dev);
3377 -}
3378 -
3379 -#endif
3380 -
3381 -static YLIST_HEAD(yaffs_dev_list);
3382 -
3383 -#if 0 /* not used */
3384 -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
3385 -{
3386 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3387 -
3388 - if (*flags & MS_RDONLY) {
3389 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3390 -
3391 - T(YAFFS_TRACE_OS,
3392 - ("yaffs_remount_fs: %s: RO\n", dev->name));
3393 -
3394 - yaffs_GrossLock(dev);
3395 -
3396 - yaffs_FlushEntireDeviceCache(dev);
3397 -
3398 - yaffs_CheckpointSave(dev);
3399 -
3400 - if (mtd->sync)
3401 - mtd->sync(mtd);
3402 -
3403 - yaffs_GrossUnlock(dev);
3404 - } else {
3405 - T(YAFFS_TRACE_OS,
3406 - ("yaffs_remount_fs: %s: RW\n", dev->name));
3407 - }
3408 -
3409 - return 0;
3410 -}
3411 -#endif
3412 -
3413 -static void yaffs_put_super(struct super_block *sb)
3414 -{
3415 - yaffs_Device *dev = yaffs_SuperToDevice(sb);
3416 -
3417 - T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
3418 -
3419 - yaffs_GrossLock(dev);
3420 -
3421 - yaffs_FlushEntireDeviceCache(dev);
3422 -
3423 - yaffs_CheckpointSave(dev);
3424 -
3425 - if (dev->putSuperFunc)
3426 - dev->putSuperFunc(sb);
3427 -
3428 - yaffs_Deinitialise(dev);
3429 -
3430 - yaffs_GrossUnlock(dev);
3431 -
3432 - /* we assume this is protected by lock_kernel() in mount/umount */
3433 - ylist_del(&dev->devList);
3434 -
3435 - if (dev->spareBuffer) {
3436 - YFREE(dev->spareBuffer);
3437 - dev->spareBuffer = NULL;
3438 - }
3439 -
3440 - kfree(dev);
3441 -}
3442 -
3443 -
3444 -static void yaffs_MTDPutSuper(struct super_block *sb)
3445 -{
3446 - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
3447 -
3448 - if (mtd->sync)
3449 - mtd->sync(mtd);
3450 -
3451 - put_mtd_device(mtd);
3452 -}
3453 -
3454 -
3455 -static void yaffs_MarkSuperBlockDirty(void *vsb)
3456 -{
3457 - struct super_block *sb = (struct super_block *)vsb;
3458 -
3459 - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
3460 - if (sb)
3461 - sb->s_dirt = 1;
3462 -}
3463 -
3464 -typedef struct {
3465 - int inband_tags;
3466 - int skip_checkpoint_read;
3467 - int skip_checkpoint_write;
3468 - int no_cache;
3469 -} yaffs_options;
3470 -
3471 -#define MAX_OPT_LEN 20
3472 -static int yaffs_parse_options(yaffs_options *options, const char *options_str)
3473 -{
3474 - char cur_opt[MAX_OPT_LEN + 1];
3475 - int p;
3476 - int error = 0;
3477 -
3478 - /* Parse through the options which is a comma seperated list */
3479 -
3480 - while (options_str && *options_str && !error) {
3481 - memset(cur_opt, 0, MAX_OPT_LEN + 1);
3482 - p = 0;
3483 -
3484 - while (*options_str && *options_str != ',') {
3485 - if (p < MAX_OPT_LEN) {
3486 - cur_opt[p] = *options_str;
3487 - p++;
3488 - }
3489 - options_str++;
3490 - }
3491 -
3492 - if (!strcmp(cur_opt, "inband-tags"))
3493 - options->inband_tags = 1;
3494 - else if (!strcmp(cur_opt, "no-cache"))
3495 - options->no_cache = 1;
3496 - else if (!strcmp(cur_opt, "no-checkpoint-read"))
3497 - options->skip_checkpoint_read = 1;
3498 - else if (!strcmp(cur_opt, "no-checkpoint-write"))
3499 - options->skip_checkpoint_write = 1;
3500 - else if (!strcmp(cur_opt, "no-checkpoint")) {
3501 - options->skip_checkpoint_read = 1;
3502 - options->skip_checkpoint_write = 1;
3503 - } else {
3504 - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
3505 - cur_opt);
3506 - error = 1;
3507 - }
3508 - }
3509 -
3510 - return error;
3511 -}
3512 -
3513 -static struct super_block *yaffs_internal_read_super(int yaffsVersion,
3514 - struct super_block *sb,
3515 - void *data, int silent)
3516 -{
3517 - int nBlocks;
3518 - struct inode *inode = NULL;
3519 - struct dentry *root;
3520 - yaffs_Device *dev = 0;
3521 - char devname_buf[BDEVNAME_SIZE + 1];
3522 - struct mtd_info *mtd;
3523 - int err;
3524 - char *data_str = (char *)data;
3525 -
3526 - yaffs_options options;
3527 -
3528 - sb->s_magic = YAFFS_MAGIC;
3529 - sb->s_op = &yaffs_super_ops;
3530 - sb->s_flags |= MS_NOATIME;
3531 -
3532 - if (!sb)
3533 - printk(KERN_INFO "yaffs: sb is NULL\n");
3534 - else if (!sb->s_dev)
3535 - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
3536 - else if (!yaffs_devname(sb, devname_buf))
3537 - printk(KERN_INFO "yaffs: devname is NULL\n");
3538 - else
3539 - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
3540 - sb->s_dev,
3541 - yaffs_devname(sb, devname_buf));
3542 -
3543 - if (!data_str)
3544 - data_str = "";
3545 -
3546 - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
3547 -
3548 - memset(&options, 0, sizeof(options));
3549 -
3550 - if (yaffs_parse_options(&options, data_str)) {
3551 - /* Option parsing failed */
3552 - return NULL;
3553 - }
3554 -
3555 -
3556 - sb->s_blocksize = PAGE_CACHE_SIZE;
3557 - sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3558 - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3559 - T(YAFFS_TRACE_OS,
3560 - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3561 -
3562 -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3563 - T(YAFFS_TRACE_OS,
3564 - ("yaffs: Write verification disabled. All guarantees "
3565 - "null and void\n"));
3566 -#endif
3567 -
3568 - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3569 - "\"%s\"\n",
3570 - MAJOR(sb->s_dev), MINOR(sb->s_dev),
3571 - yaffs_devname(sb, devname_buf)));
3572 -
3573 - /* Check it's an mtd device..... */
3574 - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
3575 - return NULL; /* This isn't an mtd device */
3576 -
3577 - /* Get the device */
3578 - mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3579 - if (!mtd) {
3580 - T(YAFFS_TRACE_ALWAYS,
3581 - ("yaffs: MTD device #%u doesn't appear to exist\n",
3582 - MINOR(sb->s_dev)));
3583 - return NULL;
3584 - }
3585 - /* Check it's NAND */
3586 - if (mtd->type != MTD_NANDFLASH) {
3587 - T(YAFFS_TRACE_ALWAYS,
3588 - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3589 - return NULL;
3590 - }
3591 -
3592 - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3593 - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3594 - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3595 - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3596 - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3597 - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3598 - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3599 - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3600 - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3601 - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3602 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
3603 - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
3604 -#else
3605 - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
3606 -#endif
3607 -
3608 -#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3609 -
3610 - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
3611 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
3612 - yaffsVersion = 2;
3613 - }
3614 -
3615 - /* Added NCB 26/5/2006 for completeness */
3616 - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
3617 - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
3618 - yaffsVersion = 1;
3619 - }
3620 -
3621 -#endif
3622 -
3623 - if (yaffsVersion == 2) {
3624 - /* Check for version 2 style functions */
3625 - if (!mtd->erase ||
3626 - !mtd->block_isbad ||
3627 - !mtd->block_markbad ||
3628 - !mtd->read ||
3629 - !mtd->write ||
3630 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3631 - !mtd->read_oob || !mtd->write_oob) {
3632 -#else
3633 - !mtd->write_ecc ||
3634 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3635 -#endif
3636 - T(YAFFS_TRACE_ALWAYS,
3637 - ("yaffs: MTD device does not support required "
3638 - "functions\n"));;
3639 - return NULL;
3640 - }
3641 -
3642 - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3643 - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
3644 - !options.inband_tags) {
3645 - T(YAFFS_TRACE_ALWAYS,
3646 - ("yaffs: MTD device does not have the "
3647 - "right page sizes\n"));
3648 - return NULL;
3649 - }
3650 - } else {
3651 - /* Check for V1 style functions */
3652 - if (!mtd->erase ||
3653 - !mtd->read ||
3654 - !mtd->write ||
3655 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3656 - !mtd->read_oob || !mtd->write_oob) {
3657 -#else
3658 - !mtd->write_ecc ||
3659 - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3660 -#endif
3661 - T(YAFFS_TRACE_ALWAYS,
3662 - ("yaffs: MTD device does not support required "
3663 - "functions\n"));;
3664 - return NULL;
3665 - }
3666 -
3667 - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3668 - mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3669 - T(YAFFS_TRACE_ALWAYS,
3670 - ("yaffs: MTD device does not support have the "
3671 - "right page sizes\n"));
3672 - return NULL;
3673 - }
3674 - }
3675 -
3676 - /* OK, so if we got here, we have an MTD that's NAND and looks
3677 - * like it has the right capabilities
3678 - * Set the yaffs_Device up for mtd
3679 - */
3680 -
3681 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3682 - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3683 -#else
3684 - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3685 -#endif
3686 - if (!dev) {
3687 - /* Deep shit could not allocate device structure */
3688 - T(YAFFS_TRACE_ALWAYS,
3689 - ("yaffs_read_super: Failed trying to allocate "
3690 - "yaffs_Device. \n"));
3691 - return NULL;
3692 - }
3693 -
3694 - memset(dev, 0, sizeof(yaffs_Device));
3695 - dev->genericDevice = mtd;
3696 - dev->name = mtd->name;
3697 -
3698 - /* Set up the memory size parameters.... */
3699 -
3700 - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
3701 -
3702 - dev->startBlock = 0;
3703 - dev->endBlock = nBlocks - 1;
3704 - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3705 - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3706 - dev->nReservedBlocks = 5;
3707 - dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3708 - dev->inbandTags = options.inband_tags;
3709 -
3710 - /* ... and the functions. */
3711 - if (yaffsVersion == 2) {
3712 - dev->writeChunkWithTagsToNAND =
3713 - nandmtd2_WriteChunkWithTagsToNAND;
3714 - dev->readChunkWithTagsFromNAND =
3715 - nandmtd2_ReadChunkWithTagsFromNAND;
3716 - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3717 - dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3718 - dev->spareBuffer = YMALLOC(mtd->oobsize);
3719 - dev->isYaffs2 = 1;
3720 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3721 - dev->totalBytesPerChunk = mtd->writesize;
3722 - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3723 -#else
3724 - dev->totalBytesPerChunk = mtd->oobblock;
3725 - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3726 -#endif
3727 - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
3728 -
3729 - dev->startBlock = 0;
3730 - dev->endBlock = nBlocks - 1;
3731 - } else {
3732 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3733 - /* use the MTD interface in yaffs_mtdif1.c */
3734 - dev->writeChunkWithTagsToNAND =
3735 - nandmtd1_WriteChunkWithTagsToNAND;
3736 - dev->readChunkWithTagsFromNAND =
3737 - nandmtd1_ReadChunkWithTagsFromNAND;
3738 - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3739 - dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3740 -#else
3741 - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3742 - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3743 -#endif
3744 - dev->isYaffs2 = 0;
3745 - }
3746 - /* ... and common functions */
3747 - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3748 - dev->initialiseNAND = nandmtd_InitialiseNAND;
3749 -
3750 - dev->putSuperFunc = yaffs_MTDPutSuper;
3751 -
3752 - dev->superBlock = (void *)sb;
3753 - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3754 -
3755 -
3756 -#ifndef CONFIG_YAFFS_DOES_ECC
3757 - dev->useNANDECC = 1;
3758 -#endif
3759 -
3760 -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3761 - dev->wideTnodesDisabled = 1;
3762 -#endif
3763 -
3764 - dev->skipCheckpointRead = options.skip_checkpoint_read;
3765 - dev->skipCheckpointWrite = options.skip_checkpoint_write;
3766 -
3767 - /* we assume this is protected by lock_kernel() in mount/umount */
3768 - ylist_add_tail(&dev->devList, &yaffs_dev_list);
3769 -
3770 - init_MUTEX(&dev->grossLock);
3771 -
3772 - yaffs_GrossLock(dev);
3773 -
3774 - err = yaffs_GutsInitialise(dev);
3775 -
3776 - T(YAFFS_TRACE_OS,
3777 - ("yaffs_read_super: guts initialised %s\n",
3778 - (err == YAFFS_OK) ? "OK" : "FAILED"));
3779 -
3780 - /* Release lock before yaffs_get_inode() */
3781 - yaffs_GrossUnlock(dev);
3782 -
3783 - /* Create root inode */
3784 - if (err == YAFFS_OK)
3785 - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3786 - yaffs_Root(dev));
3787 -
3788 - if (!inode)
3789 - return NULL;
3790 -
3791 - inode->i_op = &yaffs_dir_inode_operations;
3792 - inode->i_fop = &yaffs_dir_operations;
3793 -
3794 - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3795 -
3796 - root = d_alloc_root(inode);
3797 -
3798 - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3799 -
3800 - if (!root) {
3801 - iput(inode);
3802 - return NULL;
3803 - }
3804 - sb->s_root = root;
3805 - sb->s_dirt = !dev->isCheckpointed;
3806 - T(YAFFS_TRACE_ALWAYS,
3807 - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
3808 -
3809 - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3810 - return sb;
3811 -}
3812 -
3813 -
3814 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3815 -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3816 - int silent)
3817 -{
3818 - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3819 -}
3820 -
3821 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3822 -static int yaffs_read_super(struct file_system_type *fs,
3823 - int flags, const char *dev_name,
3824 - void *data, struct vfsmount *mnt)
3825 -{
3826 -
3827 - return get_sb_bdev(fs, flags, dev_name, data,
3828 - yaffs_internal_read_super_mtd, mnt);
3829 -}
3830 -#else
3831 -static struct super_block *yaffs_read_super(struct file_system_type *fs,
3832 - int flags, const char *dev_name,
3833 - void *data)
3834 -{
3835 -
3836 - return get_sb_bdev(fs, flags, dev_name, data,
3837 - yaffs_internal_read_super_mtd);
3838 -}
3839 -#endif
3840 -
3841 -static struct file_system_type yaffs_fs_type = {
3842 - .owner = THIS_MODULE,
3843 - .name = "yaffs",
3844 - .get_sb = yaffs_read_super,
3845 - .kill_sb = kill_block_super,
3846 - .fs_flags = FS_REQUIRES_DEV,
3847 -};
3848 -#else
3849 -static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3850 - int silent)
3851 -{
3852 - return yaffs_internal_read_super(1, sb, data, silent);
3853 -}
3854 -
3855 -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3856 - FS_REQUIRES_DEV);
3857 -#endif
3858 -
3859 -
3860 -#ifdef CONFIG_YAFFS_YAFFS2
3861 -
3862 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3863 -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3864 - int silent)
3865 -{
3866 - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3867 -}
3868 -
3869 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3870 -static int yaffs2_read_super(struct file_system_type *fs,
3871 - int flags, const char *dev_name, void *data,
3872 - struct vfsmount *mnt)
3873 -{
3874 - return get_sb_bdev(fs, flags, dev_name, data,
3875 - yaffs2_internal_read_super_mtd, mnt);
3876 -}
3877 -#else
3878 -static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3879 - int flags, const char *dev_name,
3880 - void *data)
3881 -{
3882 -
3883 - return get_sb_bdev(fs, flags, dev_name, data,
3884 - yaffs2_internal_read_super_mtd);
3885 -}
3886 -#endif
3887 -
3888 -static struct file_system_type yaffs2_fs_type = {
3889 - .owner = THIS_MODULE,
3890 - .name = "yaffs2",
3891 - .get_sb = yaffs2_read_super,
3892 - .kill_sb = kill_block_super,
3893 - .fs_flags = FS_REQUIRES_DEV,
3894 -};
3895 -#else
3896 -static struct super_block *yaffs2_read_super(struct super_block *sb,
3897 - void *data, int silent)
3898 -{
3899 - return yaffs_internal_read_super(2, sb, data, silent);
3900 -}
3901 -
3902 -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3903 - FS_REQUIRES_DEV);
3904 -#endif
3905 -
3906 -#endif /* CONFIG_YAFFS_YAFFS2 */
3907 -
3908 -static struct proc_dir_entry *my_proc_entry;
3909 -
3910 -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3911 -{
3912 - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3913 - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3914 - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
3915 - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3916 - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3917 - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3918 - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3919 - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3920 - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3921 - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3922 - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3923 - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3924 - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3925 - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3926 - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3927 - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3928 - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3929 - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3930 - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3931 - buf += sprintf(buf, "passiveGCs......... %d\n",
3932 - dev->passiveGarbageCollections);
3933 - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3934 - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3935 - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3936 - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3937 - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3938 - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3939 - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3940 - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3941 - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3942 - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3943 - buf +=
3944 - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3945 - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3946 - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3947 - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
3948 -
3949 - return buf;
3950 -}
3951 -
3952 -static int yaffs_proc_read(char *page,
3953 - char **start,
3954 - off_t offset, int count, int *eof, void *data)
3955 -{
3956 - struct ylist_head *item;
3957 - char *buf = page;
3958 - int step = offset;
3959 - int n = 0;
3960 -
3961 - /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3962 - * We use 'offset' (*ppos) to indicate where we are in devList.
3963 - * This also assumes the user has posted a read buffer large
3964 - * enough to hold the complete output; but that's life in /proc.
3965 - */
3966 -
3967 - *(int *)start = 1;
3968 -
3969 - /* Print header first */
3970 - if (step == 0) {
3971 - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3972 - "\n%s\n%s\n", yaffs_fs_c_version,
3973 - yaffs_guts_c_version);
3974 - }
3975 -
3976 - /* hold lock_kernel while traversing yaffs_dev_list */
3977 - lock_kernel();
3978 -
3979 - /* Locate and print the Nth entry. Order N-squared but N is small. */
3980 - ylist_for_each(item, &yaffs_dev_list) {
3981 - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
3982 - if (n < step) {
3983 - n++;
3984 - continue;
3985 - }
3986 - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3987 - buf = yaffs_dump_dev(buf, dev);
3988 - break;
3989 - }
3990 - unlock_kernel();
3991 -
3992 - return buf - page < count ? buf - page : count;
3993 -}
3994 -
3995 -/**
3996 - * Set the verbosity of the warnings and error messages.
3997 - *
3998 - * Note that the names can only be a..z or _ with the current code.
3999 - */
4000 -
4001 -static struct {
4002 - char *mask_name;
4003 - unsigned mask_bitfield;
4004 -} mask_flags[] = {
4005 - {"allocate", YAFFS_TRACE_ALLOCATE},
4006 - {"always", YAFFS_TRACE_ALWAYS},
4007 - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
4008 - {"buffers", YAFFS_TRACE_BUFFERS},
4009 - {"bug", YAFFS_TRACE_BUG},
4010 - {"checkpt", YAFFS_TRACE_CHECKPOINT},
4011 - {"deletion", YAFFS_TRACE_DELETION},
4012 - {"erase", YAFFS_TRACE_ERASE},
4013 - {"error", YAFFS_TRACE_ERROR},
4014 - {"gc_detail", YAFFS_TRACE_GC_DETAIL},
4015 - {"gc", YAFFS_TRACE_GC},
4016 - {"mtd", YAFFS_TRACE_MTD},
4017 - {"nandaccess", YAFFS_TRACE_NANDACCESS},
4018 - {"os", YAFFS_TRACE_OS},
4019 - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
4020 - {"scan", YAFFS_TRACE_SCAN},
4021 - {"tracing", YAFFS_TRACE_TRACING},
4022 -
4023 - {"verify", YAFFS_TRACE_VERIFY},
4024 - {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
4025 - {"verify_full", YAFFS_TRACE_VERIFY_FULL},
4026 - {"verify_all", YAFFS_TRACE_VERIFY_ALL},
4027 -
4028 - {"write", YAFFS_TRACE_WRITE},
4029 - {"all", 0xffffffff},
4030 - {"none", 0},
4031 - {NULL, 0},
4032 -};
4033 -
4034 -#define MAX_MASK_NAME_LENGTH 40
4035 -static int yaffs_proc_write(struct file *file, const char *buf,
4036 - unsigned long count, void *data)
4037 -{
4038 - unsigned rg = 0, mask_bitfield;
4039 - char *end;
4040 - char *mask_name;
4041 - const char *x;
4042 - char substring[MAX_MASK_NAME_LENGTH + 1];
4043 - int i;
4044 - int done = 0;
4045 - int add, len = 0;
4046 - int pos = 0;
4047 -
4048 - rg = yaffs_traceMask;
4049 -
4050 - while (!done && (pos < count)) {
4051 - done = 1;
4052 - while ((pos < count) && isspace(buf[pos]))
4053 - pos++;
4054 -
4055 - switch (buf[pos]) {
4056 - case '+':
4057 - case '-':
4058 - case '=':
4059 - add = buf[pos];
4060 - pos++;
4061 - break;
4062 -
4063 - default:
4064 - add = ' ';
4065 - break;
4066 - }
4067 - mask_name = NULL;
4068 -
4069 - mask_bitfield = simple_strtoul(buf + pos, &end, 0);
4070 -
4071 - if (end > buf + pos) {
4072 - mask_name = "numeral";
4073 - len = end - (buf + pos);
4074 - pos += len;
4075 - done = 0;
4076 - } else {
4077 - for (x = buf + pos, i = 0;
4078 - (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
4079 - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
4080 - substring[i] = *x;
4081 - substring[i] = '\0';
4082 -
4083 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
4084 - if (strcmp(substring, mask_flags[i].mask_name) == 0) {
4085 - mask_name = mask_flags[i].mask_name;
4086 - mask_bitfield = mask_flags[i].mask_bitfield;
4087 - done = 0;
4088 - break;
4089 - }
4090 - }
4091 - }
4092 -
4093 - if (mask_name != NULL) {
4094 - done = 0;
4095 - switch (add) {
4096 - case '-':
4097 - rg &= ~mask_bitfield;
4098 - break;
4099 - case '+':
4100 - rg |= mask_bitfield;
4101 - break;
4102 - case '=':
4103 - rg = mask_bitfield;
4104 - break;
4105 - default:
4106 - rg |= mask_bitfield;
4107 - break;
4108 - }
4109 - }
4110 - }
4111 -
4112 - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
4113 -
4114 - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
4115 -
4116 - if (rg & YAFFS_TRACE_ALWAYS) {
4117 - for (i = 0; mask_flags[i].mask_name != NULL; i++) {
4118 - char flag;
4119 - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
4120 - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
4121 - }
4122 - }
4123 -
4124 - return count;
4125 -}
4126 -
4127 -/* Stuff to handle installation of file systems */
4128 -struct file_system_to_install {
4129 - struct file_system_type *fst;
4130 - int installed;
4131 -};
4132 -
4133 -static struct file_system_to_install fs_to_install[] = {
4134 - {&yaffs_fs_type, 0},
4135 - {&yaffs2_fs_type, 0},
4136 - {NULL, 0}
4137 -};
4138 -
4139 -static int __init init_yaffs_fs(void)
4140 -{
4141 - int error = 0;
4142 - struct file_system_to_install *fsinst;
4143 -
4144 - T(YAFFS_TRACE_ALWAYS,
4145 - ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
4146 -
4147 - /* Install the proc_fs entry */
4148 - my_proc_entry = create_proc_entry("yaffs",
4149 - S_IRUGO | S_IFREG,
4150 - YPROC_ROOT);
4151 -
4152 - if (my_proc_entry) {
4153 - my_proc_entry->write_proc = yaffs_proc_write;
4154 - my_proc_entry->read_proc = yaffs_proc_read;
4155 - my_proc_entry->data = NULL;
4156 - } else
4157 - return -ENOMEM;
4158 -
4159 - /* Now add the file system entries */
4160 -
4161 - fsinst = fs_to_install;
4162 -
4163 - while (fsinst->fst && !error) {
4164 - error = register_filesystem(fsinst->fst);
4165 - if (!error)
4166 - fsinst->installed = 1;
4167 - fsinst++;
4168 - }
4169 -
4170 - /* Any errors? uninstall */
4171 - if (error) {
4172 - fsinst = fs_to_install;
4173 -
4174 - while (fsinst->fst) {
4175 - if (fsinst->installed) {
4176 - unregister_filesystem(fsinst->fst);
4177 - fsinst->installed = 0;
4178 - }
4179 - fsinst++;
4180 - }
4181 - }
4182 -
4183 - return error;
4184 -}
4185 -
4186 -static void __exit exit_yaffs_fs(void)
4187 -{
4188 -
4189 - struct file_system_to_install *fsinst;
4190 -
4191 - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
4192 - " removing. \n"));
4193 -
4194 - remove_proc_entry("yaffs", YPROC_ROOT);
4195 -
4196 - fsinst = fs_to_install;
4197 -
4198 - while (fsinst->fst) {
4199 - if (fsinst->installed) {
4200 - unregister_filesystem(fsinst->fst);
4201 - fsinst->installed = 0;
4202 - }
4203 - fsinst++;
4204 - }
4205 -}
4206 -
4207 -module_init(init_yaffs_fs)
4208 -module_exit(exit_yaffs_fs)
4209 -
4210 -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
4211 -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
4212 -MODULE_LICENSE("GPL");
4213 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_getblockinfo.h
4214 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_getblockinfo.h 2010-10-20 13:17:58.945000294 +0300
4215 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_getblockinfo.h 2010-10-20 13:28:16.058000294 +0300
4216 @@ -1,7 +1,7 @@
4217 /*
4218 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
4219 *
4220 - * Copyright (C) 2002-2007 Aleph One Ltd.
4221 + * Copyright (C) 2002-2010 Aleph One Ltd.
4222 * for Toby Churchill Ltd and Brightstar Engineering
4223 *
4224 * Created by Charles Manning <charles@aleph1.co.uk>
4225 @@ -17,18 +17,19 @@
4226 #define __YAFFS_GETBLOCKINFO_H__
4227
4228 #include "yaffs_guts.h"
4229 +#include "yaffs_trace.h"
4230
4231 /* Function to manipulate block info */
4232 -static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
4233 +static Y_INLINE yaffs_block_info_t *yaffs_get_block_info(yaffs_dev_t * dev, int blk)
4234 {
4235 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4236 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
4237 T(YAFFS_TRACE_ERROR,
4238 (TSTR
4239 ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
4240 blk));
4241 YBUG();
4242 }
4243 - return &dev->blockInfo[blk - dev->internalStartBlock];
4244 + return &dev->block_info[blk - dev->internal_start_block];
4245 }
4246
4247 #endif
4248 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.c
4249 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.c 2010-10-20 13:17:58.951000294 +0300
4250 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.c 2010-10-20 13:28:16.027000294 +0300
4251 @@ -1,7 +1,7 @@
4252 /*
4253 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4254 *
4255 - * Copyright (C) 2002-2007 Aleph One Ltd.
4256 + * Copyright (C) 2002-2010 Aleph One Ltd.
4257 * for Toby Churchill Ltd and Brightstar Engineering
4258 *
4259 * Created by Charles Manning <charles@aleph1.co.uk>
4260 @@ -10,11 +10,8 @@
4261 * it under the terms of the GNU General Public License version 2 as
4262 * published by the Free Software Foundation.
4263 */
4264 -
4265 -const char *yaffs_guts_c_version =
4266 - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
4267 -
4268 #include "yportenv.h"
4269 +#include "yaffs_trace.h"
4270
4271 #include "yaffsinterface.h"
4272 #include "yaffs_guts.h"
4273 @@ -22,118 +19,109 @@ const char *yaffs_guts_c_version =
4274 #include "yaffs_getblockinfo.h"
4275
4276 #include "yaffs_tagscompat.h"
4277 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
4278 -#include "yaffs_qsort.h"
4279 -#endif
4280 +
4281 #include "yaffs_nand.h"
4282
4283 -#include "yaffs_checkptrw.h"
4284 +#include "yaffs_yaffs1.h"
4285 +#include "yaffs_yaffs2.h"
4286 +#include "yaffs_bitmap.h"
4287 +#include "yaffs_verify.h"
4288
4289 #include "yaffs_nand.h"
4290 #include "yaffs_packedtags2.h"
4291
4292 +#include "yaffs_nameval.h"
4293 +#include "yaffs_allocator.h"
4294
4295 -#define YAFFS_PASSIVE_GC_CHUNKS 2
4296 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
4297 +#define YAFFS_GC_GOOD_ENOUGH 2
4298 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
4299
4300 #include "yaffs_ecc.h"
4301
4302
4303 +
4304 /* Robustification (if it ever comes about...) */
4305 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
4306 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
4307 +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block);
4308 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
4309 int erasedOk);
4310 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
4311 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
4312 const __u8 *data,
4313 - const yaffs_ExtendedTags *tags);
4314 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
4315 - const yaffs_ExtendedTags *tags);
4316 + const yaffs_ext_tags *tags);
4317 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
4318 + const yaffs_ext_tags *tags);
4319
4320 /* Other local prototypes */
4321 -static int yaffs_UnlinkObject(yaffs_Object *obj);
4322 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
4323 -
4324 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
4325 +static void yaffs_update_parent(yaffs_obj_t *obj);
4326 +static int yaffs_unlink_obj(yaffs_obj_t *obj);
4327 +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj);
4328
4329 -static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
4330 +static int yaffs_write_new_chunk(yaffs_dev_t *dev,
4331 const __u8 *buffer,
4332 - yaffs_ExtendedTags *tags,
4333 + yaffs_ext_tags *tags,
4334 int useReserve);
4335 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
4336 - int chunkInNAND, int inScan);
4337
4338 -static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
4339 - yaffs_ObjectType type);
4340 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
4341 - yaffs_Object *obj);
4342 -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
4343 - int force, int isShrink, int shadows);
4344 -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
4345 -static int yaffs_CheckStructures(void);
4346 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
4347 - int chunkOffset, int *limit);
4348 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
4349 -
4350 -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
4351
4352 +static yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
4353 + yaffs_obj_type type);
4354
4355 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
4356 - int chunkInNAND);
4357
4358 -static int yaffs_UnlinkWorker(yaffs_Object *obj);
4359 +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod);
4360
4361 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
4362 - int chunkInObject);
4363 +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj);
4364 +static int yaffs_check_structures(void);
4365 +static int yaffs_generic_obj_del(yaffs_obj_t *in);
4366 +
4367 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
4368 + int nand_chunk);
4369
4370 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
4371 - yaffs_BlockInfo **blockUsedPtr);
4372 +static int yaffs_unlink_worker(yaffs_obj_t *obj);
4373
4374 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
4375 +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
4376 + int chunkInObject);
4377
4378 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
4379 +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
4380 + yaffs_block_info_t **blockUsedPtr);
4381
4382 -static void yaffs_VerifyDirectory(yaffs_Object *directory);
4383 -#ifdef YAFFS_PARANOID
4384 -static int yaffs_CheckFileSanity(yaffs_Object *in);
4385 -#else
4386 -#define yaffs_CheckFileSanity(in)
4387 -#endif
4388 +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in);
4389 +
4390 +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in);
4391 +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id);
4392
4393 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
4394 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
4395 +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
4396 + yaffs_ext_tags *tags);
4397
4398 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
4399 +static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
4400 + int nand_chunk,
4401 + const __u8 *data,
4402 + yaffs_ext_tags *tags);
4403
4404 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
4405 - yaffs_ExtendedTags *tags);
4406
4407 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
4408 - unsigned pos);
4409 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
4410 - yaffs_FileStructure *fStruct,
4411 - __u32 chunkId);
4412 +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
4413 +static void yaffs_load_oh_from_name(yaffs_dev_t *dev,YCHAR *ohName, const YCHAR *name);
4414
4415
4416 /* Function to calculate chunk and offset */
4417
4418 -static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
4419 +static void yaffs_addr_to_chunk(yaffs_dev_t *dev, loff_t addr, int *chunkOut,
4420 __u32 *offsetOut)
4421 {
4422 int chunk;
4423 __u32 offset;
4424
4425 - chunk = (__u32)(addr >> dev->chunkShift);
4426 + chunk = (__u32)(addr >> dev->chunk_shift);
4427
4428 - if (dev->chunkDiv == 1) {
4429 + if (dev->chunk_div == 1) {
4430 /* easy power of 2 case */
4431 - offset = (__u32)(addr & dev->chunkMask);
4432 + offset = (__u32)(addr & dev->chunk_mask);
4433 } else {
4434 /* Non power-of-2 case */
4435
4436 loff_t chunkBase;
4437
4438 - chunk /= dev->chunkDiv;
4439 + chunk /= dev->chunk_div;
4440
4441 - chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;
4442 + chunkBase = ((loff_t)chunk) * dev->data_bytes_per_chunk;
4443 offset = (__u32)(addr - chunkBase);
4444 }
4445
4446 @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
4447
4448 static __u32 Shifts(__u32 x)
4449 {
4450 - int nShifts;
4451 + __u32 nShifts;
4452
4453 nShifts = 0;
4454
4455 @@ -193,49 +181,49 @@ static __u32 Shifts(__u32 x)
4456 * Temporary buffer manipulations.
4457 */
4458
4459 -static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)
4460 +static int yaffs_init_tmp_buffers(yaffs_dev_t *dev)
4461 {
4462 int i;
4463 __u8 *buf = (__u8 *)1;
4464
4465 - memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer));
4466 + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
4467
4468 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
4469 - dev->tempBuffer[i].line = 0; /* not in use */
4470 - dev->tempBuffer[i].buffer = buf =
4471 - YMALLOC_DMA(dev->totalBytesPerChunk);
4472 + dev->temp_buffer[i].line = 0; /* not in use */
4473 + dev->temp_buffer[i].buffer = buf =
4474 + YMALLOC_DMA(dev->param.total_bytes_per_chunk);
4475 }
4476
4477 return buf ? YAFFS_OK : YAFFS_FAIL;
4478 }
4479
4480 -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo)
4481 +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no)
4482 {
4483 int i, j;
4484
4485 - dev->tempInUse++;
4486 - if (dev->tempInUse > dev->maxTemp)
4487 - dev->maxTemp = dev->tempInUse;
4488 + dev->temp_in_use++;
4489 + if (dev->temp_in_use > dev->max_temp)
4490 + dev->max_temp = dev->temp_in_use;
4491
4492 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4493 - if (dev->tempBuffer[i].line == 0) {
4494 - dev->tempBuffer[i].line = lineNo;
4495 - if ((i + 1) > dev->maxTemp) {
4496 - dev->maxTemp = i + 1;
4497 + if (dev->temp_buffer[i].line == 0) {
4498 + dev->temp_buffer[i].line = line_no;
4499 + if ((i + 1) > dev->max_temp) {
4500 + dev->max_temp = i + 1;
4501 for (j = 0; j <= i; j++)
4502 - dev->tempBuffer[j].maxLine =
4503 - dev->tempBuffer[j].line;
4504 + dev->temp_buffer[j].max_line =
4505 + dev->temp_buffer[j].line;
4506 }
4507
4508 - return dev->tempBuffer[i].buffer;
4509 + return dev->temp_buffer[i].buffer;
4510 }
4511 }
4512
4513 T(YAFFS_TRACE_BUFFERS,
4514 (TSTR("Out of temp buffers at line %d, other held by lines:"),
4515 - lineNo));
4516 + line_no));
4517 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
4518 - T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
4519 + T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->temp_buffer[i].line));
4520
4521 T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
4522
4523 @@ -244,21 +232,21 @@ __u8 *yaffs_GetTempBuffer(yaffs_Device *
4524 * This is not good.
4525 */
4526
4527 - dev->unmanagedTempAllocations++;
4528 - return YMALLOC(dev->nDataBytesPerChunk);
4529 + dev->unmanaged_buffer_allocs++;
4530 + return YMALLOC(dev->data_bytes_per_chunk);
4531
4532 }
4533
4534 -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer,
4535 - int lineNo)
4536 +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer,
4537 + int line_no)
4538 {
4539 int i;
4540
4541 - dev->tempInUse--;
4542 + dev->temp_in_use--;
4543
4544 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4545 - if (dev->tempBuffer[i].buffer == buffer) {
4546 - dev->tempBuffer[i].line = 0;
4547 + if (dev->temp_buffer[i].buffer == buffer) {
4548 + dev->temp_buffer[i].line = 0;
4549 return;
4550 }
4551 }
4552 @@ -267,9 +255,9 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic
4553 /* assume it is an unmanaged one. */
4554 T(YAFFS_TRACE_BUFFERS,
4555 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
4556 - lineNo));
4557 + line_no));
4558 YFREE(buffer);
4559 - dev->unmanagedTempDeallocations++;
4560 + dev->unmanaged_buffer_deallocs++;
4561 }
4562
4563 }
4564 @@ -277,21 +265,21 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic
4565 /*
4566 * Determine if we have a managed buffer.
4567 */
4568 -int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)
4569 +int yaffs_is_managed_tmp_buffer(yaffs_dev_t *dev, const __u8 *buffer)
4570 {
4571 int i;
4572
4573 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
4574 - if (dev->tempBuffer[i].buffer == buffer)
4575 + if (dev->temp_buffer[i].buffer == buffer)
4576 return 1;
4577 }
4578
4579 - for (i = 0; i < dev->nShortOpCaches; i++) {
4580 - if (dev->srCache[i].data == buffer)
4581 + for (i = 0; i < dev->param.n_caches; i++) {
4582 + if (dev->cache[i].data == buffer)
4583 return 1;
4584 }
4585
4586 - if (buffer == dev->checkpointBuffer)
4587 + if (buffer == dev->checkpt_buffer)
4588 return 1;
4589
4590 T(YAFFS_TRACE_ALWAYS,
4591 @@ -299,6397 +287,4205 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
4592 return 0;
4593 }
4594
4595 -
4596 -
4597 /*
4598 - * Chunk bitmap manipulations
4599 + * Verification code
4600 */
4601
4602 -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
4603 -{
4604 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
4605 - T(YAFFS_TRACE_ERROR,
4606 - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
4607 - blk));
4608 - YBUG();
4609 - }
4610 - return dev->chunkBits +
4611 - (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
4612 -}
4613
4614 -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
4615 -{
4616 - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
4617 - chunk < 0 || chunk >= dev->nChunksPerBlock) {
4618 - T(YAFFS_TRACE_ERROR,
4619 - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
4620 - blk, chunk));
4621 - YBUG();
4622 - }
4623 -}
4624
4625 -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
4626 -{
4627 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4628
4629 - memset(blkBits, 0, dev->chunkBitmapStride);
4630 -}
4631 +/*
4632 + * Simple hash function. Needs to have a reasonable spread
4633 + */
4634
4635 -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
4636 +static Y_INLINE int yaffs_hash_fn(int n)
4637 {
4638 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4639 -
4640 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4641 -
4642 - blkBits[chunk / 8] &= ~(1 << (chunk & 7));
4643 + n = abs(n);
4644 + return n % YAFFS_NOBJECT_BUCKETS;
4645 }
4646
4647 -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
4648 -{
4649 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4650 -
4651 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4652 -
4653 - blkBits[chunk / 8] |= (1 << (chunk & 7));
4654 -}
4655 +/*
4656 + * Access functions to useful fake objects.
4657 + * Note that root might have a presence in NAND if permissions are set.
4658 + */
4659
4660 -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
4661 +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev)
4662 {
4663 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4664 - yaffs_VerifyChunkBitId(dev, blk, chunk);
4665 -
4666 - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
4667 + return dev->root_dir;
4668 }
4669
4670 -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
4671 +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev)
4672 {
4673 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4674 - int i;
4675 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4676 - if (*blkBits)
4677 - return 1;
4678 - blkBits++;
4679 - }
4680 - return 0;
4681 + return dev->lost_n_found;
4682 }
4683
4684 -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
4685 -{
4686 - __u8 *blkBits = yaffs_BlockBits(dev, blk);
4687 - int i;
4688 - int n = 0;
4689 - for (i = 0; i < dev->chunkBitmapStride; i++) {
4690 - __u8 x = *blkBits;
4691 - while (x) {
4692 - if (x & 1)
4693 - n++;
4694 - x >>= 1;
4695 - }
4696 -
4697 - blkBits++;
4698 - }
4699 - return n;
4700 -}
4701
4702 /*
4703 - * Verification code
4704 + * Erased NAND checking functions
4705 */
4706
4707 -static int yaffs_SkipVerification(yaffs_Device *dev)
4708 -{
4709 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
4710 -}
4711 -
4712 -static int yaffs_SkipFullVerification(yaffs_Device *dev)
4713 -{
4714 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
4715 -}
4716 -
4717 -static int yaffs_SkipNANDVerification(yaffs_Device *dev)
4718 +int yaffs_check_ff(__u8 *buffer, int n_bytes)
4719 {
4720 - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
4721 + /* Horrible, slow implementation */
4722 + while (n_bytes--) {
4723 + if (*buffer != 0xFF)
4724 + return 0;
4725 + buffer++;
4726 + }
4727 + return 1;
4728 }
4729
4730 -static const char *blockStateName[] = {
4731 -"Unknown",
4732 -"Needs scanning",
4733 -"Scanning",
4734 -"Empty",
4735 -"Allocating",
4736 -"Full",
4737 -"Dirty",
4738 -"Checkpoint",
4739 -"Collecting",
4740 -"Dead"
4741 -};
4742 -
4743 -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
4744 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
4745 + int nand_chunk)
4746 {
4747 - int actuallyUsed;
4748 - int inUse;
4749 + int retval = YAFFS_OK;
4750 + __u8 *data = yaffs_get_temp_buffer(dev, __LINE__);
4751 + yaffs_ext_tags tags;
4752 + int result;
4753
4754 - if (yaffs_SkipVerification(dev))
4755 - return;
4756 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
4757
4758 - /* Report illegal runtime states */
4759 - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
4760 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
4761 + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
4762 + retval = YAFFS_FAIL;
4763
4764 - switch (bi->blockState) {
4765 - case YAFFS_BLOCK_STATE_UNKNOWN:
4766 - case YAFFS_BLOCK_STATE_SCANNING:
4767 - case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
4768 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
4769 - n, blockStateName[bi->blockState]));
4770 + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || tags.chunk_used) {
4771 + T(YAFFS_TRACE_NANDACCESS,
4772 + (TSTR("Chunk %d not erased" TENDSTR), nand_chunk));
4773 + retval = YAFFS_FAIL;
4774 }
4775
4776 - /* Check pages in use and soft deletions are legal */
4777 -
4778 - actuallyUsed = bi->pagesInUse - bi->softDeletions;
4779 -
4780 - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
4781 - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
4782 - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
4783 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
4784 - n, bi->pagesInUse, bi->softDeletions));
4785 -
4786 + yaffs_release_temp_buffer(dev, data, __LINE__);
4787
4788 - /* Check chunk bitmap legal */
4789 - inUse = yaffs_CountChunkBits(dev, n);
4790 - if (inUse != bi->pagesInUse)
4791 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
4792 - n, bi->pagesInUse, inUse));
4793 + return retval;
4794
4795 - /* Check that the sequence number is valid.
4796 - * Ten million is legal, but is very unlikely
4797 - */
4798 - if (dev->isYaffs2 &&
4799 - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
4800 - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
4801 - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
4802 - n, bi->sequenceNumber));
4803 }
4804
4805 -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
4806 - int n)
4807 +
4808 +static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
4809 + int nand_chunk,
4810 + const __u8 *data,
4811 + yaffs_ext_tags *tags)
4812 {
4813 - yaffs_VerifyBlock(dev, bi, n);
4814 + int retval = YAFFS_OK;
4815 + yaffs_ext_tags tempTags;
4816 + __u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__);
4817 + int result;
4818 +
4819 + result = yaffs_rd_chunk_tags_nand(dev,nand_chunk,buffer,&tempTags);
4820 + if(memcmp(buffer,data,dev->data_bytes_per_chunk) ||
4821 + tempTags.obj_id != tags->obj_id ||
4822 + tempTags.chunk_id != tags->chunk_id ||
4823 + tempTags.n_bytes != tags->n_bytes)
4824 + retval = YAFFS_FAIL;
4825
4826 - /* After collection the block should be in the erased state */
4827 - /* This will need to change if we do partial gc */
4828 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
4829
4830 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
4831 - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
4832 - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
4833 - n, bi->blockState));
4834 - }
4835 + return retval;
4836 }
4837
4838 -static void yaffs_VerifyBlocks(yaffs_Device *dev)
4839 +static int yaffs_write_new_chunk(struct yaffs_dev_s *dev,
4840 + const __u8 *data,
4841 + yaffs_ext_tags *tags,
4842 + int useReserve)
4843 {
4844 - int i;
4845 - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
4846 - int nIllegalBlockStates = 0;
4847 -
4848 - if (yaffs_SkipVerification(dev))
4849 - return;
4850 -
4851 - memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
4852 -
4853 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
4854 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
4855 - yaffs_VerifyBlock(dev, bi, i);
4856 -
4857 - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
4858 - nBlocksPerState[bi->blockState]++;
4859 - else
4860 - nIllegalBlockStates++;
4861 - }
4862 + int attempts = 0;
4863 + int writeOk = 0;
4864 + int chunk;
4865
4866 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4867 - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
4868 + yaffs2_checkpt_invalidate(dev);
4869
4870 - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
4871 - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
4872 - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
4873 + do {
4874 + yaffs_block_info_t *bi = 0;
4875 + int erasedOk = 0;
4876
4877 - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
4878 - T(YAFFS_TRACE_VERIFY,
4879 - (TSTR("%s %d blocks"TENDSTR),
4880 - blockStateName[i], nBlocksPerState[i]));
4881 + chunk = yaffs_alloc_chunk(dev, useReserve, &bi);
4882 + if (chunk < 0) {
4883 + /* no space */
4884 + break;
4885 + }
4886
4887 - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
4888 - T(YAFFS_TRACE_VERIFY,
4889 - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
4890 - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
4891 + /* First check this chunk is erased, if it needs
4892 + * checking. The checking policy (unless forced
4893 + * always on) is as follows:
4894 + *
4895 + * Check the first page we try to write in a block.
4896 + * If the check passes then we don't need to check any
4897 + * more. If the check fails, we check again...
4898 + * If the block has been erased, we don't need to check.
4899 + *
4900 + * However, if the block has been prioritised for gc,
4901 + * then we think there might be something odd about
4902 + * this block and stop using it.
4903 + *
4904 + * Rationale: We should only ever see chunks that have
4905 + * not been erased if there was a partially written
4906 + * chunk due to power loss. This checking policy should
4907 + * catch that case with very few checks and thus save a
4908 + * lot of checks that are most likely not needed.
4909 + *
4910 + * Mods to the above
4911 + * If an erase check fails or the write fails we skip the
4912 + * rest of the block.
4913 + */
4914
4915 - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
4916 - T(YAFFS_TRACE_VERIFY,
4917 - (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
4918 - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
4919 + /* let's give it a try */
4920 + attempts++;
4921
4922 - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
4923 - T(YAFFS_TRACE_VERIFY,
4924 - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
4925 - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
4926 + if(dev->param.always_check_erased)
4927 + bi->skip_erased_check = 0;
4928
4929 - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
4930 + if (!bi->skip_erased_check) {
4931 + erasedOk = yaffs_check_chunk_erased(dev, chunk);
4932 + if (erasedOk != YAFFS_OK) {
4933 + T(YAFFS_TRACE_ERROR,
4934 + (TSTR("**>> yaffs chunk %d was not erased"
4935 + TENDSTR), chunk));
4936
4937 -}
4938 + /* If not erased, delete this one,
4939 + * skip rest of block and
4940 + * try another chunk */
4941 + yaffs_chunk_del(dev,chunk,1,__LINE__);
4942 + yaffs_skip_rest_of_block(dev);
4943 + continue;
4944 + }
4945 + }
4946
4947 -/*
4948 - * Verify the object header. oh must be valid, but obj and tags may be NULL in which
4949 - * case those tests will not be performed.
4950 - */
4951 -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
4952 -{
4953 - if (obj && yaffs_SkipVerification(obj->myDev))
4954 - return;
4955 + writeOk = yaffs_wr_chunk_tags_nand(dev, chunk,
4956 + data, tags);
4957
4958 - if (!(tags && obj && oh)) {
4959 - T(YAFFS_TRACE_VERIFY,
4960 - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
4961 - (__u32)tags, (__u32)obj, (__u32)oh));
4962 - return;
4963 - }
4964 + if(!bi->skip_erased_check)
4965 + writeOk = yaffs_verify_chunk_written(dev, chunk, data, tags);
4966
4967 - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
4968 - oh->type > YAFFS_OBJECT_TYPE_MAX)
4969 - T(YAFFS_TRACE_VERIFY,
4970 - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
4971 - tags->objectId, oh->type));
4972 + if (writeOk != YAFFS_OK) {
4973 + /* Clean up aborted write, skip to next block and
4974 + * try another chunk */
4975 + yaffs_handle_chunk_wr_error(dev, chunk, erasedOk);
4976 + continue;
4977 + }
4978
4979 - if (tags->objectId != obj->objectId)
4980 - T(YAFFS_TRACE_VERIFY,
4981 - (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
4982 - tags->objectId, obj->objectId));
4983 + bi->skip_erased_check = 1;
4984
4985 + /* Copy the data into the robustification buffer */
4986 + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
4987
4988 - /*
4989 - * Check that the object's parent ids match if parentCheck requested.
4990 - *
4991 - * Tests do not apply to the root object.
4992 - */
4993 + } while (writeOk != YAFFS_OK &&
4994 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
4995
4996 - if (parentCheck && tags->objectId > 1 && !obj->parent)
4997 - T(YAFFS_TRACE_VERIFY,
4998 - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
4999 - tags->objectId, oh->parentObjectId));
5000 + if (!writeOk)
5001 + chunk = -1;
5002
5003 - if (parentCheck && obj->parent &&
5004 - oh->parentObjectId != obj->parent->objectId &&
5005 - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
5006 - obj->parent->objectId != YAFFS_OBJECTID_DELETED))
5007 - T(YAFFS_TRACE_VERIFY,
5008 - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
5009 - tags->objectId, oh->parentObjectId, obj->parent->objectId));
5010 + if (attempts > 1) {
5011 + T(YAFFS_TRACE_ERROR,
5012 + (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5013 + attempts));
5014
5015 - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
5016 - T(YAFFS_TRACE_VERIFY,
5017 - (TSTR("Obj %d header name is NULL"TENDSTR),
5018 - obj->objectId));
5019 + dev->n_retired_writes += (attempts - 1);
5020 + }
5021
5022 - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
5023 - T(YAFFS_TRACE_VERIFY,
5024 - (TSTR("Obj %d header name is 0xFF"TENDSTR),
5025 - obj->objectId));
5026 + return chunk;
5027 }
5028
5029
5030 +
5031 +/*
5032 + * Block retiring for handling a broken block.
5033 + */
5034
5035 -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
5036 - __u32 level, int chunkOffset)
5037 +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block)
5038 {
5039 - int i;
5040 - yaffs_Device *dev = obj->myDev;
5041 - int ok = 1;
5042 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
5043
5044 - if (tn) {
5045 - if (level > 0) {
5046 + yaffs2_checkpt_invalidate(dev);
5047 +
5048 + yaffs2_clear_oldest_dirty_seq(dev,bi);
5049
5050 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
5051 - if (tn->internal[i]) {
5052 - ok = yaffs_VerifyTnodeWorker(obj,
5053 - tn->internal[i],
5054 - level - 1,
5055 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
5056 - }
5057 - }
5058 - } else if (level == 0) {
5059 - yaffs_ExtendedTags tags;
5060 - __u32 objectId = obj->objectId;
5061 + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
5062 + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
5063 + T(YAFFS_TRACE_ALWAYS, (TSTR(
5064 + "yaffs: Failed to mark bad and erase block %d"
5065 + TENDSTR), flash_block));
5066 + } else {
5067 + yaffs_ext_tags tags;
5068 + int chunk_id = flash_block * dev->param.chunks_per_block;
5069
5070 - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
5071 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
5072
5073 - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
5074 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5075 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
5076 + yaffs_init_tags(&tags);
5077 + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
5078 + if (dev->param.write_chunk_tags_fn(dev, chunk_id -
5079 + dev->chunk_offset, buffer, &tags) != YAFFS_OK)
5080 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5081 + TCONT("write bad block marker to block %d")
5082 + TENDSTR), flash_block));
5083
5084 - if (theChunk > 0) {
5085 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
5086 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
5087 - if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
5088 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
5089 - objectId, chunkOffset, theChunk,
5090 - tags.objectId, tags.chunkId));
5091 - }
5092 - }
5093 - chunkOffset++;
5094 - }
5095 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
5096 }
5097 }
5098
5099 - return ok;
5100 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
5101 + bi->gc_prioritise = 0;
5102 + bi->needs_retiring = 0;
5103
5104 + dev->n_retired_blocks++;
5105 }
5106
5107 +/*
5108 + * Functions for robustisizing TODO
5109 + *
5110 + */
5111
5112 -static void yaffs_VerifyFile(yaffs_Object *obj)
5113 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
5114 + const __u8 *data,
5115 + const yaffs_ext_tags *tags)
5116 {
5117 - int requiredTallness;
5118 - int actualTallness;
5119 - __u32 lastChunk;
5120 - __u32 x;
5121 - __u32 i;
5122 - yaffs_Device *dev;
5123 - yaffs_ExtendedTags tags;
5124 - yaffs_Tnode *tn;
5125 - __u32 objectId;
5126 + dev=dev;
5127 + nand_chunk=nand_chunk;
5128 + data=data;
5129 + tags=tags;
5130 +}
5131
5132 - if (!obj)
5133 - return;
5134 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
5135 + const yaffs_ext_tags *tags)
5136 +{
5137 + dev=dev;
5138 + nand_chunk=nand_chunk;
5139 + tags=tags;
5140 +}
5141
5142 - if (yaffs_SkipVerification(obj->myDev))
5143 - return;
5144 +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi)
5145 +{
5146 + if (!bi->gc_prioritise) {
5147 + bi->gc_prioritise = 1;
5148 + dev->has_pending_prioritised_gc = 1;
5149 + bi->chunk_error_strikes++;
5150
5151 - dev = obj->myDev;
5152 - objectId = obj->objectId;
5153 + if (bi->chunk_error_strikes > 3) {
5154 + bi->needs_retiring = 1; /* Too many stikes, so retire this */
5155 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5156
5157 - /* Check file size is consistent with tnode depth */
5158 - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
5159 - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
5160 - requiredTallness = 0;
5161 - while (x > 0) {
5162 - x >>= YAFFS_TNODES_INTERNAL_BITS;
5163 - requiredTallness++;
5164 + }
5165 }
5166 +}
5167
5168 - actualTallness = obj->variant.fileVariant.topLevel;
5169 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
5170 + int erasedOk)
5171 +{
5172 + int flash_block = nand_chunk / dev->param.chunks_per_block;
5173 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
5174
5175 - if (requiredTallness > actualTallness)
5176 - T(YAFFS_TRACE_VERIFY,
5177 - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
5178 - obj->objectId, actualTallness, requiredTallness));
5179 + yaffs_handle_chunk_error(dev, bi);
5180
5181 + if (erasedOk) {
5182 + /* Was an actual write failure, so mark the block for retirement */
5183 + bi->needs_retiring = 1;
5184 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5185 + (TSTR("**>> Block %d needs retiring" TENDSTR), flash_block));
5186 + }
5187
5188 - /* Check that the chunks in the tnode tree are all correct.
5189 - * We do this by scanning through the tnode tree and
5190 - * checking the tags for every chunk match.
5191 - */
5192 + /* Delete the chunk */
5193 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
5194 + yaffs_skip_rest_of_block(dev);
5195 +}
5196
5197 - if (yaffs_SkipNANDVerification(dev))
5198 - return;
5199
5200 - for (i = 1; i <= lastChunk; i++) {
5201 - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
5202 +/*---------------- Name handling functions ------------*/
5203
5204 - if (tn) {
5205 - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
5206 - if (theChunk > 0) {
5207 - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
5208 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
5209 - if (tags.objectId != objectId || tags.chunkId != i) {
5210 - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
5211 - objectId, i, theChunk,
5212 - tags.objectId, tags.chunkId));
5213 - }
5214 - }
5215 +static __u16 yaffs_calc_name_sum(const YCHAR *name)
5216 +{
5217 + __u16 sum = 0;
5218 + __u16 i = 1;
5219 +
5220 + const YUCHAR *bname = (const YUCHAR *) name;
5221 + if (bname) {
5222 + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5223 +
5224 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5225 + sum += yaffs_toupper(*bname) * i;
5226 +#else
5227 + sum += (*bname) * i;
5228 +#endif
5229 + i++;
5230 + bname++;
5231 }
5232 }
5233 + return sum;
5234 }
5235
5236 -
5237 -static void yaffs_VerifyHardLink(yaffs_Object *obj)
5238 +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name)
5239 {
5240 - if (obj && yaffs_SkipVerification(obj->myDev))
5241 - return;
5242 -
5243 - /* Verify sane equivalent object */
5244 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5245 + memset(obj->short_name, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
5246 + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
5247 + yaffs_strcpy(obj->short_name, name);
5248 + else
5249 + obj->short_name[0] = _Y('\0');
5250 +#endif
5251 + obj->sum = yaffs_calc_name_sum(name);
5252 }
5253
5254 -static void yaffs_VerifySymlink(yaffs_Object *obj)
5255 +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh)
5256 {
5257 - if (obj && yaffs_SkipVerification(obj->myDev))
5258 - return;
5259 -
5260 - /* Verify symlink string */
5261 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
5262 + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
5263 + memset(tmpName,0,sizeof(tmpName));
5264 + yaffs_load_name_from_oh(obj->my_dev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
5265 + yaffs_set_obj_name(obj,tmpName);
5266 +#else
5267 + yaffs_set_obj_name(obj,oh->name);
5268 +#endif
5269 }
5270
5271 -static void yaffs_VerifySpecial(yaffs_Object *obj)
5272 -{
5273 - if (obj && yaffs_SkipVerification(obj->myDev))
5274 - return;
5275 -}
5276 -
5277 -static void yaffs_VerifyObject(yaffs_Object *obj)
5278 -{
5279 - yaffs_Device *dev;
5280 -
5281 - __u32 chunkMin;
5282 - __u32 chunkMax;
5283 -
5284 - __u32 chunkIdOk;
5285 - __u32 chunkInRange;
5286 - __u32 chunkShouldNotBeDeleted;
5287 - __u32 chunkValid;
5288 -
5289 - if (!obj)
5290 - return;
5291 -
5292 - if (obj->beingCreated)
5293 - return;
5294 +/*-------------------- TNODES -------------------
5295
5296 - dev = obj->myDev;
5297 + * List of spare tnodes
5298 + * The list is hooked together using the first pointer
5299 + * in the tnode.
5300 + */
5301
5302 - if (yaffs_SkipVerification(dev))
5303 - return;
5304
5305 - /* Check sane object header chunk */
5306 +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev)
5307 +{
5308 + yaffs_tnode_t *tn = yaffs_alloc_raw_tnode(dev);
5309 + if (tn){
5310 + memset(tn, 0, dev->tnode_size);
5311 + dev->n_tnodes++;
5312 + }
5313
5314 - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
5315 - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
5316 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
5317
5318 - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
5319 - chunkIdOk = chunkInRange || obj->hdrChunk == 0;
5320 - chunkValid = chunkInRange &&
5321 - yaffs_CheckChunkBit(dev,
5322 - obj->hdrChunk / dev->nChunksPerBlock,
5323 - obj->hdrChunk % dev->nChunksPerBlock);
5324 - chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
5325 + return tn;
5326 +}
5327
5328 - if (!obj->fake &&
5329 - (!chunkIdOk || chunkShouldNotBeDeleted)) {
5330 - T(YAFFS_TRACE_VERIFY,
5331 - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
5332 - obj->objectId, obj->hdrChunk,
5333 - chunkIdOk ? "" : ",out of range",
5334 - chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
5335 - }
5336 +/* FreeTnode frees up a tnode and puts it back on the free list */
5337 +static void yaffs_free_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
5338 +{
5339 + yaffs_free_raw_tnode(dev,tn);
5340 + dev->n_tnodes--;
5341 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
5342 +}
5343
5344 - if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
5345 - yaffs_ExtendedTags tags;
5346 - yaffs_ObjectHeader *oh;
5347 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5348 +static void yaffs_deinit_tnodes_and_objs(yaffs_dev_t *dev)
5349 +{
5350 + yaffs_deinit_raw_tnodes_and_objs(dev);
5351 + dev->n_obj = 0;
5352 + dev->n_tnodes = 0;
5353 +}
5354
5355 - oh = (yaffs_ObjectHeader *)buffer;
5356
5357 - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
5358 - &tags);
5359 +void yaffs_load_tnode_0(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos,
5360 + unsigned val)
5361 +{
5362 + __u32 *map = (__u32 *)tn;
5363 + __u32 bitInMap;
5364 + __u32 bitInWord;
5365 + __u32 wordInMap;
5366 + __u32 mask;
5367
5368 - yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
5369 + pos &= YAFFS_TNODES_LEVEL0_MASK;
5370 + val >>= dev->chunk_grp_bits;
5371
5372 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5373 - }
5374 + bitInMap = pos * dev->tnode_width;
5375 + wordInMap = bitInMap / 32;
5376 + bitInWord = bitInMap & (32 - 1);
5377
5378 - /* Verify it has a parent */
5379 - if (obj && !obj->fake &&
5380 - (!obj->parent || obj->parent->myDev != dev)) {
5381 - T(YAFFS_TRACE_VERIFY,
5382 - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
5383 - obj->objectId, obj->parent));
5384 - }
5385 + mask = dev->tnode_mask << bitInWord;
5386
5387 - /* Verify parent is a directory */
5388 - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
5389 - T(YAFFS_TRACE_VERIFY,
5390 - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
5391 - obj->objectId, obj->parent->variantType));
5392 - }
5393 + map[wordInMap] &= ~mask;
5394 + map[wordInMap] |= (mask & (val << bitInWord));
5395
5396 - switch (obj->variantType) {
5397 - case YAFFS_OBJECT_TYPE_FILE:
5398 - yaffs_VerifyFile(obj);
5399 - break;
5400 - case YAFFS_OBJECT_TYPE_SYMLINK:
5401 - yaffs_VerifySymlink(obj);
5402 - break;
5403 - case YAFFS_OBJECT_TYPE_DIRECTORY:
5404 - yaffs_VerifyDirectory(obj);
5405 - break;
5406 - case YAFFS_OBJECT_TYPE_HARDLINK:
5407 - yaffs_VerifyHardLink(obj);
5408 - break;
5409 - case YAFFS_OBJECT_TYPE_SPECIAL:
5410 - yaffs_VerifySpecial(obj);
5411 - break;
5412 - case YAFFS_OBJECT_TYPE_UNKNOWN:
5413 - default:
5414 - T(YAFFS_TRACE_VERIFY,
5415 - (TSTR("Obj %d has illegaltype %d"TENDSTR),
5416 - obj->objectId, obj->variantType));
5417 - break;
5418 + if (dev->tnode_width > (32 - bitInWord)) {
5419 + bitInWord = (32 - bitInWord);
5420 + wordInMap++;;
5421 + mask = dev->tnode_mask >> (/*dev->tnode_width -*/ bitInWord);
5422 + map[wordInMap] &= ~mask;
5423 + map[wordInMap] |= (mask & (val >> bitInWord));
5424 }
5425 }
5426
5427 -static void yaffs_VerifyObjects(yaffs_Device *dev)
5428 +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn,
5429 + unsigned pos)
5430 {
5431 - yaffs_Object *obj;
5432 - int i;
5433 - struct ylist_head *lh;
5434 + __u32 *map = (__u32 *)tn;
5435 + __u32 bitInMap;
5436 + __u32 bitInWord;
5437 + __u32 wordInMap;
5438 + __u32 val;
5439
5440 - if (yaffs_SkipVerification(dev))
5441 - return;
5442 + pos &= YAFFS_TNODES_LEVEL0_MASK;
5443
5444 - /* Iterate through the objects in each hash entry */
5445 + bitInMap = pos * dev->tnode_width;
5446 + wordInMap = bitInMap / 32;
5447 + bitInWord = bitInMap & (32 - 1);
5448
5449 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
5450 - ylist_for_each(lh, &dev->objectBucket[i].list) {
5451 - if (lh) {
5452 - obj = ylist_entry(lh, yaffs_Object, hashLink);
5453 - yaffs_VerifyObject(obj);
5454 - }
5455 - }
5456 - }
5457 -}
5458 + val = map[wordInMap] >> bitInWord;
5459
5460 + if (dev->tnode_width > (32 - bitInWord)) {
5461 + bitInWord = (32 - bitInWord);
5462 + wordInMap++;;
5463 + val |= (map[wordInMap] << bitInWord);
5464 + }
5465
5466 -/*
5467 - * Simple hash function. Needs to have a reasonable spread
5468 - */
5469 + val &= dev->tnode_mask;
5470 + val <<= dev->chunk_grp_bits;
5471
5472 -static Y_INLINE int yaffs_HashFunction(int n)
5473 -{
5474 - n = abs(n);
5475 - return n % YAFFS_NOBJECT_BUCKETS;
5476 + return val;
5477 }
5478
5479 -/*
5480 - * Access functions to useful fake objects.
5481 - * Note that root might have a presence in NAND if permissions are set.
5482 +/* ------------------- End of individual tnode manipulation -----------------*/
5483 +
5484 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
5485 + * The look up tree is represented by the top tnode and the number of top_level
5486 + * in the tree. 0 means only the level 0 tnode is in the tree.
5487 */
5488
5489 -yaffs_Object *yaffs_Root(yaffs_Device *dev)
5490 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
5491 +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
5492 + yaffs_file_s *file_struct,
5493 + __u32 chunk_id)
5494 {
5495 - return dev->rootDir;
5496 -}
5497 + yaffs_tnode_t *tn = file_struct->top;
5498 + __u32 i;
5499 + int requiredTallness;
5500 + int level = file_struct->top_level;
5501
5502 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
5503 -{
5504 - return dev->lostNFoundDir;
5505 -}
5506 + dev=dev;
5507
5508 + /* Check sane level and chunk Id */
5509 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
5510 + return NULL;
5511
5512 -/*
5513 - * Erased NAND checking functions
5514 - */
5515 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
5516 + return NULL;
5517
5518 -int yaffs_CheckFF(__u8 *buffer, int nBytes)
5519 -{
5520 - /* Horrible, slow implementation */
5521 - while (nBytes--) {
5522 - if (*buffer != 0xFF)
5523 - return 0;
5524 - buffer++;
5525 + /* First check we're tall enough (ie enough top_level) */
5526 +
5527 + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
5528 + requiredTallness = 0;
5529 + while (i) {
5530 + i >>= YAFFS_TNODES_INTERNAL_BITS;
5531 + requiredTallness++;
5532 }
5533 - return 1;
5534 -}
5535
5536 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
5537 - int chunkInNAND)
5538 -{
5539 - int retval = YAFFS_OK;
5540 - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
5541 - yaffs_ExtendedTags tags;
5542 - int result;
5543 + if (requiredTallness > file_struct->top_level)
5544 + return NULL; /* Not tall enough, so we can't find it */
5545 +
5546 + /* Traverse down to level 0 */
5547 + while (level > 0 && tn) {
5548 + tn = tn->internal[(chunk_id >>
5549 + (YAFFS_TNODES_LEVEL0_BITS +
5550 + (level - 1) *
5551 + YAFFS_TNODES_INTERNAL_BITS)) &
5552 + YAFFS_TNODES_INTERNAL_MASK];
5553 + level--;
5554 + }
5555
5556 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
5557 + return tn;
5558 +}
5559
5560 - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
5561 - retval = YAFFS_FAIL;
5562 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
5563 + * This happens in two steps:
5564 + * 1. If the tree isn't tall enough, then make it taller.
5565 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
5566 + *
5567 + * Used when modifying the tree.
5568 + *
5569 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
5570 + * be plugged into the ttree.
5571 + */
5572
5573 - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
5574 - T(YAFFS_TRACE_NANDACCESS,
5575 - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
5576 - retval = YAFFS_FAIL;
5577 - }
5578 +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
5579 + yaffs_file_s *file_struct,
5580 + __u32 chunk_id,
5581 + yaffs_tnode_t *passed_tn)
5582 +{
5583 + int requiredTallness;
5584 + int i;
5585 + int l;
5586 + yaffs_tnode_t *tn;
5587
5588 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
5589 + __u32 x;
5590
5591 - return retval;
5592
5593 -}
5594 + /* Check sane level and page Id */
5595 + if (file_struct->top_level < 0 || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
5596 + return NULL;
5597
5598 -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
5599 - const __u8 *data,
5600 - yaffs_ExtendedTags *tags,
5601 - int useReserve)
5602 -{
5603 - int attempts = 0;
5604 - int writeOk = 0;
5605 - int chunk;
5606 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
5607 + return NULL;
5608
5609 - yaffs_InvalidateCheckpoint(dev);
5610 + /* First check we're tall enough (ie enough top_level) */
5611
5612 - do {
5613 - yaffs_BlockInfo *bi = 0;
5614 - int erasedOk = 0;
5615 + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
5616 + requiredTallness = 0;
5617 + while (x) {
5618 + x >>= YAFFS_TNODES_INTERNAL_BITS;
5619 + requiredTallness++;
5620 + }
5621
5622 - chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
5623 - if (chunk < 0) {
5624 - /* no space */
5625 - break;
5626 - }
5627
5628 - /* First check this chunk is erased, if it needs
5629 - * checking. The checking policy (unless forced
5630 - * always on) is as follows:
5631 - *
5632 - * Check the first page we try to write in a block.
5633 - * If the check passes then we don't need to check any
5634 - * more. If the check fails, we check again...
5635 - * If the block has been erased, we don't need to check.
5636 - *
5637 - * However, if the block has been prioritised for gc,
5638 - * then we think there might be something odd about
5639 - * this block and stop using it.
5640 - *
5641 - * Rationale: We should only ever see chunks that have
5642 - * not been erased if there was a partially written
5643 - * chunk due to power loss. This checking policy should
5644 - * catch that case with very few checks and thus save a
5645 - * lot of checks that are most likely not needed.
5646 - */
5647 - if (bi->gcPrioritise) {
5648 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
5649 - /* try another chunk */
5650 - continue;
5651 - }
5652 + if (requiredTallness > file_struct->top_level) {
5653 + /* Not tall enough, gotta make the tree taller */
5654 + for (i = file_struct->top_level; i < requiredTallness; i++) {
5655
5656 - /* let's give it a try */
5657 - attempts++;
5658 + tn = yaffs_get_tnode(dev);
5659
5660 -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
5661 - bi->skipErasedCheck = 0;
5662 -#endif
5663 - if (!bi->skipErasedCheck) {
5664 - erasedOk = yaffs_CheckChunkErased(dev, chunk);
5665 - if (erasedOk != YAFFS_OK) {
5666 + if (tn) {
5667 + tn->internal[0] = file_struct->top;
5668 + file_struct->top = tn;
5669 + file_struct->top_level++;
5670 + } else {
5671 T(YAFFS_TRACE_ERROR,
5672 - (TSTR("**>> yaffs chunk %d was not erased"
5673 - TENDSTR), chunk));
5674 -
5675 - /* try another chunk */
5676 - continue;
5677 + (TSTR("yaffs: no more tnodes" TENDSTR)));
5678 + return NULL;
5679 }
5680 - bi->skipErasedCheck = 1;
5681 }
5682 + }
5683
5684 - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
5685 - data, tags);
5686 - if (writeOk != YAFFS_OK) {
5687 - yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
5688 - /* try another chunk */
5689 - continue;
5690 - }
5691 + /* Traverse down to level 0, adding anything we need */
5692
5693 - /* Copy the data into the robustification buffer */
5694 - yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
5695 + l = file_struct->top_level;
5696 + tn = file_struct->top;
5697
5698 - } while (writeOk != YAFFS_OK &&
5699 - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
5700 + if (l > 0) {
5701 + while (l > 0 && tn) {
5702 + x = (chunk_id >>
5703 + (YAFFS_TNODES_LEVEL0_BITS +
5704 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
5705 + YAFFS_TNODES_INTERNAL_MASK;
5706
5707 - if (!writeOk)
5708 - chunk = -1;
5709
5710 - if (attempts > 1) {
5711 - T(YAFFS_TRACE_ERROR,
5712 - (TSTR("**>> yaffs write required %d attempts" TENDSTR),
5713 - attempts));
5714 + if ((l > 1) && !tn->internal[x]) {
5715 + /* Add missing non-level-zero tnode */
5716 + tn->internal[x] = yaffs_get_tnode(dev);
5717 + if(!tn->internal[x])
5718 + return NULL;
5719 + } else if (l == 1) {
5720 + /* Looking from level 1 at level 0 */
5721 + if (passed_tn) {
5722 + /* If we already have one, then release it.*/
5723 + if (tn->internal[x])
5724 + yaffs_free_tnode(dev, tn->internal[x]);
5725 + tn->internal[x] = passed_tn;
5726 +
5727 + } else if (!tn->internal[x]) {
5728 + /* Don't have one, none passed in */
5729 + tn->internal[x] = yaffs_get_tnode(dev);
5730 + if(!tn->internal[x])
5731 + return NULL;
5732 + }
5733 + }
5734
5735 - dev->nRetriedWrites += (attempts - 1);
5736 + tn = tn->internal[x];
5737 + l--;
5738 + }
5739 + } else {
5740 + /* top is level 0 */
5741 + if (passed_tn) {
5742 + memcpy(tn, passed_tn, (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8);
5743 + yaffs_free_tnode(dev, passed_tn);
5744 + }
5745 }
5746
5747 - return chunk;
5748 + return tn;
5749 }
5750
5751 -/*
5752 - * Block retiring for handling a broken block.
5753 - */
5754 -
5755 -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
5756 +static int yaffs_find_chunk_in_group(yaffs_dev_t *dev, int theChunk,
5757 + yaffs_ext_tags *tags, int obj_id,
5758 + int inode_chunk)
5759 {
5760 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5761 + int j;
5762
5763 - yaffs_InvalidateCheckpoint(dev);
5764 + for (j = 0; theChunk && j < dev->chunk_grp_size; j++) {
5765 + if (yaffs_check_chunk_bit(dev, theChunk / dev->param.chunks_per_block,
5766 + theChunk % dev->param.chunks_per_block)) {
5767 +
5768 + if(dev->chunk_grp_size == 1)
5769 + return theChunk;
5770 + else {
5771 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL,
5772 + tags);
5773 + if (yaffs_tags_match(tags, obj_id, inode_chunk)) {
5774 + /* found it; */
5775 + return theChunk;
5776 + }
5777 + }
5778 + }
5779 + theChunk++;
5780 + }
5781 + return -1;
5782 +}
5783
5784 - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
5785 - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
5786 - T(YAFFS_TRACE_ALWAYS, (TSTR(
5787 - "yaffs: Failed to mark bad and erase block %d"
5788 - TENDSTR), blockInNAND));
5789 - } else {
5790 - yaffs_ExtendedTags tags;
5791 - int chunkId = blockInNAND * dev->nChunksPerBlock;
5792 +#if 0
5793 +/* Experimental code not being used yet. Might speed up file deletion */
5794 +/* DeleteWorker scans backwards through the tnode tree and deletes all the
5795 + * chunks and tnodes in the file.
5796 + * Returns 1 if the tree was deleted.
5797 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
5798 + */
5799
5800 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
5801 +static int yaffs_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, __u32 level,
5802 + int chunk_offset, int *limit)
5803 +{
5804 + int i;
5805 + int inode_chunk;
5806 + int theChunk;
5807 + yaffs_ext_tags tags;
5808 + int foundChunk;
5809 + yaffs_dev_t *dev = in->my_dev;
5810
5811 - memset(buffer, 0xff, dev->nDataBytesPerChunk);
5812 - yaffs_InitialiseTags(&tags);
5813 - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
5814 - if (dev->writeChunkWithTagsToNAND(dev, chunkId -
5815 - dev->chunkOffset, buffer, &tags) != YAFFS_OK)
5816 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
5817 - TCONT("write bad block marker to block %d")
5818 - TENDSTR), blockInNAND));
5819 + int allDone = 1;
5820
5821 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
5822 - }
5823 - }
5824 + if (tn) {
5825 + if (level > 0) {
5826 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5827 + i--) {
5828 + if (tn->internal[i]) {
5829 + if (limit && (*limit) < 0) {
5830 + allDone = 0;
5831 + } else {
5832 + allDone =
5833 + yaffs_del_worker(in,
5834 + tn->
5835 + internal
5836 + [i],
5837 + level -
5838 + 1,
5839 + (chunk_offset
5840 + <<
5841 + YAFFS_TNODES_INTERNAL_BITS)
5842 + + i,
5843 + limit);
5844 + }
5845 + if (allDone) {
5846 + yaffs_free_tnode(dev,
5847 + tn->
5848 + internal[i]);
5849 + tn->internal[i] = NULL;
5850 + }
5851 + }
5852 + }
5853 + return (allDone) ? 1 : 0;
5854 + } else if (level == 0) {
5855 + int hitLimit = 0;
5856
5857 - bi->blockState = YAFFS_BLOCK_STATE_DEAD;
5858 - bi->gcPrioritise = 0;
5859 - bi->needsRetiring = 0;
5860 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
5861 + i--) {
5862 + theChunk = yaffs_get_group_base(dev, tn, i);
5863 + if (theChunk) {
5864
5865 - dev->nRetiredBlocks++;
5866 -}
5867 + inode_chunk = (chunk_offset <<
5868 + YAFFS_TNODES_LEVEL0_BITS) + i;
5869
5870 -/*
5871 - * Functions for robustisizing TODO
5872 - *
5873 - */
5874 + foundChunk =
5875 + yaffs_find_chunk_in_group(dev,
5876 + theChunk,
5877 + &tags,
5878 + in->obj_id,
5879 + inode_chunk);
5880
5881 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
5882 - const __u8 *data,
5883 - const yaffs_ExtendedTags *tags)
5884 -{
5885 -}
5886 + if (foundChunk > 0) {
5887 + yaffs_chunk_del(dev,
5888 + foundChunk, 1,
5889 + __LINE__);
5890 + in->n_data_chunks--;
5891 + if (limit) {
5892 + *limit = *limit - 1;
5893 + if (*limit <= 0)
5894 + hitLimit = 1;
5895 + }
5896
5897 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
5898 - const yaffs_ExtendedTags *tags)
5899 -{
5900 -}
5901 + }
5902
5903 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
5904 -{
5905 - if (!bi->gcPrioritise) {
5906 - bi->gcPrioritise = 1;
5907 - dev->hasPendingPrioritisedGCs = 1;
5908 - bi->chunkErrorStrikes++;
5909 + yaffs_load_tnode_0(dev, tn, i, 0);
5910 + }
5911
5912 - if (bi->chunkErrorStrikes > 3) {
5913 - bi->needsRetiring = 1; /* Too many stikes, so retire this */
5914 - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
5915 + }
5916 + return (i < 0) ? 1 : 0;
5917
5918 }
5919 +
5920 }
5921 +
5922 + return 1;
5923 +
5924 }
5925
5926 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
5927 - int erasedOk)
5928 +#endif
5929 +
5930 +static void yaffs_soft_del_chunk(yaffs_dev_t *dev, int chunk)
5931 {
5932 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
5933 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
5934 + yaffs_block_info_t *theBlock;
5935 + unsigned block_no;
5936
5937 - yaffs_HandleChunkError(dev, bi);
5938 + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
5939
5940 - if (erasedOk) {
5941 - /* Was an actual write failure, so mark the block for retirement */
5942 - bi->needsRetiring = 1;
5943 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
5944 - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
5945 + block_no = chunk / dev->param.chunks_per_block;
5946 + theBlock = yaffs_get_block_info(dev, block_no);
5947 + if (theBlock) {
5948 + theBlock->soft_del_pages++;
5949 + dev->n_free_chunks++;
5950 + yaffs2_update_oldest_dirty_seq(dev, block_no, theBlock);
5951 }
5952 -
5953 - /* Delete the chunk */
5954 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
5955 }
5956
5957 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
5958 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out
5959 + * of the tnode.
5960 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
5961 + */
5962
5963 -/*---------------- Name handling functions ------------*/
5964 -
5965 -static __u16 yaffs_CalcNameSum(const YCHAR *name)
5966 +static int yaffs_soft_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
5967 + __u32 level, int chunk_offset)
5968 {
5969 - __u16 sum = 0;
5970 - __u16 i = 1;
5971 + int i;
5972 + int theChunk;
5973 + int allDone = 1;
5974 + yaffs_dev_t *dev = in->my_dev;
5975
5976 - const YUCHAR *bname = (const YUCHAR *) name;
5977 - if (bname) {
5978 - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
5979 + if (tn) {
5980 + if (level > 0) {
5981 +
5982 + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
5983 + i--) {
5984 + if (tn->internal[i]) {
5985 + allDone =
5986 + yaffs_soft_del_worker(in,
5987 + tn->
5988 + internal[i],
5989 + level - 1,
5990 + (chunk_offset
5991 + <<
5992 + YAFFS_TNODES_INTERNAL_BITS)
5993 + + i);
5994 + if (allDone) {
5995 + yaffs_free_tnode(dev,
5996 + tn->
5997 + internal[i]);
5998 + tn->internal[i] = NULL;
5999 + } else {
6000 + /* Hoosterman... how could this happen? */
6001 + }
6002 + }
6003 + }
6004 + return (allDone) ? 1 : 0;
6005 + } else if (level == 0) {
6006 +
6007 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
6008 + theChunk = yaffs_get_group_base(dev, tn, i);
6009 + if (theChunk) {
6010 + /* Note this does not find the real chunk, only the chunk group.
6011 + * We make an assumption that a chunk group is not larger than
6012 + * a block.
6013 + */
6014 + yaffs_soft_del_chunk(dev, theChunk);
6015 + yaffs_load_tnode_0(dev, tn, i, 0);
6016 + }
6017 +
6018 + }
6019 + return 1;
6020
6021 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
6022 - sum += yaffs_toupper(*bname) * i;
6023 -#else
6024 - sum += (*bname) * i;
6025 -#endif
6026 - i++;
6027 - bname++;
6028 }
6029 +
6030 }
6031 - return sum;
6032 +
6033 + return 1;
6034 +
6035 }
6036
6037 -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
6038 +static void yaffs_soft_del_file(yaffs_obj_t *obj)
6039 {
6040 -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
6041 - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
6042 - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
6043 - yaffs_strcpy(obj->shortName, name);
6044 - else
6045 - obj->shortName[0] = _Y('\0');
6046 -#endif
6047 - obj->sum = yaffs_CalcNameSum(name);
6048 + if (obj->deleted &&
6049 + obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) {
6050 + if (obj->n_data_chunks <= 0) {
6051 + /* Empty file with no duplicate object headers, just delete it immediately */
6052 + yaffs_free_tnode(obj->my_dev,
6053 + obj->variant.file_variant.top);
6054 + obj->variant.file_variant.top = NULL;
6055 + T(YAFFS_TRACE_TRACING,
6056 + (TSTR("yaffs: Deleting empty file %d" TENDSTR),
6057 + obj->obj_id));
6058 + yaffs_generic_obj_del(obj);
6059 + } else {
6060 + yaffs_soft_del_worker(obj,
6061 + obj->variant.file_variant.top,
6062 + obj->variant.file_variant.
6063 + top_level, 0);
6064 + obj->soft_del = 1;
6065 + }
6066 + }
6067 }
6068
6069 -/*-------------------- TNODES -------------------
6070 -
6071 - * List of spare tnodes
6072 - * The list is hooked together using the first pointer
6073 - * in the tnode.
6074 - */
6075 -
6076 -/* yaffs_CreateTnodes creates a bunch more tnodes and
6077 - * adds them to the tnode free list.
6078 - * Don't use this function directly
6079 +/* Pruning removes any part of the file structure tree that is beyond the
6080 + * bounds of the file (ie that does not point to chunks).
6081 + *
6082 + * A file should only get pruned when its size is reduced.
6083 + *
6084 + * Before pruning, the chunks must be pulled from the tree and the
6085 + * level 0 tnode entries must be zeroed out.
6086 + * Could also use this for file deletion, but that's probably better handled
6087 + * by a special case.
6088 + *
6089 + * This function is recursive. For levels > 0 the function is called again on
6090 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
6091 + * If there is no data in a subtree then it is pruned.
6092 */
6093
6094 -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
6095 +static yaffs_tnode_t *yaffs_prune_worker(yaffs_dev_t *dev, yaffs_tnode_t *tn,
6096 + __u32 level, int del0)
6097 {
6098 int i;
6099 - int tnodeSize;
6100 - yaffs_Tnode *newTnodes;
6101 - __u8 *mem;
6102 - yaffs_Tnode *curr;
6103 - yaffs_Tnode *next;
6104 - yaffs_TnodeList *tnl;
6105 + int hasData;
6106
6107 - if (nTnodes < 1)
6108 - return YAFFS_OK;
6109 + if (tn) {
6110 + hasData = 0;
6111
6112 - /* Calculate the tnode size in bytes for variable width tnode support.
6113 - * Must be a multiple of 32-bits */
6114 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6115 + if(level > 0){
6116 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
6117 + if (tn->internal[i]) {
6118 + tn->internal[i] =
6119 + yaffs_prune_worker(dev, tn->internal[i],
6120 + level - 1,
6121 + (i == 0) ? del0 : 1);
6122 + }
6123
6124 - if (tnodeSize < sizeof(yaffs_Tnode))
6125 - tnodeSize = sizeof(yaffs_Tnode);
6126 + if (tn->internal[i])
6127 + hasData++;
6128 + }
6129 + } else {
6130 + int tnode_size_u32 = dev->tnode_size/sizeof(__u32);
6131 + __u32 *map = (__u32 *)tn;
6132
6133 - /* make these things */
6134 + for(i = 0; !hasData && i < tnode_size_u32; i++){
6135 + if(map[i])
6136 + hasData++;
6137 + }
6138 + }
6139
6140 - newTnodes = YMALLOC(nTnodes * tnodeSize);
6141 - mem = (__u8 *)newTnodes;
6142 + if (hasData == 0 && del0) {
6143 + /* Free and return NULL */
6144
6145 - if (!newTnodes) {
6146 - T(YAFFS_TRACE_ERROR,
6147 - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
6148 - return YAFFS_FAIL;
6149 - }
6150 + yaffs_free_tnode(dev, tn);
6151 + tn = NULL;
6152 + }
6153
6154 - /* Hook them into the free list */
6155 -#if 0
6156 - for (i = 0; i < nTnodes - 1; i++) {
6157 - newTnodes[i].internal[0] = &newTnodes[i + 1];
6158 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6159 - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6160 -#endif
6161 }
6162
6163 - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
6164 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6165 - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6166 -#endif
6167 - dev->freeTnodes = newTnodes;
6168 -#else
6169 - /* New hookup for wide tnodes */
6170 - for (i = 0; i < nTnodes - 1; i++) {
6171 - curr = (yaffs_Tnode *) &mem[i * tnodeSize];
6172 - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
6173 - curr->internal[0] = next;
6174 - }
6175 + return tn;
6176
6177 - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
6178 - curr->internal[0] = dev->freeTnodes;
6179 - dev->freeTnodes = (yaffs_Tnode *)mem;
6180 +}
6181
6182 -#endif
6183 +static int yaffs_prune_tree(yaffs_dev_t *dev,
6184 + yaffs_file_s *file_struct)
6185 +{
6186 + int i;
6187 + int hasData;
6188 + int done = 0;
6189 + yaffs_tnode_t *tn;
6190
6191 + if (file_struct->top_level > 0) {
6192 + file_struct->top =
6193 + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
6194 +
6195 + /* Now we have a tree with all the non-zero branches NULL but the height
6196 + * is the same as it was.
6197 + * Let's see if we can trim internal tnodes to shorten the tree.
6198 + * We can do this if only the 0th element in the tnode is in use
6199 + * (ie all the non-zero are NULL)
6200 + */
6201
6202 - dev->nFreeTnodes += nTnodes;
6203 - dev->nTnodesCreated += nTnodes;
6204 + while (file_struct->top_level && !done) {
6205 + tn = file_struct->top;
6206
6207 - /* Now add this bunch of tnodes to a list for freeing up.
6208 - * NB If we can't add this to the management list it isn't fatal
6209 - * but it just means we can't free this bunch of tnodes later.
6210 - */
6211 + hasData = 0;
6212 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
6213 + if (tn->internal[i])
6214 + hasData++;
6215 + }
6216
6217 - tnl = YMALLOC(sizeof(yaffs_TnodeList));
6218 - if (!tnl) {
6219 - T(YAFFS_TRACE_ERROR,
6220 - (TSTR
6221 - ("yaffs: Could not add tnodes to management list" TENDSTR)));
6222 - return YAFFS_FAIL;
6223 - } else {
6224 - tnl->tnodes = newTnodes;
6225 - tnl->next = dev->allocatedTnodeList;
6226 - dev->allocatedTnodeList = tnl;
6227 + if (!hasData) {
6228 + file_struct->top = tn->internal[0];
6229 + file_struct->top_level--;
6230 + yaffs_free_tnode(dev, tn);
6231 + } else {
6232 + done = 1;
6233 + }
6234 + }
6235 }
6236
6237 - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
6238 -
6239 return YAFFS_OK;
6240 }
6241
6242 -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
6243 +/*-------------------- End of File Structure functions.-------------------*/
6244 +
6245
6246 -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
6247 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
6248 +static yaffs_obj_t *yaffs_alloc_empty_obj(yaffs_dev_t *dev)
6249 {
6250 - yaffs_Tnode *tn = NULL;
6251 + yaffs_obj_t *obj = yaffs_alloc_raw_obj(dev);
6252
6253 - /* If there are none left make more */
6254 - if (!dev->freeTnodes)
6255 - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
6256 -
6257 - if (dev->freeTnodes) {
6258 - tn = dev->freeTnodes;
6259 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6260 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
6261 - /* Hoosterman, this thing looks like it isn't in the list */
6262 - T(YAFFS_TRACE_ALWAYS,
6263 - (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
6264 - }
6265 -#endif
6266 - dev->freeTnodes = dev->freeTnodes->internal[0];
6267 - dev->nFreeTnodes--;
6268 - }
6269 + if (obj) {
6270 + dev->n_obj++;
6271
6272 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6273 + /* Now sweeten it up... */
6274
6275 - return tn;
6276 -}
6277 + memset(obj, 0, sizeof(yaffs_obj_t));
6278 + obj->being_created = 1;
6279
6280 -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
6281 -{
6282 - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
6283 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
6284 + obj->my_dev = dev;
6285 + obj->hdr_chunk = 0;
6286 + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
6287 + YINIT_LIST_HEAD(&(obj->hard_links));
6288 + YINIT_LIST_HEAD(&(obj->hash_link));
6289 + YINIT_LIST_HEAD(&obj->siblings);
6290
6291 - if (tnodeSize < sizeof(yaffs_Tnode))
6292 - tnodeSize = sizeof(yaffs_Tnode);
6293
6294 - if (tn)
6295 - memset(tn, 0, tnodeSize);
6296 + /* Now make the directory sane */
6297 + if (dev->root_dir) {
6298 + obj->parent = dev->root_dir;
6299 + ylist_add(&(obj->siblings), &dev->root_dir->variant.dir_variant.children);
6300 + }
6301
6302 - return tn;
6303 + /* Add it to the lost and found directory.
6304 + * NB Can't put root or lostNFound in lostNFound so
6305 + * check if lostNFound exists first
6306 + */
6307 + if (dev->lost_n_found)
6308 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
6309 +
6310 + obj->being_created = 0;
6311 + }
6312 +
6313 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
6314 +
6315 + return obj;
6316 }
6317
6318 -/* FreeTnode frees up a tnode and puts it back on the free list */
6319 -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
6320 +static yaffs_obj_t *yaffs_create_fake_dir(yaffs_dev_t *dev, int number,
6321 + __u32 mode)
6322 {
6323 - if (tn) {
6324 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
6325 - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
6326 - /* Hoosterman, this thing looks like it is already in the list */
6327 - T(YAFFS_TRACE_ALWAYS,
6328 - (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
6329 - }
6330 - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
6331 -#endif
6332 - tn->internal[0] = dev->freeTnodes;
6333 - dev->freeTnodes = tn;
6334 - dev->nFreeTnodes++;
6335 +
6336 + yaffs_obj_t *obj =
6337 + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
6338 + if (obj) {
6339 + obj->fake = 1; /* it is fake so it might have no NAND presence... */
6340 + obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */
6341 + obj->unlink_allowed = 0; /* ... or unlink it */
6342 + obj->deleted = 0;
6343 + obj->unlinked = 0;
6344 + obj->yst_mode = mode;
6345 + obj->my_dev = dev;
6346 + obj->hdr_chunk = 0; /* Not a valid chunk. */
6347 + }
6348 +
6349 + return obj;
6350 +
6351 +}
6352 +
6353 +static void yaffs_unhash_obj(yaffs_obj_t *obj)
6354 +{
6355 + int bucket;
6356 + yaffs_dev_t *dev = obj->my_dev;
6357 +
6358 + /* If it is still linked into the bucket list, free from the list */
6359 + if (!ylist_empty(&obj->hash_link)) {
6360 + ylist_del_init(&obj->hash_link);
6361 + bucket = yaffs_hash_fn(obj->obj_id);
6362 + dev->obj_bucket[bucket].count--;
6363 }
6364 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
6365 }
6366
6367 -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
6368 +/* FreeObject frees up a Object and puts it back on the free list */
6369 +static void yaffs_free_obj(yaffs_obj_t *obj)
6370 {
6371 - /* Free the list of allocated tnodes */
6372 - yaffs_TnodeList *tmp;
6373 + yaffs_dev_t *dev = obj->my_dev;
6374 +
6375 + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->my_inode));
6376
6377 - while (dev->allocatedTnodeList) {
6378 - tmp = dev->allocatedTnodeList->next;
6379 + if (!obj)
6380 + YBUG();
6381 + if (obj->parent)
6382 + YBUG();
6383 + if (!ylist_empty(&obj->siblings))
6384 + YBUG();
6385
6386 - YFREE(dev->allocatedTnodeList->tnodes);
6387 - YFREE(dev->allocatedTnodeList);
6388 - dev->allocatedTnodeList = tmp;
6389
6390 + if (obj->my_inode) {
6391 + /* We're still hooked up to a cached inode.
6392 + * Don't delete now, but mark for later deletion
6393 + */
6394 + obj->defered_free = 1;
6395 + return;
6396 }
6397
6398 - dev->freeTnodes = NULL;
6399 - dev->nFreeTnodes = 0;
6400 -}
6401 + yaffs_unhash_obj(obj);
6402
6403 -static void yaffs_InitialiseTnodes(yaffs_Device *dev)
6404 -{
6405 - dev->allocatedTnodeList = NULL;
6406 - dev->freeTnodes = NULL;
6407 - dev->nFreeTnodes = 0;
6408 - dev->nTnodesCreated = 0;
6409 + yaffs_free_raw_obj(dev,obj);
6410 + dev->n_obj--;
6411 + dev->checkpoint_blocks_required = 0; /* force recalculation*/
6412 }
6413
6414
6415 -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
6416 - unsigned val)
6417 +void yaffs_handle_defered_free(yaffs_obj_t *obj)
6418 {
6419 - __u32 *map = (__u32 *)tn;
6420 - __u32 bitInMap;
6421 - __u32 bitInWord;
6422 - __u32 wordInMap;
6423 - __u32 mask;
6424 -
6425 - pos &= YAFFS_TNODES_LEVEL0_MASK;
6426 - val >>= dev->chunkGroupBits;
6427 + if (obj->defered_free)
6428 + yaffs_free_obj(obj);
6429 +}
6430
6431 - bitInMap = pos * dev->tnodeWidth;
6432 - wordInMap = bitInMap / 32;
6433 - bitInWord = bitInMap & (32 - 1);
6434 +static void yaffs_init_tnodes_and_objs(yaffs_dev_t *dev)
6435 +{
6436 + int i;
6437
6438 - mask = dev->tnodeMask << bitInWord;
6439 + dev->n_obj = 0;
6440 + dev->n_tnodes = 0;
6441
6442 - map[wordInMap] &= ~mask;
6443 - map[wordInMap] |= (mask & (val << bitInWord));
6444 + yaffs_init_raw_tnodes_and_objs(dev);
6445
6446 - if (dev->tnodeWidth > (32 - bitInWord)) {
6447 - bitInWord = (32 - bitInWord);
6448 - wordInMap++;;
6449 - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
6450 - map[wordInMap] &= ~mask;
6451 - map[wordInMap] |= (mask & (val >> bitInWord));
6452 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6453 + YINIT_LIST_HEAD(&dev->obj_bucket[i].list);
6454 + dev->obj_bucket[i].count = 0;
6455 }
6456 }
6457
6458 -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
6459 - unsigned pos)
6460 +static int yaffs_find_nice_bucket(yaffs_dev_t *dev)
6461 {
6462 - __u32 *map = (__u32 *)tn;
6463 - __u32 bitInMap;
6464 - __u32 bitInWord;
6465 - __u32 wordInMap;
6466 - __u32 val;
6467 + int i;
6468 + int l = 999;
6469 + int lowest = 999999;
6470
6471 - pos &= YAFFS_TNODES_LEVEL0_MASK;
6472
6473 - bitInMap = pos * dev->tnodeWidth;
6474 - wordInMap = bitInMap / 32;
6475 - bitInWord = bitInMap & (32 - 1);
6476 + /* Search for the shortest list or one that
6477 + * isn't too long.
6478 + */
6479
6480 - val = map[wordInMap] >> bitInWord;
6481 + for (i = 0; i < 10 && lowest > 4; i++) {
6482 + dev->bucket_finder++;
6483 + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
6484 + if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
6485 + lowest = dev->obj_bucket[dev->bucket_finder].count;
6486 + l = dev->bucket_finder;
6487 + }
6488
6489 - if (dev->tnodeWidth > (32 - bitInWord)) {
6490 - bitInWord = (32 - bitInWord);
6491 - wordInMap++;;
6492 - val |= (map[wordInMap] << bitInWord);
6493 }
6494
6495 - val &= dev->tnodeMask;
6496 - val <<= dev->chunkGroupBits;
6497 -
6498 - return val;
6499 + return l;
6500 }
6501
6502 -/* ------------------- End of individual tnode manipulation -----------------*/
6503 -
6504 -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
6505 - * The look up tree is represented by the top tnode and the number of topLevel
6506 - * in the tree. 0 means only the level 0 tnode is in the tree.
6507 - */
6508 -
6509 -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
6510 -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
6511 - yaffs_FileStructure *fStruct,
6512 - __u32 chunkId)
6513 +static int yaffs_new_obj_id(yaffs_dev_t *dev)
6514 {
6515 - yaffs_Tnode *tn = fStruct->top;
6516 - __u32 i;
6517 - int requiredTallness;
6518 - int level = fStruct->topLevel;
6519 -
6520 - /* Check sane level and chunk Id */
6521 - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
6522 - return NULL;
6523 + int bucket = yaffs_find_nice_bucket(dev);
6524
6525 - if (chunkId > YAFFS_MAX_CHUNK_ID)
6526 - return NULL;
6527 + /* Now find an object value that has not already been taken
6528 + * by scanning the list.
6529 + */
6530
6531 - /* First check we're tall enough (ie enough topLevel) */
6532 + int found = 0;
6533 + struct ylist_head *i;
6534
6535 - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
6536 - requiredTallness = 0;
6537 - while (i) {
6538 - i >>= YAFFS_TNODES_INTERNAL_BITS;
6539 - requiredTallness++;
6540 - }
6541 + __u32 n = (__u32) bucket;
6542
6543 - if (requiredTallness > fStruct->topLevel)
6544 - return NULL; /* Not tall enough, so we can't find it */
6545 + /* yaffs_check_obj_hash_sane(); */
6546
6547 - /* Traverse down to level 0 */
6548 - while (level > 0 && tn) {
6549 - tn = tn->internal[(chunkId >>
6550 - (YAFFS_TNODES_LEVEL0_BITS +
6551 - (level - 1) *
6552 - YAFFS_TNODES_INTERNAL_BITS)) &
6553 - YAFFS_TNODES_INTERNAL_MASK];
6554 - level--;
6555 + while (!found) {
6556 + found = 1;
6557 + n += YAFFS_NOBJECT_BUCKETS;
6558 + if (1 || dev->obj_bucket[bucket].count > 0) {
6559 + ylist_for_each(i, &dev->obj_bucket[bucket].list) {
6560 + /* If there is already one in the list */
6561 + if (i && ylist_entry(i, yaffs_obj_t,
6562 + hash_link)->obj_id == n) {
6563 + found = 0;
6564 + }
6565 + }
6566 + }
6567 }
6568
6569 - return tn;
6570 + return n;
6571 }
6572
6573 -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
6574 - * This happens in two steps:
6575 - * 1. If the tree isn't tall enough, then make it taller.
6576 - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
6577 - *
6578 - * Used when modifying the tree.
6579 - *
6580 - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
6581 - * be plugged into the ttree.
6582 - */
6583 -
6584 -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
6585 - yaffs_FileStructure *fStruct,
6586 - __u32 chunkId,
6587 - yaffs_Tnode *passedTn)
6588 +static void yaffs_hash_obj(yaffs_obj_t *in)
6589 {
6590 - int requiredTallness;
6591 - int i;
6592 - int l;
6593 - yaffs_Tnode *tn;
6594 -
6595 - __u32 x;
6596 + int bucket = yaffs_hash_fn(in->obj_id);
6597 + yaffs_dev_t *dev = in->my_dev;
6598
6599 + ylist_add(&in->hash_link, &dev->obj_bucket[bucket].list);
6600 + dev->obj_bucket[bucket].count++;
6601 +}
6602
6603 - /* Check sane level and page Id */
6604 - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
6605 - return NULL;
6606 +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number)
6607 +{
6608 + int bucket = yaffs_hash_fn(number);
6609 + struct ylist_head *i;
6610 + yaffs_obj_t *in;
6611
6612 - if (chunkId > YAFFS_MAX_CHUNK_ID)
6613 - return NULL;
6614 + ylist_for_each(i, &dev->obj_bucket[bucket].list) {
6615 + /* Look if it is in the list */
6616 + if (i) {
6617 + in = ylist_entry(i, yaffs_obj_t, hash_link);
6618 + if (in->obj_id == number) {
6619
6620 - /* First check we're tall enough (ie enough topLevel) */
6621 + /* Don't tell the VFS about this one if it is defered free */
6622 + if (in->defered_free)
6623 + return NULL;
6624
6625 - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
6626 - requiredTallness = 0;
6627 - while (x) {
6628 - x >>= YAFFS_TNODES_INTERNAL_BITS;
6629 - requiredTallness++;
6630 + return in;
6631 + }
6632 + }
6633 }
6634
6635 + return NULL;
6636 +}
6637
6638 - if (requiredTallness > fStruct->topLevel) {
6639 - /* Not tall enough, gotta make the tree taller */
6640 - for (i = fStruct->topLevel; i < requiredTallness; i++) {
6641 +yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
6642 + yaffs_obj_type type)
6643 +{
6644 + yaffs_obj_t *theObject=NULL;
6645 + yaffs_tnode_t *tn = NULL;
6646
6647 - tn = yaffs_GetTnode(dev);
6648 + if (number < 0)
6649 + number = yaffs_new_obj_id(dev);
6650
6651 - if (tn) {
6652 - tn->internal[0] = fStruct->top;
6653 - fStruct->top = tn;
6654 - } else {
6655 - T(YAFFS_TRACE_ERROR,
6656 - (TSTR("yaffs: no more tnodes" TENDSTR)));
6657 - }
6658 - }
6659 + if (type == YAFFS_OBJECT_TYPE_FILE) {
6660 + tn = yaffs_get_tnode(dev);
6661 + if (!tn)
6662 + return NULL;
6663 + }
6664
6665 - fStruct->topLevel = requiredTallness;
6666 + theObject = yaffs_alloc_empty_obj(dev);
6667 + if (!theObject){
6668 + if(tn)
6669 + yaffs_free_tnode(dev,tn);
6670 + return NULL;
6671 }
6672
6673 - /* Traverse down to level 0, adding anything we need */
6674
6675 - l = fStruct->topLevel;
6676 - tn = fStruct->top;
6677 + if (theObject) {
6678 + theObject->fake = 0;
6679 + theObject->rename_allowed = 1;
6680 + theObject->unlink_allowed = 1;
6681 + theObject->obj_id = number;
6682 + yaffs_hash_obj(theObject);
6683 + theObject->variant_type = type;
6684 +#ifdef CONFIG_YAFFS_WINCE
6685 + yfsd_win_file_time_now(theObject->win_atime);
6686 + theObject->win_ctime[0] = theObject->win_mtime[0] =
6687 + theObject->win_atime[0];
6688 + theObject->win_ctime[1] = theObject->win_mtime[1] =
6689 + theObject->win_atime[1];
6690 +
6691 +#else
6692
6693 - if (l > 0) {
6694 - while (l > 0 && tn) {
6695 - x = (chunkId >>
6696 - (YAFFS_TNODES_LEVEL0_BITS +
6697 - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
6698 - YAFFS_TNODES_INTERNAL_MASK;
6699 + theObject->yst_atime = theObject->yst_mtime =
6700 + theObject->yst_ctime = Y_CURRENT_TIME;
6701 +#endif
6702 + switch (type) {
6703 + case YAFFS_OBJECT_TYPE_FILE:
6704 + theObject->variant.file_variant.file_size = 0;
6705 + theObject->variant.file_variant.scanned_size = 0;
6706 + theObject->variant.file_variant.shrink_size = 0xFFFFFFFF; /* max __u32 */
6707 + theObject->variant.file_variant.top_level = 0;
6708 + theObject->variant.file_variant.top = tn;
6709 + break;
6710 + case YAFFS_OBJECT_TYPE_DIRECTORY:
6711 + YINIT_LIST_HEAD(&theObject->variant.dir_variant.
6712 + children);
6713 + YINIT_LIST_HEAD(&theObject->variant.dir_variant.
6714 + dirty);
6715 + break;
6716 + case YAFFS_OBJECT_TYPE_SYMLINK:
6717 + case YAFFS_OBJECT_TYPE_HARDLINK:
6718 + case YAFFS_OBJECT_TYPE_SPECIAL:
6719 + /* No action required */
6720 + break;
6721 + case YAFFS_OBJECT_TYPE_UNKNOWN:
6722 + /* todo this should not happen */
6723 + break;
6724 + }
6725 + }
6726
6727 + return theObject;
6728 +}
6729
6730 - if ((l > 1) && !tn->internal[x]) {
6731 - /* Add missing non-level-zero tnode */
6732 - tn->internal[x] = yaffs_GetTnode(dev);
6733 +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
6734 + int number,
6735 + yaffs_obj_type type)
6736 +{
6737 + yaffs_obj_t *theObject = NULL;
6738
6739 - } else if (l == 1) {
6740 - /* Looking from level 1 at level 0 */
6741 - if (passedTn) {
6742 - /* If we already have one, then release it.*/
6743 - if (tn->internal[x])
6744 - yaffs_FreeTnode(dev, tn->internal[x]);
6745 - tn->internal[x] = passedTn;
6746 + if (number > 0)
6747 + theObject = yaffs_find_by_number(dev, number);
6748
6749 - } else if (!tn->internal[x]) {
6750 - /* Don't have one, none passed in */
6751 - tn->internal[x] = yaffs_GetTnode(dev);
6752 - }
6753 - }
6754 + if (!theObject)
6755 + theObject = yaffs_new_obj(dev, number, type);
6756
6757 - tn = tn->internal[x];
6758 - l--;
6759 - }
6760 - } else {
6761 - /* top is level 0 */
6762 - if (passedTn) {
6763 - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
6764 - yaffs_FreeTnode(dev, passedTn);
6765 - }
6766 - }
6767 + return theObject;
6768
6769 - return tn;
6770 }
6771
6772 -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
6773 - yaffs_ExtendedTags *tags, int objectId,
6774 - int chunkInInode)
6775 +
6776 +YCHAR *yaffs_clone_str(const YCHAR *str)
6777 {
6778 - int j;
6779 + YCHAR *newStr = NULL;
6780 + int len;
6781
6782 - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
6783 - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
6784 - theChunk % dev->nChunksPerBlock)) {
6785 - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
6786 - tags);
6787 - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
6788 - /* found it; */
6789 - return theChunk;
6790 - }
6791 - }
6792 - theChunk++;
6793 + if (!str)
6794 + str = _Y("");
6795 +
6796 + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
6797 + newStr = YMALLOC((len + 1) * sizeof(YCHAR));
6798 + if (newStr){
6799 + yaffs_strncpy(newStr, str,len);
6800 + newStr[len] = 0;
6801 }
6802 - return -1;
6803 -}
6804 + return newStr;
6805
6806 +}
6807
6808 -/* DeleteWorker scans backwards through the tnode tree and deletes all the
6809 - * chunks and tnodes in the file
6810 - * Returns 1 if the tree was deleted.
6811 - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
6812 +/*
6813 + * Mknod (create) a new object.
6814 + * equiv_obj only has meaning for a hard link;
6815 + * aliasString only has meaning for a symlink.
6816 + * rdev only has meaning for devices (a subset of special objects)
6817 */
6818
6819 -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
6820 - int chunkOffset, int *limit)
6821 +static yaffs_obj_t *yaffs_create_obj(yaffs_obj_type type,
6822 + yaffs_obj_t *parent,
6823 + const YCHAR *name,
6824 + __u32 mode,
6825 + __u32 uid,
6826 + __u32 gid,
6827 + yaffs_obj_t *equiv_obj,
6828 + const YCHAR *aliasString, __u32 rdev)
6829 {
6830 - int i;
6831 - int chunkInInode;
6832 - int theChunk;
6833 - yaffs_ExtendedTags tags;
6834 - int foundChunk;
6835 - yaffs_Device *dev = in->myDev;
6836 -
6837 - int allDone = 1;
6838 -
6839 - if (tn) {
6840 - if (level > 0) {
6841 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
6842 - i--) {
6843 - if (tn->internal[i]) {
6844 - if (limit && (*limit) < 0) {
6845 - allDone = 0;
6846 - } else {
6847 - allDone =
6848 - yaffs_DeleteWorker(in,
6849 - tn->
6850 - internal
6851 - [i],
6852 - level -
6853 - 1,
6854 - (chunkOffset
6855 - <<
6856 - YAFFS_TNODES_INTERNAL_BITS)
6857 - + i,
6858 - limit);
6859 - }
6860 - if (allDone) {
6861 - yaffs_FreeTnode(dev,
6862 - tn->
6863 - internal[i]);
6864 - tn->internal[i] = NULL;
6865 - }
6866 - }
6867 - }
6868 - return (allDone) ? 1 : 0;
6869 - } else if (level == 0) {
6870 - int hitLimit = 0;
6871 -
6872 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
6873 - i--) {
6874 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
6875 - if (theChunk) {
6876 -
6877 - chunkInInode = (chunkOffset <<
6878 - YAFFS_TNODES_LEVEL0_BITS) + i;
6879 -
6880 - foundChunk =
6881 - yaffs_FindChunkInGroup(dev,
6882 - theChunk,
6883 - &tags,
6884 - in->objectId,
6885 - chunkInInode);
6886 -
6887 - if (foundChunk > 0) {
6888 - yaffs_DeleteChunk(dev,
6889 - foundChunk, 1,
6890 - __LINE__);
6891 - in->nDataChunks--;
6892 - if (limit) {
6893 - *limit = *limit - 1;
6894 - if (*limit <= 0)
6895 - hitLimit = 1;
6896 - }
6897 -
6898 - }
6899 -
6900 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
6901 - }
6902 -
6903 - }
6904 - return (i < 0) ? 1 : 0;
6905 -
6906 - }
6907 -
6908 - }
6909 -
6910 - return 1;
6911 -
6912 -}
6913 -
6914 -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
6915 -{
6916 - yaffs_BlockInfo *theBlock;
6917 -
6918 - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
6919 -
6920 - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
6921 - if (theBlock) {
6922 - theBlock->softDeletions++;
6923 - dev->nFreeChunks++;
6924 - }
6925 -}
6926 -
6927 -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
6928 - * All soft deleting does is increment the block's softdelete count and pulls the chunk out
6929 - * of the tnode.
6930 - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
6931 - */
6932 -
6933 -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
6934 - __u32 level, int chunkOffset)
6935 -{
6936 - int i;
6937 - int theChunk;
6938 - int allDone = 1;
6939 - yaffs_Device *dev = in->myDev;
6940 -
6941 - if (tn) {
6942 - if (level > 0) {
6943 -
6944 - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
6945 - i--) {
6946 - if (tn->internal[i]) {
6947 - allDone =
6948 - yaffs_SoftDeleteWorker(in,
6949 - tn->
6950 - internal[i],
6951 - level - 1,
6952 - (chunkOffset
6953 - <<
6954 - YAFFS_TNODES_INTERNAL_BITS)
6955 - + i);
6956 - if (allDone) {
6957 - yaffs_FreeTnode(dev,
6958 - tn->
6959 - internal[i]);
6960 - tn->internal[i] = NULL;
6961 - } else {
6962 - /* Hoosterman... how could this happen? */
6963 - }
6964 - }
6965 - }
6966 - return (allDone) ? 1 : 0;
6967 - } else if (level == 0) {
6968 -
6969 - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
6970 - theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
6971 - if (theChunk) {
6972 - /* Note this does not find the real chunk, only the chunk group.
6973 - * We make an assumption that a chunk group is not larger than
6974 - * a block.
6975 - */
6976 - yaffs_SoftDeleteChunk(dev, theChunk);
6977 - yaffs_PutLevel0Tnode(dev, tn, i, 0);
6978 - }
6979 -
6980 - }
6981 - return 1;
6982 -
6983 - }
6984 -
6985 - }
6986 -
6987 - return 1;
6988 -
6989 -}
6990 -
6991 -static void yaffs_SoftDeleteFile(yaffs_Object *obj)
6992 -{
6993 - if (obj->deleted &&
6994 - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
6995 - if (obj->nDataChunks <= 0) {
6996 - /* Empty file with no duplicate object headers, just delete it immediately */
6997 - yaffs_FreeTnode(obj->myDev,
6998 - obj->variant.fileVariant.top);
6999 - obj->variant.fileVariant.top = NULL;
7000 - T(YAFFS_TRACE_TRACING,
7001 - (TSTR("yaffs: Deleting empty file %d" TENDSTR),
7002 - obj->objectId));
7003 - yaffs_DoGenericObjectDeletion(obj);
7004 - } else {
7005 - yaffs_SoftDeleteWorker(obj,
7006 - obj->variant.fileVariant.top,
7007 - obj->variant.fileVariant.
7008 - topLevel, 0);
7009 - obj->softDeleted = 1;
7010 - }
7011 - }
7012 -}
7013 -
7014 -/* Pruning removes any part of the file structure tree that is beyond the
7015 - * bounds of the file (ie that does not point to chunks).
7016 - *
7017 - * A file should only get pruned when its size is reduced.
7018 - *
7019 - * Before pruning, the chunks must be pulled from the tree and the
7020 - * level 0 tnode entries must be zeroed out.
7021 - * Could also use this for file deletion, but that's probably better handled
7022 - * by a special case.
7023 - */
7024 -
7025 -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
7026 - __u32 level, int del0)
7027 -{
7028 - int i;
7029 - int hasData;
7030 -
7031 - if (tn) {
7032 - hasData = 0;
7033 -
7034 - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
7035 - if (tn->internal[i] && level > 0) {
7036 - tn->internal[i] =
7037 - yaffs_PruneWorker(dev, tn->internal[i],
7038 - level - 1,
7039 - (i == 0) ? del0 : 1);
7040 - }
7041 -
7042 - if (tn->internal[i])
7043 - hasData++;
7044 - }
7045 -
7046 - if (hasData == 0 && del0) {
7047 - /* Free and return NULL */
7048 -
7049 - yaffs_FreeTnode(dev, tn);
7050 - tn = NULL;
7051 - }
7052 -
7053 - }
7054 -
7055 - return tn;
7056 -
7057 -}
7058 -
7059 -static int yaffs_PruneFileStructure(yaffs_Device *dev,
7060 - yaffs_FileStructure *fStruct)
7061 -{
7062 - int i;
7063 - int hasData;
7064 - int done = 0;
7065 - yaffs_Tnode *tn;
7066 -
7067 - if (fStruct->topLevel > 0) {
7068 - fStruct->top =
7069 - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
7070 -
7071 - /* Now we have a tree with all the non-zero branches NULL but the height
7072 - * is the same as it was.
7073 - * Let's see if we can trim internal tnodes to shorten the tree.
7074 - * We can do this if only the 0th element in the tnode is in use
7075 - * (ie all the non-zero are NULL)
7076 - */
7077 -
7078 - while (fStruct->topLevel && !done) {
7079 - tn = fStruct->top;
7080 -
7081 - hasData = 0;
7082 - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
7083 - if (tn->internal[i])
7084 - hasData++;
7085 - }
7086 -
7087 - if (!hasData) {
7088 - fStruct->top = tn->internal[0];
7089 - fStruct->topLevel--;
7090 - yaffs_FreeTnode(dev, tn);
7091 - } else {
7092 - done = 1;
7093 - }
7094 - }
7095 - }
7096 -
7097 - return YAFFS_OK;
7098 -}
7099 -
7100 -/*-------------------- End of File Structure functions.-------------------*/
7101 -
7102 -/* yaffs_CreateFreeObjects creates a bunch more objects and
7103 - * adds them to the object free list.
7104 - */
7105 -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
7106 -{
7107 - int i;
7108 - yaffs_Object *newObjects;
7109 - yaffs_ObjectList *list;
7110 -
7111 - if (nObjects < 1)
7112 - return YAFFS_OK;
7113 -
7114 - /* make these things */
7115 - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
7116 - list = YMALLOC(sizeof(yaffs_ObjectList));
7117 -
7118 - if (!newObjects || !list) {
7119 - if (newObjects)
7120 - YFREE(newObjects);
7121 - if (list)
7122 - YFREE(list);
7123 - T(YAFFS_TRACE_ALLOCATE,
7124 - (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
7125 - return YAFFS_FAIL;
7126 - }
7127 -
7128 - /* Hook them into the free list */
7129 - for (i = 0; i < nObjects - 1; i++) {
7130 - newObjects[i].siblings.next =
7131 - (struct ylist_head *)(&newObjects[i + 1]);
7132 - }
7133 -
7134 - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
7135 - dev->freeObjects = newObjects;
7136 - dev->nFreeObjects += nObjects;
7137 - dev->nObjectsCreated += nObjects;
7138 -
7139 - /* Now add this bunch of Objects to a list for freeing up. */
7140 -
7141 - list->objects = newObjects;
7142 - list->next = dev->allocatedObjectList;
7143 - dev->allocatedObjectList = list;
7144 -
7145 - return YAFFS_OK;
7146 -}
7147 -
7148 -
7149 -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
7150 -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
7151 -{
7152 - yaffs_Object *tn = NULL;
7153 -
7154 -#ifdef VALGRIND_TEST
7155 - tn = YMALLOC(sizeof(yaffs_Object));
7156 -#else
7157 - /* If there are none left make more */
7158 - if (!dev->freeObjects)
7159 - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
7160 -
7161 - if (dev->freeObjects) {
7162 - tn = dev->freeObjects;
7163 - dev->freeObjects =
7164 - (yaffs_Object *) (dev->freeObjects->siblings.next);
7165 - dev->nFreeObjects--;
7166 - }
7167 -#endif
7168 - if (tn) {
7169 - /* Now sweeten it up... */
7170 -
7171 - memset(tn, 0, sizeof(yaffs_Object));
7172 - tn->beingCreated = 1;
7173 -
7174 - tn->myDev = dev;
7175 - tn->hdrChunk = 0;
7176 - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
7177 - YINIT_LIST_HEAD(&(tn->hardLinks));
7178 - YINIT_LIST_HEAD(&(tn->hashLink));
7179 - YINIT_LIST_HEAD(&tn->siblings);
7180 -
7181 -
7182 - /* Now make the directory sane */
7183 - if (dev->rootDir) {
7184 - tn->parent = dev->rootDir;
7185 - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
7186 - }
7187 -
7188 - /* Add it to the lost and found directory.
7189 - * NB Can't put root or lostNFound in lostNFound so
7190 - * check if lostNFound exists first
7191 - */
7192 - if (dev->lostNFoundDir)
7193 - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
7194 -
7195 - tn->beingCreated = 0;
7196 - }
7197 -
7198 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7199 -
7200 - return tn;
7201 -}
7202 -
7203 -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
7204 - __u32 mode)
7205 -{
7206 -
7207 - yaffs_Object *obj =
7208 - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
7209 - if (obj) {
7210 - obj->fake = 1; /* it is fake so it might have no NAND presence... */
7211 - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
7212 - obj->unlinkAllowed = 0; /* ... or unlink it */
7213 - obj->deleted = 0;
7214 - obj->unlinked = 0;
7215 - obj->yst_mode = mode;
7216 - obj->myDev = dev;
7217 - obj->hdrChunk = 0; /* Not a valid chunk. */
7218 - }
7219 -
7220 - return obj;
7221 -
7222 -}
7223 -
7224 -static void yaffs_UnhashObject(yaffs_Object *tn)
7225 -{
7226 - int bucket;
7227 - yaffs_Device *dev = tn->myDev;
7228 -
7229 - /* If it is still linked into the bucket list, free from the list */
7230 - if (!ylist_empty(&tn->hashLink)) {
7231 - ylist_del_init(&tn->hashLink);
7232 - bucket = yaffs_HashFunction(tn->objectId);
7233 - dev->objectBucket[bucket].count--;
7234 - }
7235 -}
7236 -
7237 -/* FreeObject frees up a Object and puts it back on the free list */
7238 -static void yaffs_FreeObject(yaffs_Object *tn)
7239 -{
7240 - yaffs_Device *dev = tn->myDev;
7241 -
7242 -#ifdef __KERNEL__
7243 - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
7244 -#endif
7245 -
7246 - if (tn->parent)
7247 - YBUG();
7248 - if (!ylist_empty(&tn->siblings))
7249 - YBUG();
7250 -
7251 -
7252 -#ifdef __KERNEL__
7253 - if (tn->myInode) {
7254 - /* We're still hooked up to a cached inode.
7255 - * Don't delete now, but mark for later deletion
7256 - */
7257 - tn->deferedFree = 1;
7258 - return;
7259 - }
7260 -#endif
7261 -
7262 - yaffs_UnhashObject(tn);
7263 -
7264 -#ifdef VALGRIND_TEST
7265 - YFREE(tn);
7266 -#else
7267 - /* Link into the free list. */
7268 - tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
7269 - dev->freeObjects = tn;
7270 - dev->nFreeObjects++;
7271 -#endif
7272 - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
7273 -}
7274 -
7275 -#ifdef __KERNEL__
7276 -
7277 -void yaffs_HandleDeferedFree(yaffs_Object *obj)
7278 -{
7279 - if (obj->deferedFree)
7280 - yaffs_FreeObject(obj);
7281 -}
7282 -
7283 -#endif
7284 -
7285 -static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
7286 -{
7287 - /* Free the list of allocated Objects */
7288 -
7289 - yaffs_ObjectList *tmp;
7290 -
7291 - while (dev->allocatedObjectList) {
7292 - tmp = dev->allocatedObjectList->next;
7293 - YFREE(dev->allocatedObjectList->objects);
7294 - YFREE(dev->allocatedObjectList);
7295 -
7296 - dev->allocatedObjectList = tmp;
7297 - }
7298 -
7299 - dev->freeObjects = NULL;
7300 - dev->nFreeObjects = 0;
7301 -}
7302 -
7303 -static void yaffs_InitialiseObjects(yaffs_Device *dev)
7304 -{
7305 - int i;
7306 -
7307 - dev->allocatedObjectList = NULL;
7308 - dev->freeObjects = NULL;
7309 - dev->nFreeObjects = 0;
7310 -
7311 - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
7312 - YINIT_LIST_HEAD(&dev->objectBucket[i].list);
7313 - dev->objectBucket[i].count = 0;
7314 - }
7315 -}
7316 -
7317 -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
7318 -{
7319 - static int x;
7320 - int i;
7321 - int l = 999;
7322 - int lowest = 999999;
7323 -
7324 - /* First let's see if we can find one that's empty. */
7325 -
7326 - for (i = 0; i < 10 && lowest > 0; i++) {
7327 - x++;
7328 - x %= YAFFS_NOBJECT_BUCKETS;
7329 - if (dev->objectBucket[x].count < lowest) {
7330 - lowest = dev->objectBucket[x].count;
7331 - l = x;
7332 - }
7333 -
7334 - }
7335 -
7336 - /* If we didn't find an empty list, then try
7337 - * looking a bit further for a short one
7338 - */
7339 -
7340 - for (i = 0; i < 10 && lowest > 3; i++) {
7341 - x++;
7342 - x %= YAFFS_NOBJECT_BUCKETS;
7343 - if (dev->objectBucket[x].count < lowest) {
7344 - lowest = dev->objectBucket[x].count;
7345 - l = x;
7346 - }
7347 -
7348 - }
7349 -
7350 - return l;
7351 -}
7352 -
7353 -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
7354 -{
7355 - int bucket = yaffs_FindNiceObjectBucket(dev);
7356 -
7357 - /* Now find an object value that has not already been taken
7358 - * by scanning the list.
7359 - */
7360 -
7361 - int found = 0;
7362 - struct ylist_head *i;
7363 -
7364 - __u32 n = (__u32) bucket;
7365 -
7366 - /* yaffs_CheckObjectHashSanity(); */
7367 -
7368 - while (!found) {
7369 - found = 1;
7370 - n += YAFFS_NOBJECT_BUCKETS;
7371 - if (1 || dev->objectBucket[bucket].count > 0) {
7372 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
7373 - /* If there is already one in the list */
7374 - if (i && ylist_entry(i, yaffs_Object,
7375 - hashLink)->objectId == n) {
7376 - found = 0;
7377 - }
7378 - }
7379 - }
7380 - }
7381 -
7382 - return n;
7383 -}
7384 -
7385 -static void yaffs_HashObject(yaffs_Object *in)
7386 -{
7387 - int bucket = yaffs_HashFunction(in->objectId);
7388 - yaffs_Device *dev = in->myDev;
7389 -
7390 - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
7391 - dev->objectBucket[bucket].count++;
7392 -}
7393 -
7394 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
7395 -{
7396 - int bucket = yaffs_HashFunction(number);
7397 - struct ylist_head *i;
7398 - yaffs_Object *in;
7399 -
7400 - ylist_for_each(i, &dev->objectBucket[bucket].list) {
7401 - /* Look if it is in the list */
7402 - if (i) {
7403 - in = ylist_entry(i, yaffs_Object, hashLink);
7404 - if (in->objectId == number) {
7405 -#ifdef __KERNEL__
7406 - /* Don't tell the VFS about this one if it is defered free */
7407 - if (in->deferedFree)
7408 - return NULL;
7409 -#endif
7410 -
7411 - return in;
7412 - }
7413 - }
7414 - }
7415 -
7416 - return NULL;
7417 -}
7418 -
7419 -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
7420 - yaffs_ObjectType type)
7421 -{
7422 - yaffs_Object *theObject;
7423 - yaffs_Tnode *tn = NULL;
7424 -
7425 - if (number < 0)
7426 - number = yaffs_CreateNewObjectNumber(dev);
7427 -
7428 - theObject = yaffs_AllocateEmptyObject(dev);
7429 - if (!theObject)
7430 - return NULL;
7431 -
7432 - if (type == YAFFS_OBJECT_TYPE_FILE) {
7433 - tn = yaffs_GetTnode(dev);
7434 - if (!tn) {
7435 - yaffs_FreeObject(theObject);
7436 - return NULL;
7437 - }
7438 - }
7439 -
7440 - if (theObject) {
7441 - theObject->fake = 0;
7442 - theObject->renameAllowed = 1;
7443 - theObject->unlinkAllowed = 1;
7444 - theObject->objectId = number;
7445 - yaffs_HashObject(theObject);
7446 - theObject->variantType = type;
7447 -#ifdef CONFIG_YAFFS_WINCE
7448 - yfsd_WinFileTimeNow(theObject->win_atime);
7449 - theObject->win_ctime[0] = theObject->win_mtime[0] =
7450 - theObject->win_atime[0];
7451 - theObject->win_ctime[1] = theObject->win_mtime[1] =
7452 - theObject->win_atime[1];
7453 -
7454 -#else
7455 -
7456 - theObject->yst_atime = theObject->yst_mtime =
7457 - theObject->yst_ctime = Y_CURRENT_TIME;
7458 -#endif
7459 - switch (type) {
7460 - case YAFFS_OBJECT_TYPE_FILE:
7461 - theObject->variant.fileVariant.fileSize = 0;
7462 - theObject->variant.fileVariant.scannedFileSize = 0;
7463 - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
7464 - theObject->variant.fileVariant.topLevel = 0;
7465 - theObject->variant.fileVariant.top = tn;
7466 - break;
7467 - case YAFFS_OBJECT_TYPE_DIRECTORY:
7468 - YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
7469 - children);
7470 - break;
7471 - case YAFFS_OBJECT_TYPE_SYMLINK:
7472 - case YAFFS_OBJECT_TYPE_HARDLINK:
7473 - case YAFFS_OBJECT_TYPE_SPECIAL:
7474 - /* No action required */
7475 - break;
7476 - case YAFFS_OBJECT_TYPE_UNKNOWN:
7477 - /* todo this should not happen */
7478 - break;
7479 - }
7480 - }
7481 -
7482 - return theObject;
7483 -}
7484 -
7485 -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
7486 - int number,
7487 - yaffs_ObjectType type)
7488 -{
7489 - yaffs_Object *theObject = NULL;
7490 -
7491 - if (number > 0)
7492 - theObject = yaffs_FindObjectByNumber(dev, number);
7493 -
7494 - if (!theObject)
7495 - theObject = yaffs_CreateNewObject(dev, number, type);
7496 -
7497 - return theObject;
7498 -
7499 -}
7500 -
7501 -
7502 -static YCHAR *yaffs_CloneString(const YCHAR *str)
7503 -{
7504 - YCHAR *newStr = NULL;
7505 -
7506 - if (str && *str) {
7507 - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
7508 - if (newStr)
7509 - yaffs_strcpy(newStr, str);
7510 - }
7511 -
7512 - return newStr;
7513 -
7514 -}
7515 -
7516 -/*
7517 - * Mknod (create) a new object.
7518 - * equivalentObject only has meaning for a hard link;
7519 - * aliasString only has meaning for a sumlink.
7520 - * rdev only has meaning for devices (a subset of special objects)
7521 - */
7522 -
7523 -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
7524 - yaffs_Object *parent,
7525 - const YCHAR *name,
7526 - __u32 mode,
7527 - __u32 uid,
7528 - __u32 gid,
7529 - yaffs_Object *equivalentObject,
7530 - const YCHAR *aliasString, __u32 rdev)
7531 -{
7532 - yaffs_Object *in;
7533 - YCHAR *str = NULL;
7534 -
7535 - yaffs_Device *dev = parent->myDev;
7536 -
7537 - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
7538 - if (yaffs_FindObjectByName(parent, name))
7539 - return NULL;
7540 -
7541 - in = yaffs_CreateNewObject(dev, -1, type);
7542 -
7543 - if (!in)
7544 - return YAFFS_FAIL;
7545 -
7546 - if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
7547 - str = yaffs_CloneString(aliasString);
7548 - if (!str) {
7549 - yaffs_FreeObject(in);
7550 - return NULL;
7551 - }
7552 - }
7553 -
7554 -
7555 -
7556 - if (in) {
7557 - in->hdrChunk = 0;
7558 - in->valid = 1;
7559 - in->variantType = type;
7560 -
7561 - in->yst_mode = mode;
7562 -
7563 -#ifdef CONFIG_YAFFS_WINCE
7564 - yfsd_WinFileTimeNow(in->win_atime);
7565 - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
7566 - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
7567 -
7568 -#else
7569 - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
7570 -
7571 - in->yst_rdev = rdev;
7572 - in->yst_uid = uid;
7573 - in->yst_gid = gid;
7574 -#endif
7575 - in->nDataChunks = 0;
7576 -
7577 - yaffs_SetObjectName(in, name);
7578 - in->dirty = 1;
7579 -
7580 - yaffs_AddObjectToDirectory(parent, in);
7581 -
7582 - in->myDev = parent->myDev;
7583 -
7584 - switch (type) {
7585 - case YAFFS_OBJECT_TYPE_SYMLINK:
7586 - in->variant.symLinkVariant.alias = str;
7587 - break;
7588 - case YAFFS_OBJECT_TYPE_HARDLINK:
7589 - in->variant.hardLinkVariant.equivalentObject =
7590 - equivalentObject;
7591 - in->variant.hardLinkVariant.equivalentObjectId =
7592 - equivalentObject->objectId;
7593 - ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
7594 - break;
7595 - case YAFFS_OBJECT_TYPE_FILE:
7596 - case YAFFS_OBJECT_TYPE_DIRECTORY:
7597 - case YAFFS_OBJECT_TYPE_SPECIAL:
7598 - case YAFFS_OBJECT_TYPE_UNKNOWN:
7599 - /* do nothing */
7600 - break;
7601 - }
7602 -
7603 - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
7604 - /* Could not create the object header, fail the creation */
7605 - yaffs_DeleteObject(in);
7606 - in = NULL;
7607 - }
7608 -
7609 - }
7610 -
7611 - return in;
7612 -}
7613 -
7614 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
7615 - __u32 mode, __u32 uid, __u32 gid)
7616 -{
7617 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
7618 - uid, gid, NULL, NULL, 0);
7619 -}
7620 -
7621 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
7622 - __u32 mode, __u32 uid, __u32 gid)
7623 -{
7624 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
7625 - mode, uid, gid, NULL, NULL, 0);
7626 -}
7627 -
7628 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
7629 - __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
7630 -{
7631 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
7632 - uid, gid, NULL, NULL, rdev);
7633 -}
7634 -
7635 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
7636 - __u32 mode, __u32 uid, __u32 gid,
7637 - const YCHAR *alias)
7638 -{
7639 - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
7640 - uid, gid, NULL, alias, 0);
7641 -}
7642 -
7643 -/* yaffs_Link returns the object id of the equivalent object.*/
7644 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
7645 - yaffs_Object *equivalentObject)
7646 -{
7647 - /* Get the real object in case we were fed a hard link as an equivalent object */
7648 - equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
7649 -
7650 - if (yaffs_MknodObject
7651 - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
7652 - equivalentObject, NULL, 0)) {
7653 - return equivalentObject;
7654 - } else {
7655 - return NULL;
7656 - }
7657 -
7658 -}
7659 -
7660 -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
7661 - const YCHAR *newName, int force, int shadows)
7662 -{
7663 - int unlinkOp;
7664 - int deleteOp;
7665 -
7666 - yaffs_Object *existingTarget;
7667 -
7668 - if (newDir == NULL)
7669 - newDir = obj->parent; /* use the old directory */
7670 -
7671 - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
7672 - T(YAFFS_TRACE_ALWAYS,
7673 - (TSTR
7674 - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
7675 - TENDSTR)));
7676 - YBUG();
7677 - }
7678 -
7679 - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
7680 - if (obj->myDev->isYaffs2)
7681 - unlinkOp = (newDir == obj->myDev->unlinkedDir);
7682 - else
7683 - unlinkOp = (newDir == obj->myDev->unlinkedDir
7684 - && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
7685 -
7686 - deleteOp = (newDir == obj->myDev->deletedDir);
7687 -
7688 - existingTarget = yaffs_FindObjectByName(newDir, newName);
7689 -
7690 - /* If the object is a file going into the unlinked directory,
7691 - * then it is OK to just stuff it in since duplicate names are allowed.
7692 - * else only proceed if the new name does not exist and if we're putting
7693 - * it into a directory.
7694 - */
7695 - if ((unlinkOp ||
7696 - deleteOp ||
7697 - force ||
7698 - (shadows > 0) ||
7699 - !existingTarget) &&
7700 - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
7701 - yaffs_SetObjectName(obj, newName);
7702 - obj->dirty = 1;
7703 -
7704 - yaffs_AddObjectToDirectory(newDir, obj);
7705 -
7706 - if (unlinkOp)
7707 - obj->unlinked = 1;
7708 -
7709 - /* If it is a deletion then we mark it as a shrink for gc purposes. */
7710 - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
7711 - return YAFFS_OK;
7712 - }
7713 -
7714 - return YAFFS_FAIL;
7715 -}
7716 -
7717 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
7718 - yaffs_Object *newDir, const YCHAR *newName)
7719 -{
7720 - yaffs_Object *obj = NULL;
7721 - yaffs_Object *existingTarget = NULL;
7722 - int force = 0;
7723 -
7724 -
7725 - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7726 - YBUG();
7727 - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7728 - YBUG();
7729 -
7730 -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
7731 - /* Special case for case insemsitive systems (eg. WinCE).
7732 - * While look-up is case insensitive, the name isn't.
7733 - * Therefore we might want to change x.txt to X.txt
7734 - */
7735 - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
7736 - force = 1;
7737 -#endif
7738 -
7739 - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
7740 - /* ENAMETOOLONG */
7741 - return YAFFS_FAIL;
7742 -
7743 - obj = yaffs_FindObjectByName(oldDir, oldName);
7744 -
7745 - if (obj && obj->renameAllowed) {
7746 -
7747 - /* Now do the handling for an existing target, if there is one */
7748 -
7749 - existingTarget = yaffs_FindObjectByName(newDir, newName);
7750 - if (existingTarget &&
7751 - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
7752 - !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
7753 - /* There is a target that is a non-empty directory, so we fail */
7754 - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
7755 - } else if (existingTarget && existingTarget != obj) {
7756 - /* Nuke the target first, using shadowing,
7757 - * but only if it isn't the same object
7758 - */
7759 - yaffs_ChangeObjectName(obj, newDir, newName, force,
7760 - existingTarget->objectId);
7761 - yaffs_UnlinkObject(existingTarget);
7762 - }
7763 -
7764 - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
7765 - }
7766 - return YAFFS_FAIL;
7767 -}
7768 -
7769 -/*------------------------- Block Management and Page Allocation ----------------*/
7770 -
7771 -static int yaffs_InitialiseBlocks(yaffs_Device *dev)
7772 -{
7773 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
7774 -
7775 - dev->blockInfo = NULL;
7776 - dev->chunkBits = NULL;
7777 -
7778 - dev->allocationBlock = -1; /* force it to get a new one */
7779 -
7780 - /* If the first allocation strategy fails, thry the alternate one */
7781 - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
7782 - if (!dev->blockInfo) {
7783 - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
7784 - dev->blockInfoAlt = 1;
7785 - } else
7786 - dev->blockInfoAlt = 0;
7787 -
7788 - if (dev->blockInfo) {
7789 - /* Set up dynamic blockinfo stuff. */
7790 - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
7791 - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
7792 - if (!dev->chunkBits) {
7793 - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
7794 - dev->chunkBitsAlt = 1;
7795 - } else
7796 - dev->chunkBitsAlt = 0;
7797 - }
7798 -
7799 - if (dev->blockInfo && dev->chunkBits) {
7800 - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
7801 - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
7802 - return YAFFS_OK;
7803 - }
7804 -
7805 - return YAFFS_FAIL;
7806 -}
7807 -
7808 -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
7809 -{
7810 - if (dev->blockInfoAlt && dev->blockInfo)
7811 - YFREE_ALT(dev->blockInfo);
7812 - else if (dev->blockInfo)
7813 - YFREE(dev->blockInfo);
7814 -
7815 - dev->blockInfoAlt = 0;
7816 -
7817 - dev->blockInfo = NULL;
7818 -
7819 - if (dev->chunkBitsAlt && dev->chunkBits)
7820 - YFREE_ALT(dev->chunkBits);
7821 - else if (dev->chunkBits)
7822 - YFREE(dev->chunkBits);
7823 - dev->chunkBitsAlt = 0;
7824 - dev->chunkBits = NULL;
7825 -}
7826 -
7827 -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
7828 - yaffs_BlockInfo *bi)
7829 -{
7830 - int i;
7831 - __u32 seq;
7832 - yaffs_BlockInfo *b;
7833 -
7834 - if (!dev->isYaffs2)
7835 - return 1; /* disqualification only applies to yaffs2. */
7836 -
7837 - if (!bi->hasShrinkHeader)
7838 - return 1; /* can gc */
7839 -
7840 - /* Find the oldest dirty sequence number if we don't know it and save it
7841 - * so we don't have to keep recomputing it.
7842 - */
7843 - if (!dev->oldestDirtySequence) {
7844 - seq = dev->sequenceNumber;
7845 -
7846 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
7847 - i++) {
7848 - b = yaffs_GetBlockInfo(dev, i);
7849 - if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
7850 - (b->pagesInUse - b->softDeletions) <
7851 - dev->nChunksPerBlock && b->sequenceNumber < seq) {
7852 - seq = b->sequenceNumber;
7853 - }
7854 - }
7855 - dev->oldestDirtySequence = seq;
7856 - }
7857 -
7858 - /* Can't do gc of this block if there are any blocks older than this one that have
7859 - * discarded pages.
7860 - */
7861 - return (bi->sequenceNumber <= dev->oldestDirtySequence);
7862 -}
7863 -
7864 -/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
7865 - * for garbage collection.
7866 - */
7867 -
7868 -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
7869 - int aggressive)
7870 -{
7871 - int b = dev->currentDirtyChecker;
7872 -
7873 - int i;
7874 - int iterations;
7875 - int dirtiest = -1;
7876 - int pagesInUse = 0;
7877 - int prioritised = 0;
7878 - yaffs_BlockInfo *bi;
7879 - int pendingPrioritisedExist = 0;
7880 -
7881 - /* First let's see if we need to grab a prioritised block */
7882 - if (dev->hasPendingPrioritisedGCs) {
7883 - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
7884 -
7885 - bi = yaffs_GetBlockInfo(dev, i);
7886 - /* yaffs_VerifyBlock(dev,bi,i); */
7887 -
7888 - if (bi->gcPrioritise) {
7889 - pendingPrioritisedExist = 1;
7890 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
7891 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
7892 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
7893 - dirtiest = i;
7894 - prioritised = 1;
7895 - aggressive = 1; /* Fool the non-aggressive skip logiv below */
7896 - }
7897 - }
7898 - }
7899 -
7900 - if (!pendingPrioritisedExist) /* None found, so we can clear this */
7901 - dev->hasPendingPrioritisedGCs = 0;
7902 - }
7903 -
7904 - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
7905 - * search harder.
7906 - * else (we're doing a leasurely gc), then we only bother to do this if the
7907 - * block has only a few pages in use.
7908 - */
7909 -
7910 - dev->nonAggressiveSkip--;
7911 -
7912 - if (!aggressive && (dev->nonAggressiveSkip > 0))
7913 - return -1;
7914 -
7915 - if (!prioritised)
7916 - pagesInUse =
7917 - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
7918 -
7919 - if (aggressive)
7920 - iterations =
7921 - dev->internalEndBlock - dev->internalStartBlock + 1;
7922 - else {
7923 - iterations =
7924 - dev->internalEndBlock - dev->internalStartBlock + 1;
7925 - iterations = iterations / 16;
7926 - if (iterations > 200)
7927 - iterations = 200;
7928 - }
7929 -
7930 - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
7931 - b++;
7932 - if (b < dev->internalStartBlock || b > dev->internalEndBlock)
7933 - b = dev->internalStartBlock;
7934 -
7935 - if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
7936 - T(YAFFS_TRACE_ERROR,
7937 - (TSTR("**>> Block %d is not valid" TENDSTR), b));
7938 - YBUG();
7939 - }
7940 -
7941 - bi = yaffs_GetBlockInfo(dev, b);
7942 -
7943 - if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
7944 - (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
7945 - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
7946 - dirtiest = b;
7947 - pagesInUse = (bi->pagesInUse - bi->softDeletions);
7948 - }
7949 - }
7950 -
7951 - dev->currentDirtyChecker = b;
7952 -
7953 - if (dirtiest > 0) {
7954 - T(YAFFS_TRACE_GC,
7955 - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
7956 - dev->nChunksPerBlock - pagesInUse, prioritised));
7957 - }
7958 -
7959 - dev->oldestDirtySequence = 0;
7960 -
7961 - if (dirtiest > 0)
7962 - dev->nonAggressiveSkip = 4;
7963 -
7964 - return dirtiest;
7965 -}
7966 -
7967 -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
7968 -{
7969 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
7970 -
7971 - int erasedOk = 0;
7972 -
7973 - /* If the block is still healthy erase it and mark as clean.
7974 - * If the block has had a data failure, then retire it.
7975 - */
7976 -
7977 - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
7978 - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
7979 - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
7980 -
7981 - bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
7982 -
7983 - if (!bi->needsRetiring) {
7984 - yaffs_InvalidateCheckpoint(dev);
7985 - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
7986 - if (!erasedOk) {
7987 - dev->nErasureFailures++;
7988 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
7989 - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
7990 - }
7991 - }
7992 -
7993 - if (erasedOk &&
7994 - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
7995 - int i;
7996 - for (i = 0; i < dev->nChunksPerBlock; i++) {
7997 - if (!yaffs_CheckChunkErased
7998 - (dev, blockNo * dev->nChunksPerBlock + i)) {
7999 - T(YAFFS_TRACE_ERROR,
8000 - (TSTR
8001 - (">>Block %d erasure supposedly OK, but chunk %d not erased"
8002 - TENDSTR), blockNo, i));
8003 - }
8004 - }
8005 - }
8006 -
8007 - if (erasedOk) {
8008 - /* Clean it up... */
8009 - bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
8010 - dev->nErasedBlocks++;
8011 - bi->pagesInUse = 0;
8012 - bi->softDeletions = 0;
8013 - bi->hasShrinkHeader = 0;
8014 - bi->skipErasedCheck = 1; /* This is clean, so no need to check */
8015 - bi->gcPrioritise = 0;
8016 - yaffs_ClearChunkBits(dev, blockNo);
8017 -
8018 - T(YAFFS_TRACE_ERASE,
8019 - (TSTR("Erased block %d" TENDSTR), blockNo));
8020 - } else {
8021 - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
8022 -
8023 - yaffs_RetireBlock(dev, blockNo);
8024 - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
8025 - (TSTR("**>> Block %d retired" TENDSTR), blockNo));
8026 - }
8027 -}
8028 -
8029 -static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
8030 -{
8031 - int i;
8032 -
8033 - yaffs_BlockInfo *bi;
8034 -
8035 - if (dev->nErasedBlocks < 1) {
8036 - /* Hoosterman we've got a problem.
8037 - * Can't get space to gc
8038 - */
8039 - T(YAFFS_TRACE_ERROR,
8040 - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
8041 -
8042 - return -1;
8043 - }
8044 -
8045 - /* Find an empty block. */
8046 -
8047 - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
8048 - dev->allocationBlockFinder++;
8049 - if (dev->allocationBlockFinder < dev->internalStartBlock
8050 - || dev->allocationBlockFinder > dev->internalEndBlock) {
8051 - dev->allocationBlockFinder = dev->internalStartBlock;
8052 - }
8053 -
8054 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
8055 -
8056 - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
8057 - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
8058 - dev->sequenceNumber++;
8059 - bi->sequenceNumber = dev->sequenceNumber;
8060 - dev->nErasedBlocks--;
8061 - T(YAFFS_TRACE_ALLOCATE,
8062 - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
8063 - dev->allocationBlockFinder, dev->sequenceNumber,
8064 - dev->nErasedBlocks));
8065 - return dev->allocationBlockFinder;
8066 - }
8067 - }
8068 -
8069 - T(YAFFS_TRACE_ALWAYS,
8070 - (TSTR
8071 - ("yaffs tragedy: no more erased blocks, but there should have been %d"
8072 - TENDSTR), dev->nErasedBlocks));
8073 -
8074 - return -1;
8075 -}
8076 -
8077 -
8078 -
8079 -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
8080 -{
8081 - if (!dev->nCheckpointBlocksRequired &&
8082 - dev->isYaffs2) {
8083 - /* Not a valid value so recalculate */
8084 - int nBytes = 0;
8085 - int nBlocks;
8086 - int devBlocks = (dev->endBlock - dev->startBlock + 1);
8087 - int tnodeSize;
8088 -
8089 - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
8090 -
8091 - if (tnodeSize < sizeof(yaffs_Tnode))
8092 - tnodeSize = sizeof(yaffs_Tnode);
8093 -
8094 - nBytes += sizeof(yaffs_CheckpointValidity);
8095 - nBytes += sizeof(yaffs_CheckpointDevice);
8096 - nBytes += devBlocks * sizeof(yaffs_BlockInfo);
8097 - nBytes += devBlocks * dev->chunkBitmapStride;
8098 - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
8099 - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
8100 - nBytes += sizeof(yaffs_CheckpointValidity);
8101 - nBytes += sizeof(__u32); /* checksum*/
8102 -
8103 - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
8104 -
8105 - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
8106 -
8107 - dev->nCheckpointBlocksRequired = nBlocks;
8108 - }
8109 -
8110 - return dev->nCheckpointBlocksRequired;
8111 -}
8112 -
8113 -/*
8114 - * Check if there's space to allocate...
8115 - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
8116 - */
8117 -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
8118 -{
8119 - int reservedChunks;
8120 - int reservedBlocks = dev->nReservedBlocks;
8121 - int checkpointBlocks;
8122 -
8123 - if (dev->isYaffs2) {
8124 - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
8125 - dev->blocksInCheckpoint;
8126 - if (checkpointBlocks < 0)
8127 - checkpointBlocks = 0;
8128 - } else {
8129 - checkpointBlocks = 0;
8130 - }
8131 -
8132 - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
8133 -
8134 - return (dev->nFreeChunks > reservedChunks);
8135 -}
8136 -
8137 -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
8138 - yaffs_BlockInfo **blockUsedPtr)
8139 -{
8140 - int retVal;
8141 - yaffs_BlockInfo *bi;
8142 -
8143 - if (dev->allocationBlock < 0) {
8144 - /* Get next block to allocate off */
8145 - dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
8146 - dev->allocationPage = 0;
8147 - }
8148 -
8149 - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
8150 - /* Not enough space to allocate unless we're allowed to use the reserve. */
8151 - return -1;
8152 - }
8153 -
8154 - if (dev->nErasedBlocks < dev->nReservedBlocks
8155 - && dev->allocationPage == 0) {
8156 - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
8157 - }
8158 -
8159 - /* Next page please.... */
8160 - if (dev->allocationBlock >= 0) {
8161 - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
8162 -
8163 - retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
8164 - dev->allocationPage;
8165 - bi->pagesInUse++;
8166 - yaffs_SetChunkBit(dev, dev->allocationBlock,
8167 - dev->allocationPage);
8168 -
8169 - dev->allocationPage++;
8170 -
8171 - dev->nFreeChunks--;
8172 -
8173 - /* If the block is full set the state to full */
8174 - if (dev->allocationPage >= dev->nChunksPerBlock) {
8175 - bi->blockState = YAFFS_BLOCK_STATE_FULL;
8176 - dev->allocationBlock = -1;
8177 - }
8178 -
8179 - if (blockUsedPtr)
8180 - *blockUsedPtr = bi;
8181 -
8182 - return retVal;
8183 - }
8184 -
8185 - T(YAFFS_TRACE_ERROR,
8186 - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
8187 -
8188 - return -1;
8189 -}
8190 -
8191 -static int yaffs_GetErasedChunks(yaffs_Device *dev)
8192 -{
8193 - int n;
8194 -
8195 - n = dev->nErasedBlocks * dev->nChunksPerBlock;
8196 -
8197 - if (dev->allocationBlock > 0)
8198 - n += (dev->nChunksPerBlock - dev->allocationPage);
8199 -
8200 - return n;
8201 -
8202 -}
8203 -
8204 -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
8205 - int wholeBlock)
8206 -{
8207 - int oldChunk;
8208 - int newChunk;
8209 - int markNAND;
8210 - int retVal = YAFFS_OK;
8211 - int cleanups = 0;
8212 - int i;
8213 - int isCheckpointBlock;
8214 - int matchingChunk;
8215 - int maxCopies;
8216 -
8217 - int chunksBefore = yaffs_GetErasedChunks(dev);
8218 - int chunksAfter;
8219 -
8220 - yaffs_ExtendedTags tags;
8221 -
8222 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
8223 -
8224 - yaffs_Object *object;
8225 -
8226 - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
8227 -
8228 - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
8229 -
8230 - T(YAFFS_TRACE_TRACING,
8231 - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
8232 - block,
8233 - bi->pagesInUse,
8234 - bi->hasShrinkHeader,
8235 - wholeBlock));
8236 -
8237 - /*yaffs_VerifyFreeChunks(dev); */
8238 -
8239 - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
8240 -
8241 - /* Take off the number of soft deleted entries because
8242 - * they're going to get really deleted during GC.
8243 - */
8244 - dev->nFreeChunks -= bi->softDeletions;
8245 -
8246 - dev->isDoingGC = 1;
8247 -
8248 - if (isCheckpointBlock ||
8249 - !yaffs_StillSomeChunkBits(dev, block)) {
8250 - T(YAFFS_TRACE_TRACING,
8251 - (TSTR
8252 - ("Collecting block %d that has no chunks in use" TENDSTR),
8253 - block));
8254 - yaffs_BlockBecameDirty(dev, block);
8255 - } else {
8256 -
8257 - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
8258 -
8259 - yaffs_VerifyBlock(dev, bi, block);
8260 -
8261 - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
8262 - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
8263 -
8264 - for (/* init already done */;
8265 - retVal == YAFFS_OK &&
8266 - dev->gcChunk < dev->nChunksPerBlock &&
8267 - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
8268 - maxCopies > 0;
8269 - dev->gcChunk++, oldChunk++) {
8270 - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
8271 -
8272 - /* This page is in use and might need to be copied off */
8273 -
8274 - maxCopies--;
8275 -
8276 - markNAND = 1;
8277 -
8278 - yaffs_InitialiseTags(&tags);
8279 -
8280 - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
8281 - buffer, &tags);
8282 -
8283 - object =
8284 - yaffs_FindObjectByNumber(dev,
8285 - tags.objectId);
8286 -
8287 - T(YAFFS_TRACE_GC_DETAIL,
8288 - (TSTR
8289 - ("Collecting chunk in block %d, %d %d %d " TENDSTR),
8290 - dev->gcChunk, tags.objectId, tags.chunkId,
8291 - tags.byteCount));
8292 -
8293 - if (object && !yaffs_SkipVerification(dev)) {
8294 - if (tags.chunkId == 0)
8295 - matchingChunk = object->hdrChunk;
8296 - else if (object->softDeleted)
8297 - matchingChunk = oldChunk; /* Defeat the test */
8298 - else
8299 - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
8300 -
8301 - if (oldChunk != matchingChunk)
8302 - T(YAFFS_TRACE_ERROR,
8303 - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
8304 - oldChunk, matchingChunk, tags.objectId, tags.chunkId));
8305 -
8306 - }
8307 -
8308 - if (!object) {
8309 - T(YAFFS_TRACE_ERROR,
8310 - (TSTR
8311 - ("page %d in gc has no object: %d %d %d "
8312 - TENDSTR), oldChunk,
8313 - tags.objectId, tags.chunkId, tags.byteCount));
8314 - }
8315 -
8316 - if (object &&
8317 - object->deleted &&
8318 - object->softDeleted &&
8319 - tags.chunkId != 0) {
8320 - /* Data chunk in a soft deleted file, throw it away
8321 - * It's a soft deleted data chunk,
8322 - * No need to copy this, just forget about it and
8323 - * fix up the object.
8324 - */
8325 -
8326 - object->nDataChunks--;
8327 -
8328 - if (object->nDataChunks <= 0) {
8329 - /* remeber to clean up the object */
8330 - dev->gcCleanupList[cleanups] =
8331 - tags.objectId;
8332 - cleanups++;
8333 - }
8334 - markNAND = 0;
8335 - } else if (0) {
8336 - /* Todo object && object->deleted && object->nDataChunks == 0 */
8337 - /* Deleted object header with no data chunks.
8338 - * Can be discarded and the file deleted.
8339 - */
8340 - object->hdrChunk = 0;
8341 - yaffs_FreeTnode(object->myDev,
8342 - object->variant.
8343 - fileVariant.top);
8344 - object->variant.fileVariant.top = NULL;
8345 - yaffs_DoGenericObjectDeletion(object);
8346 -
8347 - } else if (object) {
8348 - /* It's either a data chunk in a live file or
8349 - * an ObjectHeader, so we're interested in it.
8350 - * NB Need to keep the ObjectHeaders of deleted files
8351 - * until the whole file has been deleted off
8352 - */
8353 - tags.serialNumber++;
8354 -
8355 - dev->nGCCopies++;
8356 -
8357 - if (tags.chunkId == 0) {
8358 - /* It is an object Id,
8359 - * We need to nuke the shrinkheader flags first
8360 - * We no longer want the shrinkHeader flag since its work is done
8361 - * and if it is left in place it will mess up scanning.
8362 - */
8363 -
8364 - yaffs_ObjectHeader *oh;
8365 - oh = (yaffs_ObjectHeader *)buffer;
8366 - oh->isShrink = 0;
8367 - tags.extraIsShrinkHeader = 0;
8368 -
8369 - yaffs_VerifyObjectHeader(object, oh, &tags, 1);
8370 - }
8371 -
8372 - newChunk =
8373 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
8374 -
8375 - if (newChunk < 0) {
8376 - retVal = YAFFS_FAIL;
8377 - } else {
8378 -
8379 - /* Ok, now fix up the Tnodes etc. */
8380 -
8381 - if (tags.chunkId == 0) {
8382 - /* It's a header */
8383 - object->hdrChunk = newChunk;
8384 - object->serial = tags.serialNumber;
8385 - } else {
8386 - /* It's a data chunk */
8387 - yaffs_PutChunkIntoFile
8388 - (object,
8389 - tags.chunkId,
8390 - newChunk, 0);
8391 - }
8392 - }
8393 - }
8394 -
8395 - if (retVal == YAFFS_OK)
8396 - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
8397 -
8398 - }
8399 - }
8400 -
8401 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
8402 -
8403 -
8404 - /* Do any required cleanups */
8405 - for (i = 0; i < cleanups; i++) {
8406 - /* Time to delete the file too */
8407 - object =
8408 - yaffs_FindObjectByNumber(dev,
8409 - dev->gcCleanupList[i]);
8410 - if (object) {
8411 - yaffs_FreeTnode(dev,
8412 - object->variant.fileVariant.
8413 - top);
8414 - object->variant.fileVariant.top = NULL;
8415 - T(YAFFS_TRACE_GC,
8416 - (TSTR
8417 - ("yaffs: About to finally delete object %d"
8418 - TENDSTR), object->objectId));
8419 - yaffs_DoGenericObjectDeletion(object);
8420 - object->myDev->nDeletedFiles--;
8421 - }
8422 -
8423 - }
8424 -
8425 - }
8426 -
8427 - yaffs_VerifyCollectedBlock(dev, bi, block);
8428 -
8429 - chunksAfter = yaffs_GetErasedChunks(dev);
8430 - if (chunksBefore >= chunksAfter) {
8431 - T(YAFFS_TRACE_GC,
8432 - (TSTR
8433 - ("gc did not increase free chunks before %d after %d"
8434 - TENDSTR), chunksBefore, chunksAfter));
8435 - }
8436 -
8437 - /* If the gc completed then clear the current gcBlock so that we find another. */
8438 - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
8439 - dev->gcBlock = -1;
8440 - dev->gcChunk = 0;
8441 - }
8442 -
8443 - dev->isDoingGC = 0;
8444 -
8445 - return retVal;
8446 -}
8447 -
8448 -/* New garbage collector
8449 - * If we're very low on erased blocks then we do aggressive garbage collection
8450 - * otherwise we do "leasurely" garbage collection.
8451 - * Aggressive gc looks further (whole array) and will accept less dirty blocks.
8452 - * Passive gc only inspects smaller areas and will only accept more dirty blocks.
8453 - *
8454 - * The idea is to help clear out space in a more spread-out manner.
8455 - * Dunno if it really does anything useful.
8456 - */
8457 -static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
8458 -{
8459 - int block;
8460 - int aggressive;
8461 - int gcOk = YAFFS_OK;
8462 - int maxTries = 0;
8463 -
8464 - int checkpointBlockAdjust;
8465 -
8466 - if (dev->isDoingGC) {
8467 - /* Bail out so we don't get recursive gc */
8468 - return YAFFS_OK;
8469 - }
8470 -
8471 - /* This loop should pass the first time.
8472 - * We'll only see looping here if the erase of the collected block fails.
8473 - */
8474 -
8475 - do {
8476 - maxTries++;
8477 -
8478 - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
8479 - if (checkpointBlockAdjust < 0)
8480 - checkpointBlockAdjust = 0;
8481 -
8482 - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
8483 - /* We need a block soon...*/
8484 - aggressive = 1;
8485 - } else {
8486 - /* We're in no hurry */
8487 - aggressive = 0;
8488 - }
8489 -
8490 - if (dev->gcBlock <= 0) {
8491 - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
8492 - dev->gcChunk = 0;
8493 - }
8494 -
8495 - block = dev->gcBlock;
8496 -
8497 - if (block > 0) {
8498 - dev->garbageCollections++;
8499 - if (!aggressive)
8500 - dev->passiveGarbageCollections++;
8501 -
8502 - T(YAFFS_TRACE_GC,
8503 - (TSTR
8504 - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
8505 - dev->nErasedBlocks, aggressive));
8506 -
8507 - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
8508 - }
8509 -
8510 - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
8511 - T(YAFFS_TRACE_GC,
8512 - (TSTR
8513 - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
8514 - TENDSTR), dev->nErasedBlocks, maxTries, block));
8515 - }
8516 - } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
8517 - (block > 0) &&
8518 - (maxTries < 2));
8519 -
8520 - return aggressive ? gcOk : YAFFS_OK;
8521 -}
8522 -
8523 -/*------------------------- TAGS --------------------------------*/
8524 -
8525 -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
8526 - int chunkInObject)
8527 -{
8528 - return (tags->chunkId == chunkInObject &&
8529 - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
8530 -
8531 -}
8532 -
8533 -
8534 -/*-------------------- Data file manipulation -----------------*/
8535 -
8536 -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
8537 - yaffs_ExtendedTags *tags)
8538 -{
8539 - /*Get the Tnode, then get the level 0 offset chunk offset */
8540 - yaffs_Tnode *tn;
8541 - int theChunk = -1;
8542 - yaffs_ExtendedTags localTags;
8543 - int retVal = -1;
8544 -
8545 - yaffs_Device *dev = in->myDev;
8546 -
8547 - if (!tags) {
8548 - /* Passed a NULL, so use our own tags space */
8549 - tags = &localTags;
8550 - }
8551 -
8552 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
8553 -
8554 - if (tn) {
8555 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8556 -
8557 - retVal =
8558 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
8559 - chunkInInode);
8560 - }
8561 - return retVal;
8562 -}
8563 -
8564 -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
8565 - yaffs_ExtendedTags *tags)
8566 -{
8567 - /* Get the Tnode, then get the level 0 offset chunk offset */
8568 - yaffs_Tnode *tn;
8569 - int theChunk = -1;
8570 - yaffs_ExtendedTags localTags;
8571 -
8572 - yaffs_Device *dev = in->myDev;
8573 - int retVal = -1;
8574 -
8575 - if (!tags) {
8576 - /* Passed a NULL, so use our own tags space */
8577 - tags = &localTags;
8578 - }
8579 -
8580 - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
8581 -
8582 - if (tn) {
8583 -
8584 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8585 -
8586 - retVal =
8587 - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
8588 - chunkInInode);
8589 -
8590 - /* Delete the entry in the filestructure (if found) */
8591 - if (retVal != -1)
8592 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
8593 - }
8594 -
8595 - return retVal;
8596 -}
8597 -
8598 -#ifdef YAFFS_PARANOID
8599 -
8600 -static int yaffs_CheckFileSanity(yaffs_Object *in)
8601 -{
8602 - int chunk;
8603 - int nChunks;
8604 - int fSize;
8605 - int failed = 0;
8606 - int objId;
8607 - yaffs_Tnode *tn;
8608 - yaffs_Tags localTags;
8609 - yaffs_Tags *tags = &localTags;
8610 - int theChunk;
8611 - int chunkDeleted;
8612 -
8613 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
8614 - return YAFFS_FAIL;
8615 -
8616 - objId = in->objectId;
8617 - fSize = in->variant.fileVariant.fileSize;
8618 - nChunks =
8619 - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
8620 -
8621 - for (chunk = 1; chunk <= nChunks; chunk++) {
8622 - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
8623 - chunk);
8624 -
8625 - if (tn) {
8626 -
8627 - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
8628 -
8629 - if (yaffs_CheckChunkBits
8630 - (dev, theChunk / dev->nChunksPerBlock,
8631 - theChunk % dev->nChunksPerBlock)) {
8632 -
8633 - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
8634 - tags,
8635 - &chunkDeleted);
8636 - if (yaffs_TagsMatch
8637 - (tags, in->objectId, chunk, chunkDeleted)) {
8638 - /* found it; */
8639 -
8640 - }
8641 - } else {
8642 -
8643 - failed = 1;
8644 - }
8645 -
8646 - } else {
8647 - /* T(("No level 0 found for %d\n", chunk)); */
8648 - }
8649 - }
8650 -
8651 - return failed ? YAFFS_FAIL : YAFFS_OK;
8652 -}
8653 -
8654 -#endif
8655 -
8656 -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
8657 - int chunkInNAND, int inScan)
8658 -{
8659 - /* NB inScan is zero unless scanning.
8660 - * For forward scanning, inScan is > 0;
8661 - * for backward scanning inScan is < 0
8662 - */
8663 -
8664 - yaffs_Tnode *tn;
8665 - yaffs_Device *dev = in->myDev;
8666 - int existingChunk;
8667 - yaffs_ExtendedTags existingTags;
8668 - yaffs_ExtendedTags newTags;
8669 - unsigned existingSerial, newSerial;
8670 -
8671 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
8672 - /* Just ignore an attempt at putting a chunk into a non-file during scanning
8673 - * If it is not during Scanning then something went wrong!
8674 - */
8675 - if (!inScan) {
8676 - T(YAFFS_TRACE_ERROR,
8677 - (TSTR
8678 - ("yaffs tragedy:attempt to put data chunk into a non-file"
8679 - TENDSTR)));
8680 - YBUG();
8681 - }
8682 -
8683 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
8684 - return YAFFS_OK;
8685 - }
8686 -
8687 - tn = yaffs_AddOrFindLevel0Tnode(dev,
8688 - &in->variant.fileVariant,
8689 - chunkInInode,
8690 - NULL);
8691 - if (!tn)
8692 - return YAFFS_FAIL;
8693 -
8694 - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
8695 -
8696 - if (inScan != 0) {
8697 - /* If we're scanning then we need to test for duplicates
8698 - * NB This does not need to be efficient since it should only ever
8699 - * happen when the power fails during a write, then only one
8700 - * chunk should ever be affected.
8701 - *
8702 - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
8703 - * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
8704 - */
8705 -
8706 - if (existingChunk > 0) {
8707 - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
8708 - * thus we have to do a FindChunkInFile to get the real chunk id.
8709 - *
8710 - * We have a duplicate now we need to decide which one to use:
8711 - *
8712 - * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
8713 - * Forward scanning YAFFS2: The new one is what we use, dump the old one.
8714 - * YAFFS1: Get both sets of tags and compare serial numbers.
8715 - */
8716 -
8717 - if (inScan > 0) {
8718 - /* Only do this for forward scanning */
8719 - yaffs_ReadChunkWithTagsFromNAND(dev,
8720 - chunkInNAND,
8721 - NULL, &newTags);
8722 -
8723 - /* Do a proper find */
8724 - existingChunk =
8725 - yaffs_FindChunkInFile(in, chunkInInode,
8726 - &existingTags);
8727 - }
8728 -
8729 - if (existingChunk <= 0) {
8730 - /*Hoosterman - how did this happen? */
8731 -
8732 - T(YAFFS_TRACE_ERROR,
8733 - (TSTR
8734 - ("yaffs tragedy: existing chunk < 0 in scan"
8735 - TENDSTR)));
8736 -
8737 - }
8738 -
8739 - /* NB The deleted flags should be false, otherwise the chunks will
8740 - * not be loaded during a scan
8741 - */
8742 -
8743 - if (inScan > 0) {
8744 - newSerial = newTags.serialNumber;
8745 - existingSerial = existingTags.serialNumber;
8746 - }
8747 -
8748 - if ((inScan > 0) &&
8749 - (in->myDev->isYaffs2 ||
8750 - existingChunk <= 0 ||
8751 - ((existingSerial + 1) & 3) == newSerial)) {
8752 - /* Forward scanning.
8753 - * Use new
8754 - * Delete the old one and drop through to update the tnode
8755 - */
8756 - yaffs_DeleteChunk(dev, existingChunk, 1,
8757 - __LINE__);
8758 - } else {
8759 - /* Backward scanning or we want to use the existing one
8760 - * Use existing.
8761 - * Delete the new one and return early so that the tnode isn't changed
8762 - */
8763 - yaffs_DeleteChunk(dev, chunkInNAND, 1,
8764 - __LINE__);
8765 - return YAFFS_OK;
8766 - }
8767 - }
8768 -
8769 - }
8770 -
8771 - if (existingChunk == 0)
8772 - in->nDataChunks++;
8773 -
8774 - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
8775 -
8776 - return YAFFS_OK;
8777 -}
8778 -
8779 -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
8780 - __u8 *buffer)
8781 -{
8782 - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
8783 -
8784 - if (chunkInNAND >= 0)
8785 - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
8786 - buffer, NULL);
8787 - else {
8788 - T(YAFFS_TRACE_NANDACCESS,
8789 - (TSTR("Chunk %d not found zero instead" TENDSTR),
8790 - chunkInNAND));
8791 - /* get sane (zero) data if you read a hole */
8792 - memset(buffer, 0, in->myDev->nDataBytesPerChunk);
8793 - return 0;
8794 - }
8795 -
8796 -}
8797 -
8798 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
8799 -{
8800 - int block;
8801 - int page;
8802 - yaffs_ExtendedTags tags;
8803 - yaffs_BlockInfo *bi;
8804 -
8805 - if (chunkId <= 0)
8806 - return;
8807 -
8808 - dev->nDeletions++;
8809 - block = chunkId / dev->nChunksPerBlock;
8810 - page = chunkId % dev->nChunksPerBlock;
8811 -
8812 -
8813 - if (!yaffs_CheckChunkBit(dev, block, page))
8814 - T(YAFFS_TRACE_VERIFY,
8815 - (TSTR("Deleting invalid chunk %d"TENDSTR),
8816 - chunkId));
8817 -
8818 - bi = yaffs_GetBlockInfo(dev, block);
8819 -
8820 - T(YAFFS_TRACE_DELETION,
8821 - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
8822 -
8823 - if (markNAND &&
8824 - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
8825 -
8826 - yaffs_InitialiseTags(&tags);
8827 -
8828 - tags.chunkDeleted = 1;
8829 -
8830 - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
8831 - yaffs_HandleUpdateChunk(dev, chunkId, &tags);
8832 - } else {
8833 - dev->nUnmarkedDeletions++;
8834 - }
8835 -
8836 - /* Pull out of the management area.
8837 - * If the whole block became dirty, this will kick off an erasure.
8838 - */
8839 - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
8840 - bi->blockState == YAFFS_BLOCK_STATE_FULL ||
8841 - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
8842 - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
8843 - dev->nFreeChunks++;
8844 -
8845 - yaffs_ClearChunkBit(dev, block, page);
8846 -
8847 - bi->pagesInUse--;
8848 -
8849 - if (bi->pagesInUse == 0 &&
8850 - !bi->hasShrinkHeader &&
8851 - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
8852 - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
8853 - yaffs_BlockBecameDirty(dev, block);
8854 - }
8855 -
8856 - }
8857 -
8858 -}
8859 -
8860 -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
8861 - const __u8 *buffer, int nBytes,
8862 - int useReserve)
8863 -{
8864 - /* Find old chunk Need to do this to get serial number
8865 - * Write new one and patch into tree.
8866 - * Invalidate old tags.
8867 - */
8868 -
8869 - int prevChunkId;
8870 - yaffs_ExtendedTags prevTags;
8871 -
8872 - int newChunkId;
8873 - yaffs_ExtendedTags newTags;
8874 -
8875 - yaffs_Device *dev = in->myDev;
8876 -
8877 - yaffs_CheckGarbageCollection(dev);
8878 -
8879 - /* Get the previous chunk at this location in the file if it exists */
8880 - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
8881 -
8882 - /* Set up new tags */
8883 - yaffs_InitialiseTags(&newTags);
8884 -
8885 - newTags.chunkId = chunkInInode;
8886 - newTags.objectId = in->objectId;
8887 - newTags.serialNumber =
8888 - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
8889 - newTags.byteCount = nBytes;
8890 -
8891 - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
8892 - T(YAFFS_TRACE_ERROR,
8893 - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
8894 - YBUG();
8895 - }
8896 -
8897 - newChunkId =
8898 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
8899 - useReserve);
8900 -
8901 - if (newChunkId >= 0) {
8902 - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
8903 -
8904 - if (prevChunkId >= 0)
8905 - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
8906 -
8907 - yaffs_CheckFileSanity(in);
8908 - }
8909 - return newChunkId;
8910 -
8911 -}
8912 -
8913 -/* UpdateObjectHeader updates the header on NAND for an object.
8914 - * If name is not NULL, then that new name is used.
8915 - */
8916 -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
8917 - int isShrink, int shadows)
8918 -{
8919 -
8920 - yaffs_BlockInfo *bi;
8921 -
8922 - yaffs_Device *dev = in->myDev;
8923 -
8924 - int prevChunkId;
8925 - int retVal = 0;
8926 - int result = 0;
8927 -
8928 - int newChunkId;
8929 - yaffs_ExtendedTags newTags;
8930 - yaffs_ExtendedTags oldTags;
8931 -
8932 - __u8 *buffer = NULL;
8933 - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
8934 -
8935 - yaffs_ObjectHeader *oh = NULL;
8936 + yaffs_obj_t *in;
8937 + YCHAR *str = NULL;
8938
8939 - yaffs_strcpy(oldName, _Y("silly old name"));
8940 + yaffs_dev_t *dev = parent->my_dev;
8941
8942 + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
8943 + if (yaffs_find_by_name(parent, name))
8944 + return NULL;
8945
8946 - if (!in->fake ||
8947 - in == dev->rootDir || /* The rootDir should also be saved */
8948 - force) {
8949 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
8950 + str = yaffs_clone_str(aliasString);
8951 + if (!str)
8952 + return NULL;
8953 + }
8954
8955 - yaffs_CheckGarbageCollection(dev);
8956 - yaffs_CheckObjectDetailsLoaded(in);
8957 + in = yaffs_new_obj(dev, -1, type);
8958
8959 - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
8960 - oh = (yaffs_ObjectHeader *) buffer;
8961 + if (!in){
8962 + if(str)
8963 + YFREE(str);
8964 + return NULL;
8965 + }
8966
8967 - prevChunkId = in->hdrChunk;
8968
8969 - if (prevChunkId > 0) {
8970 - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
8971 - buffer, &oldTags);
8972
8973 - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
8974
8975 - memcpy(oldName, oh->name, sizeof(oh->name));
8976 - }
8977
8978 - memset(buffer, 0xFF, dev->nDataBytesPerChunk);
8979 + if (in) {
8980 + in->hdr_chunk = 0;
8981 + in->valid = 1;
8982 + in->variant_type = type;
8983
8984 - oh->type = in->variantType;
8985 - oh->yst_mode = in->yst_mode;
8986 - oh->shadowsObject = oh->inbandShadowsObject = shadows;
8987 + in->yst_mode = mode;
8988
8989 #ifdef CONFIG_YAFFS_WINCE
8990 - oh->win_atime[0] = in->win_atime[0];
8991 - oh->win_ctime[0] = in->win_ctime[0];
8992 - oh->win_mtime[0] = in->win_mtime[0];
8993 - oh->win_atime[1] = in->win_atime[1];
8994 - oh->win_ctime[1] = in->win_ctime[1];
8995 - oh->win_mtime[1] = in->win_mtime[1];
8996 + yfsd_win_file_time_now(in->win_atime);
8997 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
8998 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
8999 +
9000 #else
9001 - oh->yst_uid = in->yst_uid;
9002 - oh->yst_gid = in->yst_gid;
9003 - oh->yst_atime = in->yst_atime;
9004 - oh->yst_mtime = in->yst_mtime;
9005 - oh->yst_ctime = in->yst_ctime;
9006 - oh->yst_rdev = in->yst_rdev;
9007 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
9008 +
9009 + in->yst_rdev = rdev;
9010 + in->yst_uid = uid;
9011 + in->yst_gid = gid;
9012 #endif
9013 - if (in->parent)
9014 - oh->parentObjectId = in->parent->objectId;
9015 - else
9016 - oh->parentObjectId = 0;
9017 + in->n_data_chunks = 0;
9018
9019 - if (name && *name) {
9020 - memset(oh->name, 0, sizeof(oh->name));
9021 - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
9022 - } else if (prevChunkId >= 0)
9023 - memcpy(oh->name, oldName, sizeof(oh->name));
9024 - else
9025 - memset(oh->name, 0, sizeof(oh->name));
9026 + yaffs_set_obj_name(in, name);
9027 + in->dirty = 1;
9028
9029 - oh->isShrink = isShrink;
9030 + yaffs_add_obj_to_dir(parent, in);
9031
9032 - switch (in->variantType) {
9033 - case YAFFS_OBJECT_TYPE_UNKNOWN:
9034 - /* Should not happen */
9035 - break;
9036 - case YAFFS_OBJECT_TYPE_FILE:
9037 - oh->fileSize =
9038 - (oh->parentObjectId == YAFFS_OBJECTID_DELETED
9039 - || oh->parentObjectId ==
9040 - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
9041 - fileVariant.fileSize;
9042 + in->my_dev = parent->my_dev;
9043 +
9044 + switch (type) {
9045 + case YAFFS_OBJECT_TYPE_SYMLINK:
9046 + in->variant.symlink_variant.alias = str;
9047 break;
9048 case YAFFS_OBJECT_TYPE_HARDLINK:
9049 - oh->equivalentObjectId =
9050 - in->variant.hardLinkVariant.equivalentObjectId;
9051 - break;
9052 - case YAFFS_OBJECT_TYPE_SPECIAL:
9053 - /* Do nothing */
9054 + in->variant.hardlink_variant.equiv_obj =
9055 + equiv_obj;
9056 + in->variant.hardlink_variant.equiv_id =
9057 + equiv_obj->obj_id;
9058 + ylist_add(&in->hard_links, &equiv_obj->hard_links);
9059 break;
9060 + case YAFFS_OBJECT_TYPE_FILE:
9061 case YAFFS_OBJECT_TYPE_DIRECTORY:
9062 - /* Do nothing */
9063 - break;
9064 - case YAFFS_OBJECT_TYPE_SYMLINK:
9065 - yaffs_strncpy(oh->alias,
9066 - in->variant.symLinkVariant.alias,
9067 - YAFFS_MAX_ALIAS_LENGTH);
9068 - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
9069 + case YAFFS_OBJECT_TYPE_SPECIAL:
9070 + case YAFFS_OBJECT_TYPE_UNKNOWN:
9071 + /* do nothing */
9072 break;
9073 }
9074
9075 - /* Tags */
9076 - yaffs_InitialiseTags(&newTags);
9077 - in->serial++;
9078 - newTags.chunkId = 0;
9079 - newTags.objectId = in->objectId;
9080 - newTags.serialNumber = in->serial;
9081 -
9082 - /* Add extra info for file header */
9083 -
9084 - newTags.extraHeaderInfoAvailable = 1;
9085 - newTags.extraParentObjectId = oh->parentObjectId;
9086 - newTags.extraFileLength = oh->fileSize;
9087 - newTags.extraIsShrinkHeader = oh->isShrink;
9088 - newTags.extraEquivalentObjectId = oh->equivalentObjectId;
9089 - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
9090 - newTags.extraObjectType = in->variantType;
9091 -
9092 - yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
9093 -
9094 - /* Create new chunk in NAND */
9095 - newChunkId =
9096 - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
9097 - (prevChunkId >= 0) ? 1 : 0);
9098 -
9099 - if (newChunkId >= 0) {
9100 -
9101 - in->hdrChunk = newChunkId;
9102 -
9103 - if (prevChunkId >= 0) {
9104 - yaffs_DeleteChunk(dev, prevChunkId, 1,
9105 - __LINE__);
9106 - }
9107 -
9108 - if (!yaffs_ObjectHasCachedWriteData(in))
9109 - in->dirty = 0;
9110 -
9111 - /* If this was a shrink, then mark the block that the chunk lives on */
9112 - if (isShrink) {
9113 - bi = yaffs_GetBlockInfo(in->myDev,
9114 - newChunkId / in->myDev->nChunksPerBlock);
9115 - bi->hasShrinkHeader = 1;
9116 - }
9117 -
9118 + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
9119 + /* Could not create the object header, fail the creation */
9120 + yaffs_del_obj(in);
9121 + in = NULL;
9122 }
9123
9124 - retVal = newChunkId;
9125 -
9126 + yaffs_update_parent(parent);
9127 }
9128
9129 - if (buffer)
9130 - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
9131 -
9132 - return retVal;
9133 + return in;
9134 }
9135
9136 -/*------------------------ Short Operations Cache ----------------------------------------
9137 - * In many situations where there is no high level buffering (eg WinCE) a lot of
9138 - * reads might be short sequential reads, and a lot of writes may be short
9139 - * sequential writes. eg. scanning/writing a jpeg file.
9140 - * In these cases, a short read/write cache can provide a huge perfomance benefit
9141 - * with dumb-as-a-rock code.
9142 - * In Linux, the page cache provides read buffering aand the short op cache provides write
9143 - * buffering.
9144 - *
9145 - * There are a limited number (~10) of cache chunks per device so that we don't
9146 - * need a very intelligent search.
9147 - */
9148 -
9149 -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
9150 +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
9151 + __u32 mode, __u32 uid, __u32 gid)
9152 {
9153 - yaffs_Device *dev = obj->myDev;
9154 - int i;
9155 - yaffs_ChunkCache *cache;
9156 - int nCaches = obj->myDev->nShortOpCaches;
9157 -
9158 - for (i = 0; i < nCaches; i++) {
9159 - cache = &dev->srCache[i];
9160 - if (cache->object == obj &&
9161 - cache->dirty)
9162 - return 1;
9163 - }
9164 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
9165 + uid, gid, NULL, NULL, 0);
9166 +}
9167
9168 - return 0;
9169 +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
9170 + __u32 mode, __u32 uid, __u32 gid)
9171 +{
9172 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
9173 + mode, uid, gid, NULL, NULL, 0);
9174 }
9175
9176 +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
9177 + __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
9178 +{
9179 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
9180 + uid, gid, NULL, NULL, rdev);
9181 +}
9182
9183 -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
9184 +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
9185 + __u32 mode, __u32 uid, __u32 gid,
9186 + const YCHAR *alias)
9187 {
9188 - yaffs_Device *dev = obj->myDev;
9189 - int lowest = -99; /* Stop compiler whining. */
9190 - int i;
9191 - yaffs_ChunkCache *cache;
9192 - int chunkWritten = 0;
9193 - int nCaches = obj->myDev->nShortOpCaches;
9194 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
9195 + uid, gid, NULL, alias, 0);
9196 +}
9197
9198 - if (nCaches > 0) {
9199 - do {
9200 - cache = NULL;
9201 +/* yaffs_link_obj returns the object id of the equivalent object.*/
9202 +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
9203 + yaffs_obj_t *equiv_obj)
9204 +{
9205 + /* Get the real object in case we were fed a hard link as an equivalent object */
9206 + equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
9207
9208 - /* Find the dirty cache for this object with the lowest chunk id. */
9209 - for (i = 0; i < nCaches; i++) {
9210 - if (dev->srCache[i].object == obj &&
9211 - dev->srCache[i].dirty) {
9212 - if (!cache
9213 - || dev->srCache[i].chunkId <
9214 - lowest) {
9215 - cache = &dev->srCache[i];
9216 - lowest = cache->chunkId;
9217 - }
9218 - }
9219 - }
9220 + if (yaffs_create_obj
9221 + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
9222 + equiv_obj, NULL, 0)) {
9223 + return equiv_obj;
9224 + } else {
9225 + return NULL;
9226 + }
9227
9228 - if (cache && !cache->locked) {
9229 - /* Write it out and free it up */
9230 +}
9231
9232 - chunkWritten =
9233 - yaffs_WriteChunkDataToObject(cache->object,
9234 - cache->chunkId,
9235 - cache->data,
9236 - cache->nBytes,
9237 - 1);
9238 - cache->dirty = 0;
9239 - cache->object = NULL;
9240 - }
9241 +static int yaffs_change_obj_name(yaffs_obj_t *obj, yaffs_obj_t *new_dir,
9242 + const YCHAR *new_name, int force, int shadows)
9243 +{
9244 + int unlinkOp;
9245 + int deleteOp;
9246
9247 - } while (cache && chunkWritten > 0);
9248 + yaffs_obj_t *existingTarget;
9249
9250 - if (cache) {
9251 - /* Hoosterman, disk full while writing cache out. */
9252 - T(YAFFS_TRACE_ERROR,
9253 - (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
9254 + if (new_dir == NULL)
9255 + new_dir = obj->parent; /* use the old directory */
9256
9257 - }
9258 + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
9259 + T(YAFFS_TRACE_ALWAYS,
9260 + (TSTR
9261 + ("tragedy: yaffs_change_obj_name: new_dir is not a directory"
9262 + TENDSTR)));
9263 + YBUG();
9264 }
9265
9266 -}
9267 + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
9268 + if (obj->my_dev->param.is_yaffs2)
9269 + unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
9270 + else
9271 + unlinkOp = (new_dir == obj->my_dev->unlinked_dir
9272 + && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
9273
9274 -/*yaffs_FlushEntireDeviceCache(dev)
9275 - *
9276 - *
9277 - */
9278 + deleteOp = (new_dir == obj->my_dev->del_dir);
9279
9280 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
9281 -{
9282 - yaffs_Object *obj;
9283 - int nCaches = dev->nShortOpCaches;
9284 - int i;
9285 + existingTarget = yaffs_find_by_name(new_dir, new_name);
9286
9287 - /* Find a dirty object in the cache and flush it...
9288 - * until there are no further dirty objects.
9289 + /* If the object is a file going into the unlinked directory,
9290 + * then it is OK to just stuff it in since duplicate names are allowed.
9291 + * else only proceed if the new name does not exist and if we're putting
9292 + * it into a directory.
9293 */
9294 - do {
9295 - obj = NULL;
9296 - for (i = 0; i < nCaches && !obj; i++) {
9297 - if (dev->srCache[i].object &&
9298 - dev->srCache[i].dirty)
9299 - obj = dev->srCache[i].object;
9300 -
9301 - }
9302 - if (obj)
9303 - yaffs_FlushFilesChunkCache(obj);
9304 -
9305 - } while (obj);
9306 -
9307 -}
9308 + if ((unlinkOp ||
9309 + deleteOp ||
9310 + force ||
9311 + (shadows > 0) ||
9312 + !existingTarget) &&
9313 + new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
9314 + yaffs_set_obj_name(obj, new_name);
9315 + obj->dirty = 1;
9316
9317 + yaffs_add_obj_to_dir(new_dir, obj);
9318
9319 -/* Grab us a cache chunk for use.
9320 - * First look for an empty one.
9321 - * Then look for the least recently used non-dirty one.
9322 - * Then look for the least recently used dirty one...., flush and look again.
9323 - */
9324 -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
9325 -{
9326 - int i;
9327 + if (unlinkOp)
9328 + obj->unlinked = 1;
9329
9330 - if (dev->nShortOpCaches > 0) {
9331 - for (i = 0; i < dev->nShortOpCaches; i++) {
9332 - if (!dev->srCache[i].object)
9333 - return &dev->srCache[i];
9334 - }
9335 + /* If it is a deletion then we mark it as a shrink for gc purposes. */
9336 + if (yaffs_update_oh(obj, new_name, 0, deleteOp, shadows, NULL) >= 0)
9337 + return YAFFS_OK;
9338 }
9339
9340 - return NULL;
9341 + return YAFFS_FAIL;
9342 }
9343
9344 -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
9345 +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
9346 + yaffs_obj_t *new_dir, const YCHAR *new_name)
9347 {
9348 - yaffs_ChunkCache *cache;
9349 - yaffs_Object *theObj;
9350 - int usage;
9351 - int i;
9352 - int pushout;
9353 -
9354 - if (dev->nShortOpCaches > 0) {
9355 - /* Try find a non-dirty one... */
9356 -
9357 - cache = yaffs_GrabChunkCacheWorker(dev);
9358 + yaffs_obj_t *obj = NULL;
9359 + yaffs_obj_t *existingTarget = NULL;
9360 + int force = 0;
9361 + int result;
9362 + yaffs_dev_t *dev;
9363
9364 - if (!cache) {
9365 - /* They were all dirty, find the last recently used object and flush
9366 - * its cache, then find again.
9367 - * NB what's here is not very accurate, we actually flush the object
9368 - * the last recently used page.
9369 - */
9370
9371 - /* With locking we can't assume we can use entry zero */
9372 + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
9373 + YBUG();
9374 + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
9375 + YBUG();
9376
9377 - theObj = NULL;
9378 - usage = -1;
9379 - cache = NULL;
9380 - pushout = -1;
9381 + dev = old_dir->my_dev;
9382
9383 - for (i = 0; i < dev->nShortOpCaches; i++) {
9384 - if (dev->srCache[i].object &&
9385 - !dev->srCache[i].locked &&
9386 - (dev->srCache[i].lastUse < usage || !cache)) {
9387 - usage = dev->srCache[i].lastUse;
9388 - theObj = dev->srCache[i].object;
9389 - cache = &dev->srCache[i];
9390 - pushout = i;
9391 - }
9392 - }
9393 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
9394 + /* Special case for case insemsitive systems (eg. WinCE).
9395 + * While look-up is case insensitive, the name isn't.
9396 + * Therefore we might want to change x.txt to X.txt
9397 + */
9398 + if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0)
9399 + force = 1;
9400 +#endif
9401
9402 - if (!cache || cache->dirty) {
9403 - /* Flush and try again */
9404 - yaffs_FlushFilesChunkCache(theObj);
9405 - cache = yaffs_GrabChunkCacheWorker(dev);
9406 - }
9407 + if(yaffs_strnlen(new_name,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
9408 + /* ENAMETOOLONG */
9409 + return YAFFS_FAIL;
9410
9411 - }
9412 - return cache;
9413 - } else
9414 - return NULL;
9415 + obj = yaffs_find_by_name(old_dir, old_name);
9416
9417 -}
9418 + if (obj && obj->rename_allowed) {
9419
9420 -/* Find a cached chunk */
9421 -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
9422 - int chunkId)
9423 -{
9424 - yaffs_Device *dev = obj->myDev;
9425 - int i;
9426 - if (dev->nShortOpCaches > 0) {
9427 - for (i = 0; i < dev->nShortOpCaches; i++) {
9428 - if (dev->srCache[i].object == obj &&
9429 - dev->srCache[i].chunkId == chunkId) {
9430 - dev->cacheHits++;
9431 + /* Now do the handling for an existing target, if there is one */
9432
9433 - return &dev->srCache[i];
9434 - }
9435 + existingTarget = yaffs_find_by_name(new_dir, new_name);
9436 + if (existingTarget &&
9437 + existingTarget->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
9438 + !ylist_empty(&existingTarget->variant.dir_variant.children)) {
9439 + /* There is a target that is a non-empty directory, so we fail */
9440 + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
9441 + } else if (existingTarget && existingTarget != obj) {
9442 + /* Nuke the target first, using shadowing,
9443 + * but only if it isn't the same object.
9444 + *
9445 + * Note we must disable gc otherwise it can mess up the shadowing.
9446 + *
9447 + */
9448 + dev->gc_disable=1;
9449 + yaffs_change_obj_name(obj, new_dir, new_name, force,
9450 + existingTarget->obj_id);
9451 + existingTarget->is_shadowed = 1;
9452 + yaffs_unlink_obj(existingTarget);
9453 + dev->gc_disable=0;
9454 }
9455 +
9456 + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
9457 +
9458 + yaffs_update_parent(old_dir);
9459 + if(new_dir != old_dir)
9460 + yaffs_update_parent(new_dir);
9461 +
9462 + return result;
9463 }
9464 - return NULL;
9465 + return YAFFS_FAIL;
9466 }
9467
9468 -/* Mark the chunk for the least recently used algorithym */
9469 -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
9470 - int isAWrite)
9471 +/*------------------------- Block Management and Page Allocation ----------------*/
9472 +
9473 +static int yaffs_init_blocks(yaffs_dev_t *dev)
9474 {
9475 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
9476
9477 - if (dev->nShortOpCaches > 0) {
9478 - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
9479 - /* Reset the cache usages */
9480 - int i;
9481 - for (i = 1; i < dev->nShortOpCaches; i++)
9482 - dev->srCache[i].lastUse = 0;
9483 + dev->block_info = NULL;
9484 + dev->chunk_bits = NULL;
9485
9486 - dev->srLastUse = 0;
9487 - }
9488 + dev->alloc_block = -1; /* force it to get a new one */
9489
9490 - dev->srLastUse++;
9491 + /* If the first allocation strategy fails, thry the alternate one */
9492 + dev->block_info = YMALLOC(nBlocks * sizeof(yaffs_block_info_t));
9493 + if (!dev->block_info) {
9494 + dev->block_info = YMALLOC_ALT(nBlocks * sizeof(yaffs_block_info_t));
9495 + dev->block_info_alt = 1;
9496 + } else
9497 + dev->block_info_alt = 0;
9498
9499 - cache->lastUse = dev->srLastUse;
9500 + if (dev->block_info) {
9501 + /* Set up dynamic blockinfo stuff. */
9502 + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; /* round up bytes */
9503 + dev->chunk_bits = YMALLOC(dev->chunk_bit_stride * nBlocks);
9504 + if (!dev->chunk_bits) {
9505 + dev->chunk_bits = YMALLOC_ALT(dev->chunk_bit_stride * nBlocks);
9506 + dev->chunk_bits_alt = 1;
9507 + } else
9508 + dev->chunk_bits_alt = 0;
9509 + }
9510
9511 - if (isAWrite)
9512 - cache->dirty = 1;
9513 + if (dev->block_info && dev->chunk_bits) {
9514 + memset(dev->block_info, 0, nBlocks * sizeof(yaffs_block_info_t));
9515 + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * nBlocks);
9516 + return YAFFS_OK;
9517 }
9518 +
9519 + return YAFFS_FAIL;
9520 }
9521
9522 -/* Invalidate a single cache page.
9523 - * Do this when a whole page gets written,
9524 - * ie the short cache for this page is no longer valid.
9525 - */
9526 -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
9527 +static void yaffs_deinit_blocks(yaffs_dev_t *dev)
9528 {
9529 - if (object->myDev->nShortOpCaches > 0) {
9530 - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
9531 + if (dev->block_info_alt && dev->block_info)
9532 + YFREE_ALT(dev->block_info);
9533 + else if (dev->block_info)
9534 + YFREE(dev->block_info);
9535
9536 - if (cache)
9537 - cache->object = NULL;
9538 - }
9539 -}
9540 + dev->block_info_alt = 0;
9541
9542 -/* Invalidate all the cache pages associated with this object
9543 - * Do this whenever ther file is deleted or resized.
9544 - */
9545 -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
9546 -{
9547 - int i;
9548 - yaffs_Device *dev = in->myDev;
9549 + dev->block_info = NULL;
9550
9551 - if (dev->nShortOpCaches > 0) {
9552 - /* Invalidate it. */
9553 - for (i = 0; i < dev->nShortOpCaches; i++) {
9554 - if (dev->srCache[i].object == in)
9555 - dev->srCache[i].object = NULL;
9556 - }
9557 - }
9558 + if (dev->chunk_bits_alt && dev->chunk_bits)
9559 + YFREE_ALT(dev->chunk_bits);
9560 + else if (dev->chunk_bits)
9561 + YFREE(dev->chunk_bits);
9562 + dev->chunk_bits_alt = 0;
9563 + dev->chunk_bits = NULL;
9564 }
9565
9566 -/*--------------------- Checkpointing --------------------*/
9567 +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no)
9568 +{
9569 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block_no);
9570
9571 + int erasedOk = 0;
9572
9573 -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
9574 -{
9575 - yaffs_CheckpointValidity cp;
9576 + /* If the block is still healthy erase it and mark as clean.
9577 + * If the block has had a data failure, then retire it.
9578 + */
9579
9580 - memset(&cp, 0, sizeof(cp));
9581 + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
9582 + (TSTR("yaffs_block_became_dirty block %d state %d %s"TENDSTR),
9583 + block_no, bi->block_state, (bi->needs_retiring) ? "needs retiring" : ""));
9584
9585 - cp.structType = sizeof(cp);
9586 - cp.magic = YAFFS_MAGIC;
9587 - cp.version = YAFFS_CHECKPOINT_VERSION;
9588 - cp.head = (head) ? 1 : 0;
9589 + yaffs2_clear_oldest_dirty_seq(dev,bi);
9590
9591 - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
9592 - 1 : 0;
9593 -}
9594 + bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
9595
9596 -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
9597 -{
9598 - yaffs_CheckpointValidity cp;
9599 - int ok;
9600 + /* If this is the block being garbage collected then stop gc'ing this block */
9601 + if(block_no == dev->gc_block)
9602 + dev->gc_block = 0;
9603
9604 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9605 + /* If this block is currently the best candidate for gc then drop as a candidate */
9606 + if(block_no == dev->gc_dirtiest){
9607 + dev->gc_dirtiest = 0;
9608 + dev->gc_pages_in_use = 0;
9609 + }
9610
9611 - if (ok)
9612 - ok = (cp.structType == sizeof(cp)) &&
9613 - (cp.magic == YAFFS_MAGIC) &&
9614 - (cp.version == YAFFS_CHECKPOINT_VERSION) &&
9615 - (cp.head == ((head) ? 1 : 0));
9616 - return ok ? 1 : 0;
9617 -}
9618 + if (!bi->needs_retiring) {
9619 + yaffs2_checkpt_invalidate(dev);
9620 + erasedOk = yaffs_erase_block(dev, block_no);
9621 + if (!erasedOk) {
9622 + dev->n_erase_failures++;
9623 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9624 + (TSTR("**>> Erasure failed %d" TENDSTR), block_no));
9625 + }
9626 + }
9627
9628 -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
9629 - yaffs_Device *dev)
9630 -{
9631 - cp->nErasedBlocks = dev->nErasedBlocks;
9632 - cp->allocationBlock = dev->allocationBlock;
9633 - cp->allocationPage = dev->allocationPage;
9634 - cp->nFreeChunks = dev->nFreeChunks;
9635 + if (erasedOk &&
9636 + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || !yaffs_skip_verification(dev))) {
9637 + int i;
9638 + for (i = 0; i < dev->param.chunks_per_block; i++) {
9639 + if (!yaffs_check_chunk_erased
9640 + (dev, block_no * dev->param.chunks_per_block + i)) {
9641 + T(YAFFS_TRACE_ERROR,
9642 + (TSTR
9643 + (">>Block %d erasure supposedly OK, but chunk %d not erased"
9644 + TENDSTR), block_no, i));
9645 + }
9646 + }
9647 + }
9648 +
9649 + if (erasedOk) {
9650 + /* Clean it up... */
9651 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
9652 + bi->seq_number = 0;
9653 + dev->n_erased_blocks++;
9654 + bi->pages_in_use = 0;
9655 + bi->soft_del_pages = 0;
9656 + bi->has_shrink_hdr = 0;
9657 + bi->skip_erased_check = 1; /* This is clean, so no need to check */
9658 + bi->gc_prioritise = 0;
9659 + yaffs_clear_chunk_bits(dev, block_no);
9660
9661 - cp->nDeletedFiles = dev->nDeletedFiles;
9662 - cp->nUnlinkedFiles = dev->nUnlinkedFiles;
9663 - cp->nBackgroundDeletions = dev->nBackgroundDeletions;
9664 - cp->sequenceNumber = dev->sequenceNumber;
9665 - cp->oldestDirtySequence = dev->oldestDirtySequence;
9666 + T(YAFFS_TRACE_ERASE,
9667 + (TSTR("Erased block %d" TENDSTR), block_no));
9668 + } else {
9669 + dev->n_free_chunks -= dev->param.chunks_per_block; /* We lost a block of free space */
9670
9671 + yaffs_retire_block(dev, block_no);
9672 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9673 + (TSTR("**>> Block %d retired" TENDSTR), block_no));
9674 + }
9675 }
9676
9677 -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
9678 - yaffs_CheckpointDevice *cp)
9679 +static int yaffs_find_alloc_block(yaffs_dev_t *dev)
9680 {
9681 - dev->nErasedBlocks = cp->nErasedBlocks;
9682 - dev->allocationBlock = cp->allocationBlock;
9683 - dev->allocationPage = cp->allocationPage;
9684 - dev->nFreeChunks = cp->nFreeChunks;
9685 -
9686 - dev->nDeletedFiles = cp->nDeletedFiles;
9687 - dev->nUnlinkedFiles = cp->nUnlinkedFiles;
9688 - dev->nBackgroundDeletions = cp->nBackgroundDeletions;
9689 - dev->sequenceNumber = cp->sequenceNumber;
9690 - dev->oldestDirtySequence = cp->oldestDirtySequence;
9691 -}
9692 + int i;
9693
9694 + yaffs_block_info_t *bi;
9695
9696 -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
9697 -{
9698 - yaffs_CheckpointDevice cp;
9699 - __u32 nBytes;
9700 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9701 + if (dev->n_erased_blocks < 1) {
9702 + /* Hoosterman we've got a problem.
9703 + * Can't get space to gc
9704 + */
9705 + T(YAFFS_TRACE_ERROR,
9706 + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
9707
9708 - int ok;
9709 + return -1;
9710 + }
9711
9712 - /* Write device runtime values*/
9713 - yaffs_DeviceToCheckpointDevice(&cp, dev);
9714 - cp.structType = sizeof(cp);
9715 + /* Find an empty block. */
9716
9717 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
9718 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
9719 + dev->alloc_block_finder++;
9720 + if (dev->alloc_block_finder < dev->internal_start_block
9721 + || dev->alloc_block_finder > dev->internal_end_block) {
9722 + dev->alloc_block_finder = dev->internal_start_block;
9723 + }
9724
9725 - /* Write block info */
9726 - if (ok) {
9727 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9728 - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
9729 + bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
9730 +
9731 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
9732 + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
9733 + dev->seq_number++;
9734 + bi->seq_number = dev->seq_number;
9735 + dev->n_erased_blocks--;
9736 + T(YAFFS_TRACE_ALLOCATE,
9737 + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
9738 + dev->alloc_block_finder, dev->seq_number,
9739 + dev->n_erased_blocks));
9740 + return dev->alloc_block_finder;
9741 + }
9742 }
9743
9744 - /* Write chunk bits */
9745 - if (ok) {
9746 - nBytes = nBlocks * dev->chunkBitmapStride;
9747 - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
9748 - }
9749 - return ok ? 1 : 0;
9750 + T(YAFFS_TRACE_ALWAYS,
9751 + (TSTR
9752 + ("yaffs tragedy: no more erased blocks, but there should have been %d"
9753 + TENDSTR), dev->n_erased_blocks));
9754
9755 + return -1;
9756 }
9757
9758 -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
9759 +
9760 +/*
9761 + * Check if there's space to allocate...
9762 + * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()?
9763 + */
9764 +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks)
9765 {
9766 - yaffs_CheckpointDevice cp;
9767 - __u32 nBytes;
9768 - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
9769 + int reservedChunks;
9770 + int reservedBlocks = dev->param.n_reserved_blocks;
9771 + int checkpointBlocks;
9772
9773 - int ok;
9774 + checkpointBlocks = yaffs_calc_checkpt_blocks_required(dev);
9775
9776 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
9777 - if (!ok)
9778 - return 0;
9779 + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.chunks_per_block);
9780
9781 - if (cp.structType != sizeof(cp))
9782 - return 0;
9783 + return (dev->n_free_chunks > (reservedChunks + n_chunks));
9784 +}
9785 +
9786 +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
9787 + yaffs_block_info_t **blockUsedPtr)
9788 +{
9789 + int retVal;
9790 + yaffs_block_info_t *bi;
9791 +
9792 + if (dev->alloc_block < 0) {
9793 + /* Get next block to allocate off */
9794 + dev->alloc_block = yaffs_find_alloc_block(dev);
9795 + dev->alloc_page = 0;
9796 + }
9797
9798 + if (!useReserve && !yaffs_check_alloc_available(dev, 1)) {
9799 + /* Not enough space to allocate unless we're allowed to use the reserve. */
9800 + return -1;
9801 + }
9802
9803 - yaffs_CheckpointDeviceToDevice(dev, &cp);
9804 + if (dev->n_erased_blocks < dev->param.n_reserved_blocks
9805 + && dev->alloc_page == 0) {
9806 + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
9807 + }
9808
9809 - nBytes = nBlocks * sizeof(yaffs_BlockInfo);
9810 + /* Next page please.... */
9811 + if (dev->alloc_block >= 0) {
9812 + bi = yaffs_get_block_info(dev, dev->alloc_block);
9813
9814 - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
9815 + retVal = (dev->alloc_block * dev->param.chunks_per_block) +
9816 + dev->alloc_page;
9817 + bi->pages_in_use++;
9818 + yaffs_set_chunk_bit(dev, dev->alloc_block,
9819 + dev->alloc_page);
9820
9821 - if (!ok)
9822 - return 0;
9823 - nBytes = nBlocks * dev->chunkBitmapStride;
9824 + dev->alloc_page++;
9825
9826 - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
9827 + dev->n_free_chunks--;
9828
9829 - return ok ? 1 : 0;
9830 -}
9831 + /* If the block is full set the state to full */
9832 + if (dev->alloc_page >= dev->param.chunks_per_block) {
9833 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
9834 + dev->alloc_block = -1;
9835 + }
9836
9837 -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
9838 - yaffs_Object *obj)
9839 -{
9840 + if (blockUsedPtr)
9841 + *blockUsedPtr = bi;
9842 +
9843 + return retVal;
9844 + }
9845
9846 - cp->objectId = obj->objectId;
9847 - cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
9848 - cp->hdrChunk = obj->hdrChunk;
9849 - cp->variantType = obj->variantType;
9850 - cp->deleted = obj->deleted;
9851 - cp->softDeleted = obj->softDeleted;
9852 - cp->unlinked = obj->unlinked;
9853 - cp->fake = obj->fake;
9854 - cp->renameAllowed = obj->renameAllowed;
9855 - cp->unlinkAllowed = obj->unlinkAllowed;
9856 - cp->serial = obj->serial;
9857 - cp->nDataChunks = obj->nDataChunks;
9858 + T(YAFFS_TRACE_ERROR,
9859 + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
9860
9861 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9862 - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
9863 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9864 - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
9865 + return -1;
9866 }
9867
9868 -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
9869 +static int yaffs_get_erased_chunks(yaffs_dev_t *dev)
9870 {
9871 + int n;
9872
9873 - yaffs_Object *parent;
9874 + n = dev->n_erased_blocks * dev->param.chunks_per_block;
9875
9876 - if (obj->variantType != cp->variantType) {
9877 - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
9878 - TCONT("chunk %d does not match existing object type %d")
9879 - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
9880 - obj->variantType));
9881 - return 0;
9882 - }
9883 + if (dev->alloc_block > 0)
9884 + n += (dev->param.chunks_per_block - dev->alloc_page);
9885
9886 - obj->objectId = cp->objectId;
9887 + return n;
9888
9889 - if (cp->parentId)
9890 - parent = yaffs_FindOrCreateObjectByNumber(
9891 - obj->myDev,
9892 - cp->parentId,
9893 - YAFFS_OBJECT_TYPE_DIRECTORY);
9894 - else
9895 - parent = NULL;
9896 +}
9897
9898 - if (parent) {
9899 - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
9900 - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
9901 - TCONT(" chunk %d Parent type, %d, not directory")
9902 - TENDSTR),
9903 - cp->objectId, cp->parentId, cp->variantType,
9904 - cp->hdrChunk, parent->variantType));
9905 - return 0;
9906 +/*
9907 + * yaffs_skip_rest_of_block() skips over the rest of the allocation block
9908 + * if we don't want to write to it.
9909 + */
9910 +void yaffs_skip_rest_of_block(yaffs_dev_t *dev)
9911 +{
9912 + if(dev->alloc_block > 0){
9913 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->alloc_block);
9914 + if(bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING){
9915 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
9916 + dev->alloc_block = -1;
9917 }
9918 - yaffs_AddObjectToDirectory(parent, obj);
9919 }
9920 -
9921 - obj->hdrChunk = cp->hdrChunk;
9922 - obj->variantType = cp->variantType;
9923 - obj->deleted = cp->deleted;
9924 - obj->softDeleted = cp->softDeleted;
9925 - obj->unlinked = cp->unlinked;
9926 - obj->fake = cp->fake;
9927 - obj->renameAllowed = cp->renameAllowed;
9928 - obj->unlinkAllowed = cp->unlinkAllowed;
9929 - obj->serial = cp->serial;
9930 - obj->nDataChunks = cp->nDataChunks;
9931 -
9932 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
9933 - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
9934 - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
9935 - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
9936 -
9937 - if (obj->hdrChunk > 0)
9938 - obj->lazyLoaded = 1;
9939 - return 1;
9940 }
9941
9942
9943 -
9944 -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
9945 - __u32 level, int chunkOffset)
9946 +static int yaffs_gc_block(yaffs_dev_t *dev, int block,
9947 + int wholeBlock)
9948 {
9949 + int oldChunk;
9950 + int newChunk;
9951 + int mark_flash;
9952 + int retVal = YAFFS_OK;
9953 int i;
9954 - yaffs_Device *dev = in->myDev;
9955 - int ok = 1;
9956 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
9957 -
9958 - if (tnodeSize < sizeof(yaffs_Tnode))
9959 - tnodeSize = sizeof(yaffs_Tnode);
9960 + int isCheckpointBlock;
9961 + int matchingChunk;
9962 + int maxCopies;
9963
9964 + int chunksBefore = yaffs_get_erased_chunks(dev);
9965 + int chunksAfter;
9966
9967 - if (tn) {
9968 - if (level > 0) {
9969 + yaffs_ext_tags tags;
9970
9971 - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
9972 - if (tn->internal[i]) {
9973 - ok = yaffs_CheckpointTnodeWorker(in,
9974 - tn->internal[i],
9975 - level - 1,
9976 - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
9977 - }
9978 - }
9979 - } else if (level == 0) {
9980 - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
9981 - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
9982 - if (ok)
9983 - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
9984 - }
9985 - }
9986 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block);
9987
9988 - return ok;
9989 + yaffs_obj_t *object;
9990
9991 -}
9992 + isCheckpointBlock = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
9993
9994 -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
9995 -{
9996 - __u32 endMarker = ~0;
9997 - int ok = 1;
9998
9999 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
10000 - ok = yaffs_CheckpointTnodeWorker(obj,
10001 - obj->variant.fileVariant.top,
10002 - obj->variant.fileVariant.topLevel,
10003 - 0);
10004 - if (ok)
10005 - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
10006 - sizeof(endMarker));
10007 - }
10008 + T(YAFFS_TRACE_TRACING,
10009 + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
10010 + block,
10011 + bi->pages_in_use,
10012 + bi->has_shrink_hdr,
10013 + wholeBlock));
10014
10015 - return ok ? 1 : 0;
10016 -}
10017 + /*yaffs_verify_free_chunks(dev); */
10018
10019 -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
10020 -{
10021 - __u32 baseChunk;
10022 - int ok = 1;
10023 - yaffs_Device *dev = obj->myDev;
10024 - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
10025 - yaffs_Tnode *tn;
10026 - int nread = 0;
10027 - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
10028 + if(bi->block_state == YAFFS_BLOCK_STATE_FULL)
10029 + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
10030 +
10031 + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
10032
10033 - if (tnodeSize < sizeof(yaffs_Tnode))
10034 - tnodeSize = sizeof(yaffs_Tnode);
10035 + dev->gc_disable = 1;
10036
10037 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
10038 + if (isCheckpointBlock ||
10039 + !yaffs_still_some_chunks(dev, block)) {
10040 + T(YAFFS_TRACE_TRACING,
10041 + (TSTR
10042 + ("Collecting block %d that has no chunks in use" TENDSTR),
10043 + block));
10044 + yaffs_block_became_dirty(dev, block);
10045 + } else {
10046
10047 - while (ok && (~baseChunk)) {
10048 - nread++;
10049 - /* Read level 0 tnode */
10050 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
10051
10052 + yaffs_verify_blk(dev, bi, block);
10053
10054 - tn = yaffs_GetTnodeRaw(dev);
10055 - if (tn)
10056 - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
10057 - else
10058 - ok = 0;
10059 + maxCopies = (wholeBlock) ? dev->param.chunks_per_block : 5;
10060 + oldChunk = block * dev->param.chunks_per_block + dev->gc_chunk;
10061
10062 - if (tn && ok)
10063 - ok = yaffs_AddOrFindLevel0Tnode(dev,
10064 - fileStructPtr,
10065 - baseChunk,
10066 - tn) ? 1 : 0;
10067 + for (/* init already done */;
10068 + retVal == YAFFS_OK &&
10069 + dev->gc_chunk < dev->param.chunks_per_block &&
10070 + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
10071 + maxCopies > 0;
10072 + dev->gc_chunk++, oldChunk++) {
10073 + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
10074
10075 - if (ok)
10076 - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
10077 + /* This page is in use and might need to be copied off */
10078
10079 - }
10080 + maxCopies--;
10081
10082 - T(YAFFS_TRACE_CHECKPOINT, (
10083 - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
10084 - nread, baseChunk, ok));
10085 + mark_flash = 1;
10086
10087 - return ok ? 1 : 0;
10088 -}
10089 + yaffs_init_tags(&tags);
10090
10091 + yaffs_rd_chunk_tags_nand(dev, oldChunk,
10092 + buffer, &tags);
10093
10094 -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
10095 -{
10096 - yaffs_Object *obj;
10097 - yaffs_CheckpointObject cp;
10098 - int i;
10099 - int ok = 1;
10100 - struct ylist_head *lh;
10101 + object =
10102 + yaffs_find_by_number(dev,
10103 + tags.obj_id);
10104
10105 + T(YAFFS_TRACE_GC_DETAIL,
10106 + (TSTR
10107 + ("Collecting chunk in block %d, %d %d %d " TENDSTR),
10108 + dev->gc_chunk, tags.obj_id, tags.chunk_id,
10109 + tags.n_bytes));
10110
10111 - /* Iterate through the objects in each hash entry,
10112 - * dumping them to the checkpointing stream.
10113 - */
10114 + if (object && !yaffs_skip_verification(dev)) {
10115 + if (tags.chunk_id == 0)
10116 + matchingChunk = object->hdr_chunk;
10117 + else if (object->soft_del)
10118 + matchingChunk = oldChunk; /* Defeat the test */
10119 + else
10120 + matchingChunk = yaffs_find_chunk_in_file(object, tags.chunk_id, NULL);
10121
10122 - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
10123 - ylist_for_each(lh, &dev->objectBucket[i].list) {
10124 - if (lh) {
10125 - obj = ylist_entry(lh, yaffs_Object, hashLink);
10126 - if (!obj->deferedFree) {
10127 - yaffs_ObjectToCheckpointObject(&cp, obj);
10128 - cp.structType = sizeof(cp);
10129 -
10130 - T(YAFFS_TRACE_CHECKPOINT, (
10131 - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
10132 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
10133 + if (oldChunk != matchingChunk)
10134 + T(YAFFS_TRACE_ERROR,
10135 + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
10136 + oldChunk, matchingChunk, tags.obj_id, tags.chunk_id));
10137
10138 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
10139 + }
10140
10141 - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
10142 - ok = yaffs_WriteCheckpointTnodes(obj);
10143 + if (!object) {
10144 + T(YAFFS_TRACE_ERROR,
10145 + (TSTR
10146 + ("page %d in gc has no object: %d %d %d "
10147 + TENDSTR), oldChunk,
10148 + tags.obj_id, tags.chunk_id, tags.n_bytes));
10149 }
10150 - }
10151 - }
10152 - }
10153
10154 - /* Dump end of list */
10155 - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
10156 - cp.structType = sizeof(cp);
10157 + if (object &&
10158 + object->deleted &&
10159 + object->soft_del &&
10160 + tags.chunk_id != 0) {
10161 + /* Data chunk in a soft deleted file, throw it away
10162 + * It's a soft deleted data chunk,
10163 + * No need to copy this, just forget about it and
10164 + * fix up the object.
10165 + */
10166 +
10167 + /* Free chunks already includes softdeleted chunks.
10168 + * How ever this chunk is going to soon be really deleted
10169 + * which will increment free chunks.
10170 + * We have to decrement free chunks so this works out properly.
10171 + */
10172 + dev->n_free_chunks--;
10173 + bi->soft_del_pages--;
10174 +
10175 + object->n_data_chunks--;
10176
10177 - if (ok)
10178 - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
10179 + if (object->n_data_chunks <= 0) {
10180 + /* remeber to clean up the object */
10181 + dev->gc_cleanup_list[dev->n_clean_ups] =
10182 + tags.obj_id;
10183 + dev->n_clean_ups++;
10184 + }
10185 + mark_flash = 0;
10186 + } else if (0) {
10187 + /* Todo object && object->deleted && object->n_data_chunks == 0 */
10188 + /* Deleted object header with no data chunks.
10189 + * Can be discarded and the file deleted.
10190 + */
10191 + object->hdr_chunk = 0;
10192 + yaffs_free_tnode(object->my_dev,
10193 + object->variant.
10194 + file_variant.top);
10195 + object->variant.file_variant.top = NULL;
10196 + yaffs_generic_obj_del(object);
10197
10198 - return ok ? 1 : 0;
10199 -}
10200 + } else if (object) {
10201 + /* It's either a data chunk in a live file or
10202 + * an ObjectHeader, so we're interested in it.
10203 + * NB Need to keep the ObjectHeaders of deleted files
10204 + * until the whole file has been deleted off
10205 + */
10206 + tags.serial_number++;
10207
10208 -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
10209 -{
10210 - yaffs_Object *obj;
10211 - yaffs_CheckpointObject cp;
10212 - int ok = 1;
10213 - int done = 0;
10214 - yaffs_Object *hardList = NULL;
10215 + dev->n_gc_copies++;
10216
10217 - while (ok && !done) {
10218 - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
10219 - if (cp.structType != sizeof(cp)) {
10220 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
10221 - cp.structType, sizeof(cp), ok));
10222 - ok = 0;
10223 - }
10224 -
10225 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
10226 - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
10227 -
10228 - if (ok && cp.objectId == ~0)
10229 - done = 1;
10230 - else if (ok) {
10231 - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
10232 - if (obj) {
10233 - ok = yaffs_CheckpointObjectToObject(obj, &cp);
10234 - if (!ok)
10235 - break;
10236 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
10237 - ok = yaffs_ReadCheckpointTnodes(obj);
10238 - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
10239 - obj->hardLinks.next =
10240 - (struct ylist_head *) hardList;
10241 - hardList = obj;
10242 - }
10243 - } else
10244 - ok = 0;
10245 - }
10246 - }
10247 + if (tags.chunk_id == 0) {
10248 + /* It is an object Id,
10249 + * We need to nuke the shrinkheader flags first
10250 + * Also need to clean up shadowing.
10251 + * We no longer want the shrinkHeader flag since its work is done
10252 + * and if it is left in place it will mess up scanning.
10253 + */
10254
10255 - if (ok)
10256 - yaffs_HardlinkFixup(dev, hardList);
10257 + yaffs_obj_header *oh;
10258 + oh = (yaffs_obj_header *)buffer;
10259
10260 - return ok ? 1 : 0;
10261 -}
10262 + oh->is_shrink = 0;
10263 + tags.extra_is_shrink = 0;
10264
10265 -static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
10266 -{
10267 - __u32 checkpointSum;
10268 - int ok;
10269 + oh->shadows_obj = 0;
10270 + oh->inband_shadowed_obj_id = 0;
10271 + tags.extra_shadows = 0;
10272 +
10273 + /* Update file size */
10274 + if(object->variant_type == YAFFS_OBJECT_TYPE_FILE){
10275 + oh->file_size = object->variant.file_variant.file_size;
10276 + tags.extra_length = oh->file_size;
10277 + }
10278 +
10279 + yaffs_verify_oh(object, oh, &tags, 1);
10280 + newChunk =
10281 + yaffs_write_new_chunk(dev,(__u8 *) oh, &tags, 1);
10282 + } else
10283 + newChunk =
10284 + yaffs_write_new_chunk(dev, buffer, &tags, 1);
10285 +
10286 + if (newChunk < 0) {
10287 + retVal = YAFFS_FAIL;
10288 + } else {
10289
10290 - yaffs_GetCheckpointSum(dev, &checkpointSum);
10291 + /* Ok, now fix up the Tnodes etc. */
10292
10293 - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
10294 + if (tags.chunk_id == 0) {
10295 + /* It's a header */
10296 + object->hdr_chunk = newChunk;
10297 + object->serial = tags.serial_number;
10298 + } else {
10299 + /* It's a data chunk */
10300 + int ok;
10301 + ok = yaffs_put_chunk_in_file
10302 + (object,
10303 + tags.chunk_id,
10304 + newChunk, 0);
10305 + }
10306 + }
10307 + }
10308
10309 - if (!ok)
10310 - return 0;
10311 + if (retVal == YAFFS_OK)
10312 + yaffs_chunk_del(dev, oldChunk, mark_flash, __LINE__);
10313
10314 - return 1;
10315 -}
10316 + }
10317 + }
10318
10319 -static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
10320 -{
10321 - __u32 checkpointSum0;
10322 - __u32 checkpointSum1;
10323 - int ok;
10324 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
10325
10326 - yaffs_GetCheckpointSum(dev, &checkpointSum0);
10327
10328 - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
10329
10330 - if (!ok)
10331 - return 0;
10332 + }
10333
10334 - if (checkpointSum0 != checkpointSum1)
10335 - return 0;
10336 + yaffs_verify_collected_blk(dev, bi, block);
10337
10338 - return 1;
10339 -}
10340
10341
10342 -static int yaffs_WriteCheckpointData(yaffs_Device *dev)
10343 -{
10344 - int ok = 1;
10345 + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
10346 + /*
10347 + * The gc did not complete. Set block state back to FULL
10348 + * because checkpointing does not restore gc.
10349 + */
10350 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
10351 + } else {
10352 + /* The gc completed. */
10353 + /* Do any required cleanups */
10354 + for (i = 0; i < dev->n_clean_ups; i++) {
10355 + /* Time to delete the file too */
10356 + object =
10357 + yaffs_find_by_number(dev,
10358 + dev->gc_cleanup_list[i]);
10359 + if (object) {
10360 + yaffs_free_tnode(dev,
10361 + object->variant.file_variant.
10362 + top);
10363 + object->variant.file_variant.top = NULL;
10364 + T(YAFFS_TRACE_GC,
10365 + (TSTR
10366 + ("yaffs: About to finally delete object %d"
10367 + TENDSTR), object->obj_id));
10368 + yaffs_generic_obj_del(object);
10369 + object->my_dev->n_deleted_files--;
10370 + }
10371
10372 - if (dev->skipCheckpointWrite || !dev->isYaffs2) {
10373 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
10374 - ok = 0;
10375 - }
10376 + }
10377
10378 - if (ok)
10379 - ok = yaffs_CheckpointOpen(dev, 1);
10380
10381 - if (ok) {
10382 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
10383 - ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
10384 - }
10385 - if (ok) {
10386 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
10387 - ok = yaffs_WriteCheckpointDevice(dev);
10388 - }
10389 - if (ok) {
10390 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
10391 - ok = yaffs_WriteCheckpointObjects(dev);
10392 - }
10393 - if (ok) {
10394 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
10395 - ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
10396 + chunksAfter = yaffs_get_erased_chunks(dev);
10397 + if (chunksBefore >= chunksAfter) {
10398 + T(YAFFS_TRACE_GC,
10399 + (TSTR
10400 + ("gc did not increase free chunks before %d after %d"
10401 + TENDSTR), chunksBefore, chunksAfter));
10402 + }
10403 + dev->gc_block = 0;
10404 + dev->gc_chunk = 0;
10405 + dev->n_clean_ups = 0;
10406 }
10407
10408 - if (ok)
10409 - ok = yaffs_WriteCheckpointSum(dev);
10410 -
10411 - if (!yaffs_CheckpointClose(dev))
10412 - ok = 0;
10413 -
10414 - if (ok)
10415 - dev->isCheckpointed = 1;
10416 - else
10417 - dev->isCheckpointed = 0;
10418 + dev->gc_disable = 0;
10419
10420 - return dev->isCheckpointed;
10421 + return retVal;
10422 }
10423
10424 -static int yaffs_ReadCheckpointData(yaffs_Device *dev)
10425 +/*
10426 + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
10427 + * for garbage collection.
10428 + */
10429 +
10430 +static unsigned yaffs_find_gc_block(yaffs_dev_t *dev,
10431 + int aggressive,
10432 + int background)
10433 {
10434 - int ok = 1;
10435 + int i;
10436 + int iterations;
10437 + unsigned selected = 0;
10438 + int prioritised = 0;
10439 + int prioritisedExists = 0;
10440 + yaffs_block_info_t *bi;
10441 + int threshold;
10442
10443 - if (dev->skipCheckpointRead || !dev->isYaffs2) {
10444 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
10445 - ok = 0;
10446 - }
10447 + /* First let's see if we need to grab a prioritised block */
10448 + if (dev->has_pending_prioritised_gc && !aggressive) {
10449 + dev->gc_dirtiest = 0;
10450 + bi = dev->block_info;
10451 + for (i = dev->internal_start_block;
10452 + i <= dev->internal_end_block && !selected;
10453 + i++) {
10454 +
10455 + if (bi->gc_prioritise) {
10456 + prioritisedExists = 1;
10457 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
10458 + yaffs_block_ok_for_gc(dev, bi)) {
10459 + selected = i;
10460 + prioritised = 1;
10461 + }
10462 + }
10463 + bi++;
10464 + }
10465
10466 - if (ok)
10467 - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
10468 + /*
10469 + * If there is a prioritised block and none was selected then
10470 + * this happened because there is at least one old dirty block gumming
10471 + * up the works. Let's gc the oldest dirty block.
10472 + */
10473
10474 - if (ok) {
10475 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
10476 - ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
10477 - }
10478 - if (ok) {
10479 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
10480 - ok = yaffs_ReadCheckpointDevice(dev);
10481 - }
10482 - if (ok) {
10483 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
10484 - ok = yaffs_ReadCheckpointObjects(dev);
10485 - }
10486 - if (ok) {
10487 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
10488 - ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
10489 - }
10490 + if(prioritisedExists &&
10491 + !selected &&
10492 + dev->oldest_dirty_block > 0)
10493 + selected = dev->oldest_dirty_block;
10494
10495 - if (ok) {
10496 - ok = yaffs_ReadCheckpointSum(dev);
10497 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
10498 + if (!prioritisedExists) /* None found, so we can clear this */
10499 + dev->has_pending_prioritised_gc = 0;
10500 }
10501
10502 - if (!yaffs_CheckpointClose(dev))
10503 - ok = 0;
10504 -
10505 - if (ok)
10506 - dev->isCheckpointed = 1;
10507 - else
10508 - dev->isCheckpointed = 0;
10509 -
10510 - return ok ? 1 : 0;
10511 + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
10512 + * search harder.
10513 + * else (we're doing a leasurely gc), then we only bother to do this if the
10514 + * block has only a few pages in use.
10515 + */
10516
10517 -}
10518 + if (!selected){
10519 + int pagesUsed;
10520 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
10521 + if (aggressive){
10522 + threshold = dev->param.chunks_per_block;
10523 + iterations = nBlocks;
10524 + } else {
10525 + int maxThreshold;
10526
10527 -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
10528 -{
10529 - if (dev->isCheckpointed ||
10530 - dev->blocksInCheckpoint > 0) {
10531 - dev->isCheckpointed = 0;
10532 - yaffs_CheckpointInvalidateStream(dev);
10533 - if (dev->superBlock && dev->markSuperBlockDirty)
10534 - dev->markSuperBlockDirty(dev->superBlock);
10535 - }
10536 -}
10537 + if(background)
10538 + maxThreshold = dev->param.chunks_per_block/2;
10539 + else
10540 + maxThreshold = dev->param.chunks_per_block/8;
10541
10542 + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
10543 + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
10544
10545 -int yaffs_CheckpointSave(yaffs_Device *dev)
10546 -{
10547 + threshold = background ?
10548 + (dev->gc_not_done + 2) * 2 : 0;
10549 + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
10550 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
10551 + if(threshold > maxThreshold)
10552 + threshold = maxThreshold;
10553
10554 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10555 + iterations = nBlocks / 16 + 1;
10556 + if (iterations > 100)
10557 + iterations = 100;
10558 + }
10559
10560 - yaffs_VerifyObjects(dev);
10561 - yaffs_VerifyBlocks(dev);
10562 - yaffs_VerifyFreeChunks(dev);
10563 + for (i = 0;
10564 + i < iterations &&
10565 + (dev->gc_dirtiest < 1 ||
10566 + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
10567 + i++) {
10568 + dev->gc_block_finder++;
10569 + if (dev->gc_block_finder < dev->internal_start_block ||
10570 + dev->gc_block_finder > dev->internal_end_block)
10571 + dev->gc_block_finder = dev->internal_start_block;
10572
10573 - if (!dev->isCheckpointed) {
10574 - yaffs_InvalidateCheckpoint(dev);
10575 - yaffs_WriteCheckpointData(dev);
10576 - }
10577 + bi = yaffs_get_block_info(dev, dev->gc_block_finder);
10578
10579 - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10580 + pagesUsed = bi->pages_in_use - bi->soft_del_pages;
10581
10582 - return dev->isCheckpointed;
10583 -}
10584 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
10585 + pagesUsed < dev->param.chunks_per_block &&
10586 + (dev->gc_dirtiest < 1 || pagesUsed < dev->gc_pages_in_use) &&
10587 + yaffs_block_ok_for_gc(dev, bi)) {
10588 + dev->gc_dirtiest = dev->gc_block_finder;
10589 + dev->gc_pages_in_use = pagesUsed;
10590 + }
10591 + }
10592
10593 -int yaffs_CheckpointRestore(yaffs_Device *dev)
10594 -{
10595 - int retval;
10596 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10597 + if(dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
10598 + selected = dev->gc_dirtiest;
10599 + }
10600
10601 - retval = yaffs_ReadCheckpointData(dev);
10602 + /*
10603 + * If nothing has been selected for a while, try selecting the oldest dirty
10604 + * because that's gumming up the works.
10605 + */
10606
10607 - if (dev->isCheckpointed) {
10608 - yaffs_VerifyObjects(dev);
10609 - yaffs_VerifyBlocks(dev);
10610 - yaffs_VerifyFreeChunks(dev);
10611 + if(!selected && dev->param.is_yaffs2 &&
10612 + dev->gc_not_done >= ( background ? 10 : 20)){
10613 + yaffs2_find_oldest_dirty_seq(dev);
10614 + if(dev->oldest_dirty_block > 0) {
10615 + selected = dev->oldest_dirty_block;
10616 + dev->gc_dirtiest = selected;
10617 + dev->oldest_dirty_gc_count++;
10618 + bi = yaffs_get_block_info(dev, selected);
10619 + dev->gc_pages_in_use = bi->pages_in_use - bi->soft_del_pages;
10620 + } else
10621 + dev->gc_not_done = 0;
10622 }
10623
10624 - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
10625 + if(selected){
10626 + T(YAFFS_TRACE_GC,
10627 + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
10628 + selected,
10629 + dev->param.chunks_per_block - dev->gc_pages_in_use,
10630 + prioritised));
10631 +
10632 + dev->n_gc_blocks++;
10633 + if(background)
10634 + dev->bg_gcs++;
10635 +
10636 + dev->gc_dirtiest = 0;
10637 + dev->gc_pages_in_use = 0;
10638 + dev->gc_not_done = 0;
10639 + if(dev->refresh_skip > 0)
10640 + dev->refresh_skip--;
10641 + } else{
10642 + dev->gc_not_done++;
10643 + T(YAFFS_TRACE_GC,
10644 + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
10645 + dev->gc_block_finder, dev->gc_not_done,
10646 + threshold,
10647 + dev->gc_dirtiest, dev->gc_pages_in_use,
10648 + dev->oldest_dirty_block,
10649 + background ? " bg" : ""));
10650 + }
10651
10652 - return retval;
10653 + return selected;
10654 }
10655
10656 -/*--------------------- File read/write ------------------------
10657 - * Read and write have very similar structures.
10658 - * In general the read/write has three parts to it
10659 - * An incomplete chunk to start with (if the read/write is not chunk-aligned)
10660 - * Some complete chunks
10661 - * An incomplete chunk to end off with
10662 +/* New garbage collector
10663 + * If we're very low on erased blocks then we do aggressive garbage collection
10664 + * otherwise we do "leasurely" garbage collection.
10665 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
10666 + * Passive gc only inspects smaller areas and will only accept more dirty blocks.
10667 *
10668 - * Curve-balls: the first chunk might also be the last chunk.
10669 + * The idea is to help clear out space in a more spread-out manner.
10670 + * Dunno if it really does anything useful.
10671 */
10672 -
10673 -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
10674 - int nBytes)
10675 +static int yaffs_check_gc(yaffs_dev_t *dev, int background)
10676 {
10677 + int aggressive = 0;
10678 + int gcOk = YAFFS_OK;
10679 + int maxTries = 0;
10680 + int minErased;
10681 + int erasedChunks;
10682 + int checkpointBlockAdjust;
10683
10684 - int chunk;
10685 - __u32 start;
10686 - int nToCopy;
10687 - int n = nBytes;
10688 - int nDone = 0;
10689 - yaffs_ChunkCache *cache;
10690 -
10691 - yaffs_Device *dev;
10692 -
10693 - dev = in->myDev;
10694 -
10695 - while (n > 0) {
10696 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10697 - /* start = offset % dev->nDataBytesPerChunk; */
10698 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10699 - chunk++;
10700 -
10701 - /* OK now check for the curveball where the start and end are in
10702 - * the same chunk.
10703 - */
10704 - if ((start + n) < dev->nDataBytesPerChunk)
10705 - nToCopy = n;
10706 - else
10707 - nToCopy = dev->nDataBytesPerChunk - start;
10708 -
10709 - cache = yaffs_FindChunkCache(in, chunk);
10710 -
10711 - /* If the chunk is already in the cache or it is less than a whole chunk
10712 - * or we're using inband tags then use the cache (if there is caching)
10713 - * else bypass the cache.
10714 - */
10715 - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10716 - if (dev->nShortOpCaches > 0) {
10717 -
10718 - /* If we can't find the data in the cache, then load it up. */
10719 + if(dev->param.gc_control &&
10720 + (dev->param.gc_control(dev) & 1) == 0)
10721 + return YAFFS_OK;
10722
10723 - if (!cache) {
10724 - cache = yaffs_GrabChunkCache(in->myDev);
10725 - cache->object = in;
10726 - cache->chunkId = chunk;
10727 - cache->dirty = 0;
10728 - cache->locked = 0;
10729 - yaffs_ReadChunkDataFromObject(in, chunk,
10730 - cache->
10731 - data);
10732 - cache->nBytes = 0;
10733 - }
10734 + if (dev->gc_disable) {
10735 + /* Bail out so we don't get recursive gc */
10736 + return YAFFS_OK;
10737 + }
10738
10739 - yaffs_UseChunkCache(dev, cache, 0);
10740 + /* This loop should pass the first time.
10741 + * We'll only see looping here if the collection does not increase space.
10742 + */
10743
10744 - cache->locked = 1;
10745 + do {
10746 + maxTries++;
10747
10748 + checkpointBlockAdjust = yaffs_calc_checkpt_blocks_required(dev);
10749
10750 - memcpy(buffer, &cache->data[start], nToCopy);
10751 + minErased = dev->param.n_reserved_blocks + checkpointBlockAdjust + 1;
10752 + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
10753
10754 - cache->locked = 0;
10755 - } else {
10756 - /* Read into the local buffer then copy..*/
10757 + /* If we need a block soon then do aggressive gc.*/
10758 + if (dev->n_erased_blocks < minErased)
10759 + aggressive = 1;
10760 + else {
10761 + if(!background && erasedChunks > (dev->n_free_chunks / 4))
10762 + break;
10763
10764 - __u8 *localBuffer =
10765 - yaffs_GetTempBuffer(dev, __LINE__);
10766 - yaffs_ReadChunkDataFromObject(in, chunk,
10767 - localBuffer);
10768 + if(dev->gc_skip > 20)
10769 + dev->gc_skip = 20;
10770 + if(erasedChunks < dev->n_free_chunks/2 ||
10771 + dev->gc_skip < 1 ||
10772 + background)
10773 + aggressive = 0;
10774 + else {
10775 + dev->gc_skip--;
10776 + break;
10777 + }
10778 + }
10779
10780 - memcpy(buffer, &localBuffer[start], nToCopy);
10781 + dev->gc_skip = 5;
10782
10783 + /* If we don't already have a block being gc'd then see if we should start another */
10784
10785 - yaffs_ReleaseTempBuffer(dev, localBuffer,
10786 - __LINE__);
10787 - }
10788 + if (dev->gc_block < 1 && !aggressive) {
10789 + dev->gc_block = yaffs2_find_refresh_block(dev);
10790 + dev->gc_chunk = 0;
10791 + dev->n_clean_ups=0;
10792 + }
10793 + if (dev->gc_block < 1) {
10794 + dev->gc_block = yaffs_find_gc_block(dev, aggressive, background);
10795 + dev->gc_chunk = 0;
10796 + dev->n_clean_ups=0;
10797 + }
10798
10799 - } else {
10800 + if (dev->gc_block > 0) {
10801 + dev->all_gcs++;
10802 + if (!aggressive)
10803 + dev->passive_gc_count++;
10804
10805 - /* A full chunk. Read directly into the supplied buffer. */
10806 - yaffs_ReadChunkDataFromObject(in, chunk, buffer);
10807 + T(YAFFS_TRACE_GC,
10808 + (TSTR
10809 + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
10810 + dev->n_erased_blocks, aggressive));
10811
10812 + gcOk = yaffs_gc_block(dev, dev->gc_block, aggressive);
10813 }
10814
10815 - n -= nToCopy;
10816 - offset += nToCopy;
10817 - buffer += nToCopy;
10818 - nDone += nToCopy;
10819 -
10820 - }
10821 + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && dev->gc_block > 0) {
10822 + T(YAFFS_TRACE_GC,
10823 + (TSTR
10824 + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
10825 + TENDSTR), dev->n_erased_blocks, maxTries, dev->gc_block));
10826 + }
10827 + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
10828 + (dev->gc_block > 0) &&
10829 + (maxTries < 2));
10830
10831 - return nDone;
10832 + return aggressive ? gcOk : YAFFS_OK;
10833 }
10834
10835 -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
10836 - int nBytes, int writeThrough)
10837 +/*
10838 + * yaffs_bg_gc()
10839 + * Garbage collects. Intended to be called from a background thread.
10840 + * Returns non-zero if at least half the free chunks are erased.
10841 + */
10842 +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency)
10843 {
10844 + int erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
10845
10846 - int chunk;
10847 - __u32 start;
10848 - int nToCopy;
10849 - int n = nBytes;
10850 - int nDone = 0;
10851 - int nToWriteBack;
10852 - int startOfWrite = offset;
10853 - int chunkWritten = 0;
10854 - __u32 nBytesRead;
10855 - __u32 chunkStart;
10856 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
10857
10858 - yaffs_Device *dev;
10859 + yaffs_check_gc(dev, 1);
10860 + return erasedChunks > dev->n_free_chunks/2;
10861 +}
10862
10863 - dev = in->myDev;
10864 +/*------------------------- TAGS --------------------------------*/
10865
10866 - while (n > 0 && chunkWritten >= 0) {
10867 - /* chunk = offset / dev->nDataBytesPerChunk + 1; */
10868 - /* start = offset % dev->nDataBytesPerChunk; */
10869 - yaffs_AddrToChunk(dev, offset, &chunk, &start);
10870 +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
10871 + int chunkInObject)
10872 +{
10873 + return (tags->chunk_id == chunkInObject &&
10874 + tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
10875
10876 - if (chunk * dev->nDataBytesPerChunk + start != offset ||
10877 - start >= dev->nDataBytesPerChunk) {
10878 - T(YAFFS_TRACE_ERROR, (
10879 - TSTR("AddrToChunk of offset %d gives chunk %d start %d"
10880 - TENDSTR),
10881 - (int)offset, chunk, start));
10882 - }
10883 - chunk++;
10884 +}
10885
10886 - /* OK now check for the curveball where the start and end are in
10887 - * the same chunk.
10888 - */
10889
10890 - if ((start + n) < dev->nDataBytesPerChunk) {
10891 - nToCopy = n;
10892 +/*-------------------- Data file manipulation -----------------*/
10893
10894 - /* Now folks, to calculate how many bytes to write back....
10895 - * If we're overwriting and not writing to then end of file then
10896 - * we need to write back as much as was there before.
10897 - */
10898 +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
10899 + yaffs_ext_tags *tags)
10900 +{
10901 + /*Get the Tnode, then get the level 0 offset chunk offset */
10902 + yaffs_tnode_t *tn;
10903 + int theChunk = -1;
10904 + yaffs_ext_tags localTags;
10905 + int retVal = -1;
10906
10907 - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
10908 + yaffs_dev_t *dev = in->my_dev;
10909
10910 - if (chunkStart > in->variant.fileVariant.fileSize)
10911 - nBytesRead = 0; /* Past end of file */
10912 - else
10913 - nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
10914 + if (!tags) {
10915 + /* Passed a NULL, so use our own tags space */
10916 + tags = &localTags;
10917 + }
10918
10919 - if (nBytesRead > dev->nDataBytesPerChunk)
10920 - nBytesRead = dev->nDataBytesPerChunk;
10921 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
10922
10923 - nToWriteBack =
10924 - (nBytesRead >
10925 - (start + n)) ? nBytesRead : (start + n);
10926 + if (tn) {
10927 + theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
10928
10929 - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
10930 - YBUG();
10931 + retVal =
10932 + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
10933 + inode_chunk);
10934 + }
10935 + return retVal;
10936 +}
10937
10938 - } else {
10939 - nToCopy = dev->nDataBytesPerChunk - start;
10940 - nToWriteBack = dev->nDataBytesPerChunk;
10941 - }
10942 +static int yaffs_find_del_file_chunk(yaffs_obj_t *in, int inode_chunk,
10943 + yaffs_ext_tags *tags)
10944 +{
10945 + /* Get the Tnode, then get the level 0 offset chunk offset */
10946 + yaffs_tnode_t *tn;
10947 + int theChunk = -1;
10948 + yaffs_ext_tags localTags;
10949
10950 - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
10951 - /* An incomplete start or end chunk (or maybe both start and end chunk),
10952 - * or we're using inband tags, so we want to use the cache buffers.
10953 - */
10954 - if (dev->nShortOpCaches > 0) {
10955 - yaffs_ChunkCache *cache;
10956 - /* If we can't find the data in the cache, then load the cache */
10957 - cache = yaffs_FindChunkCache(in, chunk);
10958 + yaffs_dev_t *dev = in->my_dev;
10959 + int retVal = -1;
10960
10961 - if (!cache
10962 - && yaffs_CheckSpaceForAllocation(in->
10963 - myDev)) {
10964 - cache = yaffs_GrabChunkCache(in->myDev);
10965 - cache->object = in;
10966 - cache->chunkId = chunk;
10967 - cache->dirty = 0;
10968 - cache->locked = 0;
10969 - yaffs_ReadChunkDataFromObject(in, chunk,
10970 - cache->
10971 - data);
10972 - } else if (cache &&
10973 - !cache->dirty &&
10974 - !yaffs_CheckSpaceForAllocation(in->myDev)) {
10975 - /* Drop the cache if it was a read cache item and
10976 - * no space check has been made for it.
10977 - */
10978 - cache = NULL;
10979 - }
10980 + if (!tags) {
10981 + /* Passed a NULL, so use our own tags space */
10982 + tags = &localTags;
10983 + }
10984
10985 - if (cache) {
10986 - yaffs_UseChunkCache(dev, cache, 1);
10987 - cache->locked = 1;
10988 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
10989
10990 + if (tn) {
10991
10992 - memcpy(&cache->data[start], buffer,
10993 - nToCopy);
10994 + theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
10995
10996 + retVal =
10997 + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
10998 + inode_chunk);
10999
11000 - cache->locked = 0;
11001 - cache->nBytes = nToWriteBack;
11002 + /* Delete the entry in the filestructure (if found) */
11003 + if (retVal != -1)
11004 + yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
11005 + }
11006
11007 - if (writeThrough) {
11008 - chunkWritten =
11009 - yaffs_WriteChunkDataToObject
11010 - (cache->object,
11011 - cache->chunkId,
11012 - cache->data, cache->nBytes,
11013 - 1);
11014 - cache->dirty = 0;
11015 - }
11016 + return retVal;
11017 +}
11018
11019 - } else {
11020 - chunkWritten = -1; /* fail the write */
11021 - }
11022 - } else {
11023 - /* An incomplete start or end chunk (or maybe both start and end chunk)
11024 - * Read into the local buffer then copy, then copy over and write back.
11025 - */
11026
11027 - __u8 *localBuffer =
11028 - yaffs_GetTempBuffer(dev, __LINE__);
11029 +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
11030 + int nand_chunk, int in_scan)
11031 +{
11032 + /* NB in_scan is zero unless scanning.
11033 + * For forward scanning, in_scan is > 0;
11034 + * for backward scanning in_scan is < 0
11035 + *
11036 + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
11037 + */
11038
11039 - yaffs_ReadChunkDataFromObject(in, chunk,
11040 - localBuffer);
11041 + yaffs_tnode_t *tn;
11042 + yaffs_dev_t *dev = in->my_dev;
11043 + int existingChunk;
11044 + yaffs_ext_tags existingTags;
11045 + yaffs_ext_tags newTags;
11046 + unsigned existingSerial, newSerial;
11047
11048 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
11049 + /* Just ignore an attempt at putting a chunk into a non-file during scanning
11050 + * If it is not during Scanning then something went wrong!
11051 + */
11052 + if (!in_scan) {
11053 + T(YAFFS_TRACE_ERROR,
11054 + (TSTR
11055 + ("yaffs tragedy:attempt to put data chunk into a non-file"
11056 + TENDSTR)));
11057 + YBUG();
11058 + }
11059
11060 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
11061 + return YAFFS_OK;
11062 + }
11063
11064 - memcpy(&localBuffer[start], buffer, nToCopy);
11065 + tn = yaffs_add_find_tnode_0(dev,
11066 + &in->variant.file_variant,
11067 + inode_chunk,
11068 + NULL);
11069 + if (!tn)
11070 + return YAFFS_FAIL;
11071 +
11072 + if(!nand_chunk)
11073 + /* Dummy insert, bail now */
11074 + return YAFFS_OK;
11075
11076 - chunkWritten =
11077 - yaffs_WriteChunkDataToObject(in, chunk,
11078 - localBuffer,
11079 - nToWriteBack,
11080 - 0);
11081 + existingChunk = yaffs_get_group_base(dev, tn, inode_chunk);
11082
11083 - yaffs_ReleaseTempBuffer(dev, localBuffer,
11084 - __LINE__);
11085 + if (in_scan != 0) {
11086 + /* If we're scanning then we need to test for duplicates
11087 + * NB This does not need to be efficient since it should only ever
11088 + * happen when the power fails during a write, then only one
11089 + * chunk should ever be affected.
11090 + *
11091 + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
11092 + * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
11093 + */
11094 +
11095 + if (existingChunk > 0) {
11096 + /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
11097 + * thus we have to do a FindChunkInFile to get the real chunk id.
11098 + *
11099 + * We have a duplicate now we need to decide which one to use:
11100 + *
11101 + * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
11102 + * Forward scanning YAFFS2: The new one is what we use, dump the old one.
11103 + * YAFFS1: Get both sets of tags and compare serial numbers.
11104 + */
11105 +
11106 + if (in_scan > 0) {
11107 + /* Only do this for forward scanning */
11108 + yaffs_rd_chunk_tags_nand(dev,
11109 + nand_chunk,
11110 + NULL, &newTags);
11111
11112 + /* Do a proper find */
11113 + existingChunk =
11114 + yaffs_find_chunk_in_file(in, inode_chunk,
11115 + &existingTags);
11116 }
11117
11118 - } else {
11119 - /* A full chunk. Write directly from the supplied buffer. */
11120 + if (existingChunk <= 0) {
11121 + /*Hoosterman - how did this happen? */
11122
11123 + T(YAFFS_TRACE_ERROR,
11124 + (TSTR
11125 + ("yaffs tragedy: existing chunk < 0 in scan"
11126 + TENDSTR)));
11127
11128 + }
11129
11130 - chunkWritten =
11131 - yaffs_WriteChunkDataToObject(in, chunk, buffer,
11132 - dev->nDataBytesPerChunk,
11133 - 0);
11134 + /* NB The deleted flags should be false, otherwise the chunks will
11135 + * not be loaded during a scan
11136 + */
11137
11138 - /* Since we've overwritten the cached data, we better invalidate it. */
11139 - yaffs_InvalidateChunkCache(in, chunk);
11140 - }
11141 + if (in_scan > 0) {
11142 + newSerial = newTags.serial_number;
11143 + existingSerial = existingTags.serial_number;
11144 + }
11145
11146 - if (chunkWritten >= 0) {
11147 - n -= nToCopy;
11148 - offset += nToCopy;
11149 - buffer += nToCopy;
11150 - nDone += nToCopy;
11151 + if ((in_scan > 0) &&
11152 + (existingChunk <= 0 ||
11153 + ((existingSerial + 1) & 3) == newSerial)) {
11154 + /* Forward scanning.
11155 + * Use new
11156 + * Delete the old one and drop through to update the tnode
11157 + */
11158 + yaffs_chunk_del(dev, existingChunk, 1,
11159 + __LINE__);
11160 + } else {
11161 + /* Backward scanning or we want to use the existing one
11162 + * Use existing.
11163 + * Delete the new one and return early so that the tnode isn't changed
11164 + */
11165 + yaffs_chunk_del(dev, nand_chunk, 1,
11166 + __LINE__);
11167 + return YAFFS_OK;
11168 + }
11169 }
11170
11171 }
11172
11173 - /* Update file object */
11174 -
11175 - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
11176 - in->variant.fileVariant.fileSize = (startOfWrite + nDone);
11177 + if (existingChunk == 0)
11178 + in->n_data_chunks++;
11179
11180 - in->dirty = 1;
11181 + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
11182
11183 - return nDone;
11184 + return YAFFS_OK;
11185 }
11186
11187 +static int yaffs_rd_data_obj(yaffs_obj_t *in, int inode_chunk,
11188 + __u8 *buffer)
11189 +{
11190 + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
11191
11192 -/* ---------------------- File resizing stuff ------------------ */
11193 + if (nand_chunk >= 0)
11194 + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
11195 + buffer, NULL);
11196 + else {
11197 + T(YAFFS_TRACE_NANDACCESS,
11198 + (TSTR("Chunk %d not found zero instead" TENDSTR),
11199 + nand_chunk));
11200 + /* get sane (zero) data if you read a hole */
11201 + memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
11202 + return 0;
11203 + }
11204 +
11205 +}
11206
11207 -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
11208 +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn)
11209 {
11210 + int block;
11211 + int page;
11212 + yaffs_ext_tags tags;
11213 + yaffs_block_info_t *bi;
11214
11215 - yaffs_Device *dev = in->myDev;
11216 - int oldFileSize = in->variant.fileVariant.fileSize;
11217 + if (chunk_id <= 0)
11218 + return;
11219
11220 - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
11221 + dev->n_deletions++;
11222 + block = chunk_id / dev->param.chunks_per_block;
11223 + page = chunk_id % dev->param.chunks_per_block;
11224
11225 - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
11226 - dev->nDataBytesPerChunk;
11227 - int i;
11228 - int chunkId;
11229
11230 - /* Delete backwards so that we don't end up with holes if
11231 - * power is lost part-way through the operation.
11232 + if (!yaffs_check_chunk_bit(dev, block, page))
11233 + T(YAFFS_TRACE_VERIFY,
11234 + (TSTR("Deleting invalid chunk %d"TENDSTR),
11235 + chunk_id));
11236 +
11237 + bi = yaffs_get_block_info(dev, block);
11238 +
11239 + yaffs2_update_oldest_dirty_seq(dev, block, bi);
11240 +
11241 + T(YAFFS_TRACE_DELETION,
11242 + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunk_id));
11243 +
11244 + if (!dev->param.is_yaffs2 && mark_flash &&
11245 + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
11246 +
11247 + yaffs_init_tags(&tags);
11248 +
11249 + tags.is_deleted = 1;
11250 +
11251 + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
11252 + yaffs_handle_chunk_update(dev, chunk_id, &tags);
11253 + } else {
11254 + dev->n_unmarked_deletions++;
11255 + }
11256 +
11257 + /* Pull out of the management area.
11258 + * If the whole block became dirty, this will kick off an erasure.
11259 */
11260 - for (i = lastDel; i >= startDel; i--) {
11261 - /* NB this could be optimised somewhat,
11262 - * eg. could retrieve the tags and write them without
11263 - * using yaffs_DeleteChunk
11264 - */
11265 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
11266 + bi->block_state == YAFFS_BLOCK_STATE_FULL ||
11267 + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
11268 + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
11269 + dev->n_free_chunks++;
11270
11271 - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
11272 - if (chunkId > 0) {
11273 - if (chunkId <
11274 - (dev->internalStartBlock * dev->nChunksPerBlock)
11275 - || chunkId >=
11276 - ((dev->internalEndBlock +
11277 - 1) * dev->nChunksPerBlock)) {
11278 - T(YAFFS_TRACE_ALWAYS,
11279 - (TSTR("Found daft chunkId %d for %d" TENDSTR),
11280 - chunkId, i));
11281 - } else {
11282 - in->nDataChunks--;
11283 - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
11284 - }
11285 + yaffs_clear_chunk_bit(dev, block, page);
11286 +
11287 + bi->pages_in_use--;
11288 +
11289 + if (bi->pages_in_use == 0 &&
11290 + !bi->has_shrink_hdr &&
11291 + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
11292 + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
11293 + yaffs_block_became_dirty(dev, block);
11294 }
11295 +
11296 }
11297
11298 }
11299
11300 -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
11301 +static int yaffs_wr_data_obj(yaffs_obj_t *in, int inode_chunk,
11302 + const __u8 *buffer, int n_bytes,
11303 + int useReserve)
11304 {
11305 + /* Find old chunk Need to do this to get serial number
11306 + * Write new one and patch into tree.
11307 + * Invalidate old tags.
11308 + */
11309
11310 - int oldFileSize = in->variant.fileVariant.fileSize;
11311 - __u32 newSizeOfPartialChunk;
11312 - int newFullChunks;
11313 + int prevChunkId;
11314 + yaffs_ext_tags prevTags;
11315
11316 - yaffs_Device *dev = in->myDev;
11317 + int newChunkId;
11318 + yaffs_ext_tags newTags;
11319
11320 - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
11321 + yaffs_dev_t *dev = in->my_dev;
11322
11323 - yaffs_FlushFilesChunkCache(in);
11324 - yaffs_InvalidateWholeChunkCache(in);
11325 + yaffs_check_gc(dev,0);
11326
11327 - yaffs_CheckGarbageCollection(dev);
11328 + /* Get the previous chunk at this location in the file if it exists.
11329 + * If it does not exist then put a zero into the tree. This creates
11330 + * the tnode now, rather than later when it is harder to clean up.
11331 + */
11332 + prevChunkId = yaffs_find_chunk_in_file(in, inode_chunk, &prevTags);
11333 + if(prevChunkId < 1 &&
11334 + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
11335 + return 0;
11336
11337 - if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
11338 - return YAFFS_FAIL;
11339 + /* Set up new tags */
11340 + yaffs_init_tags(&newTags);
11341
11342 - if (newSize == oldFileSize)
11343 - return YAFFS_OK;
11344 + newTags.chunk_id = inode_chunk;
11345 + newTags.obj_id = in->obj_id;
11346 + newTags.serial_number =
11347 + (prevChunkId > 0) ? prevTags.serial_number + 1 : 1;
11348 + newTags.n_bytes = n_bytes;
11349
11350 - if (newSize < oldFileSize) {
11351 + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
11352 + T(YAFFS_TRACE_ERROR,
11353 + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes));
11354 + YBUG();
11355 + }
11356 +
11357 +
11358 + newChunkId =
11359 + yaffs_write_new_chunk(dev, buffer, &newTags,
11360 + useReserve);
11361
11362 - yaffs_PruneResizedChunks(in, newSize);
11363 + if (newChunkId > 0) {
11364 + yaffs_put_chunk_in_file(in, inode_chunk, newChunkId, 0);
11365
11366 - if (newSizeOfPartialChunk != 0) {
11367 - int lastChunk = 1 + newFullChunks;
11368 + if (prevChunkId > 0)
11369 + yaffs_chunk_del(dev, prevChunkId, 1, __LINE__);
11370
11371 - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
11372 + yaffs_verify_file_sane(in);
11373 + }
11374 + return newChunkId;
11375
11376 - /* Got to read and rewrite the last chunk with its new size and zero pad */
11377 - yaffs_ReadChunkDataFromObject(in, lastChunk,
11378 - localBuffer);
11379 +}
11380
11381 - memset(localBuffer + newSizeOfPartialChunk, 0,
11382 - dev->nDataBytesPerChunk - newSizeOfPartialChunk);
11383 +/* UpdateObjectHeader updates the header on NAND for an object.
11384 + * If name is not NULL, then that new name is used.
11385 + */
11386 +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name, int force,
11387 + int is_shrink, int shadows, yaffs_xattr_mod *xmod)
11388 +{
11389
11390 - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
11391 - newSizeOfPartialChunk, 1);
11392 + yaffs_block_info_t *bi;
11393
11394 - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
11395 - }
11396 + yaffs_dev_t *dev = in->my_dev;
11397
11398 - in->variant.fileVariant.fileSize = newSize;
11399 + int prevChunkId;
11400 + int retVal = 0;
11401 + int result = 0;
11402
11403 - yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
11404 - } else {
11405 - /* newsSize > oldFileSize */
11406 - in->variant.fileVariant.fileSize = newSize;
11407 - }
11408 + int newChunkId;
11409 + yaffs_ext_tags newTags;
11410 + yaffs_ext_tags oldTags;
11411 + const YCHAR *alias = NULL;
11412
11413 + __u8 *buffer = NULL;
11414 + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
11415
11416 - /* Write a new object header.
11417 - * show we've shrunk the file, if need be
11418 - * Do this only if the file is not in the deleted directories.
11419 - */
11420 - if (in->parent &&
11421 - in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
11422 - in->parent->objectId != YAFFS_OBJECTID_DELETED)
11423 - yaffs_UpdateObjectHeader(in, NULL, 0,
11424 - (newSize < oldFileSize) ? 1 : 0, 0);
11425 + yaffs_obj_header *oh = NULL;
11426
11427 - return YAFFS_OK;
11428 -}
11429 + yaffs_strcpy(old_name, _Y("silly old name"));
11430
11431 -loff_t yaffs_GetFileSize(yaffs_Object *obj)
11432 -{
11433 - obj = yaffs_GetEquivalentObject(obj);
11434
11435 - switch (obj->variantType) {
11436 - case YAFFS_OBJECT_TYPE_FILE:
11437 - return obj->variant.fileVariant.fileSize;
11438 - case YAFFS_OBJECT_TYPE_SYMLINK:
11439 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
11440 - default:
11441 - return 0;
11442 - }
11443 -}
11444 + if (!in->fake ||
11445 + in == dev->root_dir || /* The root_dir should also be saved */
11446 + force || xmod) {
11447
11448 + yaffs_check_gc(dev,0);
11449 + yaffs_check_obj_details_loaded(in);
11450
11451 + buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__);
11452 + oh = (yaffs_obj_header *) buffer;
11453 +
11454 + prevChunkId = in->hdr_chunk;
11455 +
11456 + if (prevChunkId > 0) {
11457 + result = yaffs_rd_chunk_tags_nand(dev, prevChunkId,
11458 + buffer, &oldTags);
11459 +
11460 + yaffs_verify_oh(in, oh, &oldTags, 0);
11461 +
11462 + memcpy(old_name, oh->name, sizeof(oh->name));
11463 + memset(buffer, 0xFF, sizeof(yaffs_obj_header));
11464 + } else
11465 + memset(buffer, 0xFF, dev->data_bytes_per_chunk);
11466 +
11467 + oh->type = in->variant_type;
11468 + oh->yst_mode = in->yst_mode;
11469 + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
11470
11471 -int yaffs_FlushFile(yaffs_Object *in, int updateTime)
11472 -{
11473 - int retVal;
11474 - if (in->dirty) {
11475 - yaffs_FlushFilesChunkCache(in);
11476 - if (updateTime) {
11477 #ifdef CONFIG_YAFFS_WINCE
11478 - yfsd_WinFileTimeNow(in->win_mtime);
11479 + oh->win_atime[0] = in->win_atime[0];
11480 + oh->win_ctime[0] = in->win_ctime[0];
11481 + oh->win_mtime[0] = in->win_mtime[0];
11482 + oh->win_atime[1] = in->win_atime[1];
11483 + oh->win_ctime[1] = in->win_ctime[1];
11484 + oh->win_mtime[1] = in->win_mtime[1];
11485 #else
11486 + oh->yst_uid = in->yst_uid;
11487 + oh->yst_gid = in->yst_gid;
11488 + oh->yst_atime = in->yst_atime;
11489 + oh->yst_mtime = in->yst_mtime;
11490 + oh->yst_ctime = in->yst_ctime;
11491 + oh->yst_rdev = in->yst_rdev;
11492 +#endif
11493 + if (in->parent)
11494 + oh->parent_obj_id = in->parent->obj_id;
11495 + else
11496 + oh->parent_obj_id = 0;
11497 +
11498 + if (name && *name) {
11499 + memset(oh->name, 0, sizeof(oh->name));
11500 + yaffs_load_oh_from_name(dev,oh->name,name);
11501 + } else if (prevChunkId > 0)
11502 + memcpy(oh->name, old_name, sizeof(oh->name));
11503 + else
11504 + memset(oh->name, 0, sizeof(oh->name));
11505
11506 - in->yst_mtime = Y_CURRENT_TIME;
11507 + oh->is_shrink = is_shrink;
11508
11509 -#endif
11510 + switch (in->variant_type) {
11511 + case YAFFS_OBJECT_TYPE_UNKNOWN:
11512 + /* Should not happen */
11513 + break;
11514 + case YAFFS_OBJECT_TYPE_FILE:
11515 + oh->file_size =
11516 + (oh->parent_obj_id == YAFFS_OBJECTID_DELETED
11517 + || oh->parent_obj_id ==
11518 + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
11519 + file_variant.file_size;
11520 + break;
11521 + case YAFFS_OBJECT_TYPE_HARDLINK:
11522 + oh->equiv_id =
11523 + in->variant.hardlink_variant.equiv_id;
11524 + break;
11525 + case YAFFS_OBJECT_TYPE_SPECIAL:
11526 + /* Do nothing */
11527 + break;
11528 + case YAFFS_OBJECT_TYPE_DIRECTORY:
11529 + /* Do nothing */
11530 + break;
11531 + case YAFFS_OBJECT_TYPE_SYMLINK:
11532 + alias = in->variant.symlink_variant.alias;
11533 + if(!alias)
11534 + alias = _Y("no alias");
11535 + yaffs_strncpy(oh->alias,
11536 + alias,
11537 + YAFFS_MAX_ALIAS_LENGTH);
11538 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
11539 + break;
11540 }
11541
11542 - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
11543 - 0) ? YAFFS_OK : YAFFS_FAIL;
11544 - } else {
11545 - retVal = YAFFS_OK;
11546 - }
11547 + /* process any xattrib modifications */
11548 + if(xmod)
11549 + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
11550
11551 - return retVal;
11552
11553 -}
11554 + /* Tags */
11555 + yaffs_init_tags(&newTags);
11556 + in->serial++;
11557 + newTags.chunk_id = 0;
11558 + newTags.obj_id = in->obj_id;
11559 + newTags.serial_number = in->serial;
11560
11561 -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
11562 -{
11563 + /* Add extra info for file header */
11564
11565 - /* First off, invalidate the file's data in the cache, without flushing. */
11566 - yaffs_InvalidateWholeChunkCache(in);
11567 + newTags.extra_available = 1;
11568 + newTags.extra_parent_id = oh->parent_obj_id;
11569 + newTags.extra_length = oh->file_size;
11570 + newTags.extra_is_shrink = oh->is_shrink;
11571 + newTags.extra_equiv_id = oh->equiv_id;
11572 + newTags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
11573 + newTags.extra_obj_type = in->variant_type;
11574
11575 - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
11576 - /* Move to the unlinked directory so we have a record that it was deleted. */
11577 - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
11578 + yaffs_verify_oh(in, oh, &newTags, 1);
11579
11580 - }
11581 + /* Create new chunk in NAND */
11582 + newChunkId =
11583 + yaffs_write_new_chunk(dev, buffer, &newTags,
11584 + (prevChunkId > 0) ? 1 : 0);
11585
11586 - yaffs_RemoveObjectFromDirectory(in);
11587 - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
11588 - in->hdrChunk = 0;
11589 + if (newChunkId >= 0) {
11590
11591 - yaffs_FreeObject(in);
11592 - return YAFFS_OK;
11593 + in->hdr_chunk = newChunkId;
11594
11595 -}
11596 + if (prevChunkId > 0) {
11597 + yaffs_chunk_del(dev, prevChunkId, 1,
11598 + __LINE__);
11599 + }
11600
11601 -/* yaffs_DeleteFile deletes the whole file data
11602 - * and the inode associated with the file.
11603 - * It does not delete the links associated with the file.
11604 - */
11605 -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
11606 -{
11607 + if (!yaffs_obj_cache_dirty(in))
11608 + in->dirty = 0;
11609
11610 - int retVal;
11611 - int immediateDeletion = 0;
11612 + /* If this was a shrink, then mark the block that the chunk lives on */
11613 + if (is_shrink) {
11614 + bi = yaffs_get_block_info(in->my_dev,
11615 + newChunkId / in->my_dev->param.chunks_per_block);
11616 + bi->has_shrink_hdr = 1;
11617 + }
11618
11619 -#ifdef __KERNEL__
11620 - if (!in->myInode)
11621 - immediateDeletion = 1;
11622 -#else
11623 - if (in->inUse <= 0)
11624 - immediateDeletion = 1;
11625 -#endif
11626 + }
11627 +
11628 + retVal = newChunkId;
11629
11630 - if (immediateDeletion) {
11631 - retVal =
11632 - yaffs_ChangeObjectName(in, in->myDev->deletedDir,
11633 - _Y("deleted"), 0, 0);
11634 - T(YAFFS_TRACE_TRACING,
11635 - (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
11636 - in->objectId));
11637 - in->deleted = 1;
11638 - in->myDev->nDeletedFiles++;
11639 - if (1 || in->myDev->isYaffs2)
11640 - yaffs_ResizeFile(in, 0);
11641 - yaffs_SoftDeleteFile(in);
11642 - } else {
11643 - retVal =
11644 - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
11645 - _Y("unlinked"), 0, 0);
11646 }
11647
11648 + if (buffer)
11649 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
11650
11651 return retVal;
11652 }
11653
11654 -int yaffs_DeleteFile(yaffs_Object *in)
11655 -{
11656 - int retVal = YAFFS_OK;
11657 - int deleted = in->deleted;
11658 -
11659 - yaffs_ResizeFile(in, 0);
11660 -
11661 - if (in->nDataChunks > 0) {
11662 - /* Use soft deletion if there is data in the file.
11663 - * That won't be the case if it has been resized to zero.
11664 - */
11665 - if (!in->unlinked)
11666 - retVal = yaffs_UnlinkFileIfNeeded(in);
11667 -
11668 - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
11669 - in->deleted = 1;
11670 - deleted = 1;
11671 - in->myDev->nDeletedFiles++;
11672 - yaffs_SoftDeleteFile(in);
11673 - }
11674 - return deleted ? YAFFS_OK : YAFFS_FAIL;
11675 - } else {
11676 - /* The file has no data chunks so we toss it immediately */
11677 - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
11678 - in->variant.fileVariant.top = NULL;
11679 - yaffs_DoGenericObjectDeletion(in);
11680 -
11681 - return YAFFS_OK;
11682 - }
11683 -}
11684 +/*------------------------ Short Operations Cache ----------------------------------------
11685 + * In many situations where there is no high level buffering (eg WinCE) a lot of
11686 + * reads might be short sequential reads, and a lot of writes may be short
11687 + * sequential writes. eg. scanning/writing a jpeg file.
11688 + * In these cases, a short read/write cache can provide a huge perfomance benefit
11689 + * with dumb-as-a-rock code.
11690 + * In Linux, the page cache provides read buffering aand the short op cache provides write
11691 + * buffering.
11692 + *
11693 + * There are a limited number (~10) of cache chunks per device so that we don't
11694 + * need a very intelligent search.
11695 + */
11696
11697 -static int yaffs_DeleteDirectory(yaffs_Object *in)
11698 +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj)
11699 {
11700 - /* First check that the directory is empty. */
11701 - if (ylist_empty(&in->variant.directoryVariant.children))
11702 - return yaffs_DoGenericObjectDeletion(in);
11703 + yaffs_dev_t *dev = obj->my_dev;
11704 + int i;
11705 + yaffs_cache_t *cache;
11706 + int nCaches = obj->my_dev->param.n_caches;
11707
11708 - return YAFFS_FAIL;
11709 + for (i = 0; i < nCaches; i++) {
11710 + cache = &dev->cache[i];
11711 + if (cache->object == obj &&
11712 + cache->dirty)
11713 + return 1;
11714 + }
11715
11716 + return 0;
11717 }
11718
11719 -static int yaffs_DeleteSymLink(yaffs_Object *in)
11720 -{
11721 - YFREE(in->variant.symLinkVariant.alias);
11722 -
11723 - return yaffs_DoGenericObjectDeletion(in);
11724 -}
11725
11726 -static int yaffs_DeleteHardLink(yaffs_Object *in)
11727 +static void yaffs_flush_file_cache(yaffs_obj_t *obj)
11728 {
11729 - /* remove this hardlink from the list assocaited with the equivalent
11730 - * object
11731 - */
11732 - ylist_del_init(&in->hardLinks);
11733 - return yaffs_DoGenericObjectDeletion(in);
11734 -}
11735 + yaffs_dev_t *dev = obj->my_dev;
11736 + int lowest = -99; /* Stop compiler whining. */
11737 + int i;
11738 + yaffs_cache_t *cache;
11739 + int chunkWritten = 0;
11740 + int nCaches = obj->my_dev->param.n_caches;
11741
11742 -int yaffs_DeleteObject(yaffs_Object *obj)
11743 -{
11744 -int retVal = -1;
11745 - switch (obj->variantType) {
11746 - case YAFFS_OBJECT_TYPE_FILE:
11747 - retVal = yaffs_DeleteFile(obj);
11748 - break;
11749 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11750 - return yaffs_DeleteDirectory(obj);
11751 - break;
11752 - case YAFFS_OBJECT_TYPE_SYMLINK:
11753 - retVal = yaffs_DeleteSymLink(obj);
11754 - break;
11755 - case YAFFS_OBJECT_TYPE_HARDLINK:
11756 - retVal = yaffs_DeleteHardLink(obj);
11757 - break;
11758 - case YAFFS_OBJECT_TYPE_SPECIAL:
11759 - retVal = yaffs_DoGenericObjectDeletion(obj);
11760 - break;
11761 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11762 - retVal = 0;
11763 - break; /* should not happen. */
11764 - }
11765 + if (nCaches > 0) {
11766 + do {
11767 + cache = NULL;
11768
11769 - return retVal;
11770 -}
11771 + /* Find the dirty cache for this object with the lowest chunk id. */
11772 + for (i = 0; i < nCaches; i++) {
11773 + if (dev->cache[i].object == obj &&
11774 + dev->cache[i].dirty) {
11775 + if (!cache
11776 + || dev->cache[i].chunk_id <
11777 + lowest) {
11778 + cache = &dev->cache[i];
11779 + lowest = cache->chunk_id;
11780 + }
11781 + }
11782 + }
11783
11784 -static int yaffs_UnlinkWorker(yaffs_Object *obj)
11785 -{
11786 + if (cache && !cache->locked) {
11787 + /* Write it out and free it up */
11788
11789 - int immediateDeletion = 0;
11790 + chunkWritten =
11791 + yaffs_wr_data_obj(cache->object,
11792 + cache->chunk_id,
11793 + cache->data,
11794 + cache->n_bytes,
11795 + 1);
11796 + cache->dirty = 0;
11797 + cache->object = NULL;
11798 + }
11799
11800 -#ifdef __KERNEL__
11801 - if (!obj->myInode)
11802 - immediateDeletion = 1;
11803 -#else
11804 - if (obj->inUse <= 0)
11805 - immediateDeletion = 1;
11806 -#endif
11807 + } while (cache && chunkWritten > 0);
11808
11809 - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
11810 - return yaffs_DeleteHardLink(obj);
11811 - } else if (!ylist_empty(&obj->hardLinks)) {
11812 - /* Curve ball: We're unlinking an object that has a hardlink.
11813 - *
11814 - * This problem arises because we are not strictly following
11815 - * The Linux link/inode model.
11816 - *
11817 - * We can't really delete the object.
11818 - * Instead, we do the following:
11819 - * - Select a hardlink.
11820 - * - Unhook it from the hard links
11821 - * - Unhook it from its parent directory (so that the rename can work)
11822 - * - Rename the object to the hardlink's name.
11823 - * - Delete the hardlink
11824 - */
11825 + if (cache) {
11826 + /* Hoosterman, disk full while writing cache out. */
11827 + T(YAFFS_TRACE_ERROR,
11828 + (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
11829
11830 - yaffs_Object *hl;
11831 - int retVal;
11832 - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
11833 + }
11834 + }
11835
11836 - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
11837 +}
11838
11839 - ylist_del_init(&hl->hardLinks);
11840 - ylist_del_init(&hl->siblings);
11841 +/*yaffs_flush_whole_cache(dev)
11842 + *
11843 + *
11844 + */
11845
11846 - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
11847 +void yaffs_flush_whole_cache(yaffs_dev_t *dev)
11848 +{
11849 + yaffs_obj_t *obj;
11850 + int nCaches = dev->param.n_caches;
11851 + int i;
11852
11853 - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
11854 + /* Find a dirty object in the cache and flush it...
11855 + * until there are no further dirty objects.
11856 + */
11857 + do {
11858 + obj = NULL;
11859 + for (i = 0; i < nCaches && !obj; i++) {
11860 + if (dev->cache[i].object &&
11861 + dev->cache[i].dirty)
11862 + obj = dev->cache[i].object;
11863
11864 - if (retVal == YAFFS_OK)
11865 - retVal = yaffs_DoGenericObjectDeletion(hl);
11866 + }
11867 + if (obj)
11868 + yaffs_flush_file_cache(obj);
11869
11870 - return retVal;
11871 + } while (obj);
11872
11873 - } else if (immediateDeletion) {
11874 - switch (obj->variantType) {
11875 - case YAFFS_OBJECT_TYPE_FILE:
11876 - return yaffs_DeleteFile(obj);
11877 - break;
11878 - case YAFFS_OBJECT_TYPE_DIRECTORY:
11879 - return yaffs_DeleteDirectory(obj);
11880 - break;
11881 - case YAFFS_OBJECT_TYPE_SYMLINK:
11882 - return yaffs_DeleteSymLink(obj);
11883 - break;
11884 - case YAFFS_OBJECT_TYPE_SPECIAL:
11885 - return yaffs_DoGenericObjectDeletion(obj);
11886 - break;
11887 - case YAFFS_OBJECT_TYPE_HARDLINK:
11888 - case YAFFS_OBJECT_TYPE_UNKNOWN:
11889 - default:
11890 - return YAFFS_FAIL;
11891 - }
11892 - } else
11893 - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
11894 - _Y("unlinked"), 0, 0);
11895 }
11896
11897
11898 -static int yaffs_UnlinkObject(yaffs_Object *obj)
11899 +/* Grab us a cache chunk for use.
11900 + * First look for an empty one.
11901 + * Then look for the least recently used non-dirty one.
11902 + * Then look for the least recently used dirty one...., flush and look again.
11903 + */
11904 +static yaffs_cache_t *yaffs_grab_chunk_worker(yaffs_dev_t *dev)
11905 {
11906 + int i;
11907
11908 - if (obj && obj->unlinkAllowed)
11909 - return yaffs_UnlinkWorker(obj);
11910 -
11911 - return YAFFS_FAIL;
11912 -
11913 -}
11914 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
11915 -{
11916 - yaffs_Object *obj;
11917 + if (dev->param.n_caches > 0) {
11918 + for (i = 0; i < dev->param.n_caches; i++) {
11919 + if (!dev->cache[i].object)
11920 + return &dev->cache[i];
11921 + }
11922 + }
11923
11924 - obj = yaffs_FindObjectByName(dir, name);
11925 - return yaffs_UnlinkObject(obj);
11926 + return NULL;
11927 }
11928
11929 -/*----------------------- Initialisation Scanning ---------------------- */
11930 -
11931 -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
11932 - int backwardScanning)
11933 +static yaffs_cache_t *yaffs_grab_chunk_cache(yaffs_dev_t *dev)
11934 {
11935 - yaffs_Object *obj;
11936 + yaffs_cache_t *cache;
11937 + yaffs_obj_t *theObj;
11938 + int usage;
11939 + int i;
11940 + int pushout;
11941
11942 - if (!backwardScanning) {
11943 - /* Handle YAFFS1 forward scanning case
11944 - * For YAFFS1 we always do the deletion
11945 - */
11946 + if (dev->param.n_caches > 0) {
11947 + /* Try find a non-dirty one... */
11948
11949 - } else {
11950 - /* Handle YAFFS2 case (backward scanning)
11951 - * If the shadowed object exists then ignore.
11952 - */
11953 - if (yaffs_FindObjectByNumber(dev, objId))
11954 - return;
11955 - }
11956 + cache = yaffs_grab_chunk_worker(dev);
11957
11958 - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
11959 - * We put it in unlinked dir to be cleaned up after the scanning
11960 - */
11961 - obj =
11962 - yaffs_FindOrCreateObjectByNumber(dev, objId,
11963 - YAFFS_OBJECT_TYPE_FILE);
11964 - if (!obj)
11965 - return;
11966 - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
11967 - obj->variant.fileVariant.shrinkSize = 0;
11968 - obj->valid = 1; /* So that we don't read any other info for this file */
11969 + if (!cache) {
11970 + /* They were all dirty, find the last recently used object and flush
11971 + * its cache, then find again.
11972 + * NB what's here is not very accurate, we actually flush the object
11973 + * the last recently used page.
11974 + */
11975
11976 -}
11977 + /* With locking we can't assume we can use entry zero */
11978
11979 -typedef struct {
11980 - int seq;
11981 - int block;
11982 -} yaffs_BlockIndex;
11983 + theObj = NULL;
11984 + usage = -1;
11985 + cache = NULL;
11986 + pushout = -1;
11987
11988 + for (i = 0; i < dev->param.n_caches; i++) {
11989 + if (dev->cache[i].object &&
11990 + !dev->cache[i].locked &&
11991 + (dev->cache[i].last_use < usage || !cache)) {
11992 + usage = dev->cache[i].last_use;
11993 + theObj = dev->cache[i].object;
11994 + cache = &dev->cache[i];
11995 + pushout = i;
11996 + }
11997 + }
11998
11999 -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
12000 -{
12001 - yaffs_Object *hl;
12002 - yaffs_Object *in;
12003 + if (!cache || cache->dirty) {
12004 + /* Flush and try again */
12005 + yaffs_flush_file_cache(theObj);
12006 + cache = yaffs_grab_chunk_worker(dev);
12007 + }
12008
12009 - while (hardList) {
12010 - hl = hardList;
12011 - hardList = (yaffs_Object *) (hardList->hardLinks.next);
12012 + }
12013 + return cache;
12014 + } else
12015 + return NULL;
12016
12017 - in = yaffs_FindObjectByNumber(dev,
12018 - hl->variant.hardLinkVariant.
12019 - equivalentObjectId);
12020 +}
12021
12022 - if (in) {
12023 - /* Add the hardlink pointers */
12024 - hl->variant.hardLinkVariant.equivalentObject = in;
12025 - ylist_add(&hl->hardLinks, &in->hardLinks);
12026 - } else {
12027 - /* Todo Need to report/handle this better.
12028 - * Got a problem... hardlink to a non-existant object
12029 - */
12030 - hl->variant.hardLinkVariant.equivalentObject = NULL;
12031 - YINIT_LIST_HEAD(&hl->hardLinks);
12032 +/* Find a cached chunk */
12033 +static yaffs_cache_t *yaffs_find_chunk_cache(const yaffs_obj_t *obj,
12034 + int chunk_id)
12035 +{
12036 + yaffs_dev_t *dev = obj->my_dev;
12037 + int i;
12038 + if (dev->param.n_caches > 0) {
12039 + for (i = 0; i < dev->param.n_caches; i++) {
12040 + if (dev->cache[i].object == obj &&
12041 + dev->cache[i].chunk_id == chunk_id) {
12042 + dev->cache_hits++;
12043
12044 + return &dev->cache[i];
12045 + }
12046 }
12047 }
12048 + return NULL;
12049 }
12050
12051 +/* Mark the chunk for the least recently used algorithym */
12052 +static void yaffs_use_cache(yaffs_dev_t *dev, yaffs_cache_t *cache,
12053 + int isAWrite)
12054 +{
12055 +
12056 + if (dev->param.n_caches > 0) {
12057 + if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) {
12058 + /* Reset the cache usages */
12059 + int i;
12060 + for (i = 1; i < dev->param.n_caches; i++)
12061 + dev->cache[i].last_use = 0;
12062
12063 + dev->cache_last_use = 0;
12064 + }
12065
12066 + dev->cache_last_use++;
12067
12068 + cache->last_use = dev->cache_last_use;
12069
12070 -static int ybicmp(const void *a, const void *b)
12071 -{
12072 - register int aseq = ((yaffs_BlockIndex *)a)->seq;
12073 - register int bseq = ((yaffs_BlockIndex *)b)->seq;
12074 - register int ablock = ((yaffs_BlockIndex *)a)->block;
12075 - register int bblock = ((yaffs_BlockIndex *)b)->block;
12076 - if (aseq == bseq)
12077 - return ablock - bblock;
12078 - else
12079 - return aseq - bseq;
12080 + if (isAWrite)
12081 + cache->dirty = 1;
12082 + }
12083 }
12084
12085 +/* Invalidate a single cache page.
12086 + * Do this when a whole page gets written,
12087 + * ie the short cache for this page is no longer valid.
12088 + */
12089 +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id)
12090 +{
12091 + if (object->my_dev->param.n_caches > 0) {
12092 + yaffs_cache_t *cache = yaffs_find_chunk_cache(object, chunk_id);
12093
12094 -struct yaffs_ShadowFixerStruct {
12095 - int objectId;
12096 - int shadowedId;
12097 - struct yaffs_ShadowFixerStruct *next;
12098 -};
12099 -
12100 + if (cache)
12101 + cache->object = NULL;
12102 + }
12103 +}
12104
12105 -static void yaffs_StripDeletedObjects(yaffs_Device *dev)
12106 +/* Invalidate all the cache pages associated with this object
12107 + * Do this whenever ther file is deleted or resized.
12108 + */
12109 +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in)
12110 {
12111 - /*
12112 - * Sort out state of unlinked and deleted objects after scanning.
12113 - */
12114 - struct ylist_head *i;
12115 - struct ylist_head *n;
12116 - yaffs_Object *l;
12117 + int i;
12118 + yaffs_dev_t *dev = in->my_dev;
12119
12120 - /* Soft delete all the unlinked files */
12121 - ylist_for_each_safe(i, n,
12122 - &dev->unlinkedDir->variant.directoryVariant.children) {
12123 - if (i) {
12124 - l = ylist_entry(i, yaffs_Object, siblings);
12125 - yaffs_DeleteObject(l);
12126 + if (dev->param.n_caches > 0) {
12127 + /* Invalidate it. */
12128 + for (i = 0; i < dev->param.n_caches; i++) {
12129 + if (dev->cache[i].object == in)
12130 + dev->cache[i].object = NULL;
12131 }
12132 }
12133 +}
12134
12135 - ylist_for_each_safe(i, n,
12136 - &dev->deletedDir->variant.directoryVariant.children) {
12137 - if (i) {
12138 - l = ylist_entry(i, yaffs_Object, siblings);
12139 - yaffs_DeleteObject(l);
12140 - }
12141 - }
12142
12143 -}
12144 +/*--------------------- File read/write ------------------------
12145 + * Read and write have very similar structures.
12146 + * In general the read/write has three parts to it
12147 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
12148 + * Some complete chunks
12149 + * An incomplete chunk to end off with
12150 + *
12151 + * Curve-balls: the first chunk might also be the last chunk.
12152 + */
12153
12154 -static int yaffs_Scan(yaffs_Device *dev)
12155 +int yaffs_file_rd(yaffs_obj_t *in, __u8 *buffer, loff_t offset,
12156 + int n_bytes)
12157 {
12158 - yaffs_ExtendedTags tags;
12159 - int blk;
12160 - int blockIterator;
12161 - int startIterator;
12162 - int endIterator;
12163 - int result;
12164
12165 int chunk;
12166 - int c;
12167 - int deleted;
12168 - yaffs_BlockState state;
12169 - yaffs_Object *hardList = NULL;
12170 - yaffs_BlockInfo *bi;
12171 - __u32 sequenceNumber;
12172 - yaffs_ObjectHeader *oh;
12173 - yaffs_Object *in;
12174 - yaffs_Object *parent;
12175 + __u32 start;
12176 + int nToCopy;
12177 + int n = n_bytes;
12178 + int nDone = 0;
12179 + yaffs_cache_t *cache;
12180
12181 - int alloc_failed = 0;
12182 + yaffs_dev_t *dev;
12183
12184 - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
12185 + dev = in->my_dev;
12186
12187 + while (n > 0) {
12188 + /* chunk = offset / dev->data_bytes_per_chunk + 1; */
12189 + /* start = offset % dev->data_bytes_per_chunk; */
12190 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
12191 + chunk++;
12192
12193 - __u8 *chunkData;
12194 + /* OK now check for the curveball where the start and end are in
12195 + * the same chunk.
12196 + */
12197 + if ((start + n) < dev->data_bytes_per_chunk)
12198 + nToCopy = n;
12199 + else
12200 + nToCopy = dev->data_bytes_per_chunk - start;
12201
12202 + cache = yaffs_find_chunk_cache(in, chunk);
12203
12204 + /* If the chunk is already in the cache or it is less than a whole chunk
12205 + * or we're using inband tags then use the cache (if there is caching)
12206 + * else bypass the cache.
12207 + */
12208 + if (cache || nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
12209 + if (dev->param.n_caches > 0) {
12210
12211 - T(YAFFS_TRACE_SCAN,
12212 - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
12213 - dev->internalStartBlock, dev->internalEndBlock));
12214 + /* If we can't find the data in the cache, then load it up. */
12215
12216 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12217 + if (!cache) {
12218 + cache = yaffs_grab_chunk_cache(in->my_dev);
12219 + cache->object = in;
12220 + cache->chunk_id = chunk;
12221 + cache->dirty = 0;
12222 + cache->locked = 0;
12223 + yaffs_rd_data_obj(in, chunk,
12224 + cache->
12225 + data);
12226 + cache->n_bytes = 0;
12227 + }
12228
12229 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12230 + yaffs_use_cache(dev, cache, 0);
12231
12232 - /* Scan all the blocks to determine their state */
12233 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
12234 - bi = yaffs_GetBlockInfo(dev, blk);
12235 - yaffs_ClearChunkBits(dev, blk);
12236 - bi->pagesInUse = 0;
12237 - bi->softDeletions = 0;
12238 + cache->locked = 1;
12239
12240 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
12241
12242 - bi->blockState = state;
12243 - bi->sequenceNumber = sequenceNumber;
12244 + memcpy(buffer, &cache->data[start], nToCopy);
12245
12246 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
12247 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
12248 + cache->locked = 0;
12249 + } else {
12250 + /* Read into the local buffer then copy..*/
12251
12252 - T(YAFFS_TRACE_SCAN_DEBUG,
12253 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
12254 - state, sequenceNumber));
12255 + __u8 *localBuffer =
12256 + yaffs_get_temp_buffer(dev, __LINE__);
12257 + yaffs_rd_data_obj(in, chunk,
12258 + localBuffer);
12259
12260 - if (state == YAFFS_BLOCK_STATE_DEAD) {
12261 - T(YAFFS_TRACE_BAD_BLOCKS,
12262 - (TSTR("block %d is bad" TENDSTR), blk));
12263 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
12264 - T(YAFFS_TRACE_SCAN_DEBUG,
12265 - (TSTR("Block empty " TENDSTR)));
12266 - dev->nErasedBlocks++;
12267 - dev->nFreeChunks += dev->nChunksPerBlock;
12268 - }
12269 - }
12270 + memcpy(buffer, &localBuffer[start], nToCopy);
12271
12272 - startIterator = dev->internalStartBlock;
12273 - endIterator = dev->internalEndBlock;
12274
12275 - /* For each block.... */
12276 - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
12277 - blockIterator++) {
12278 + yaffs_release_temp_buffer(dev, localBuffer,
12279 + __LINE__);
12280 + }
12281
12282 - YYIELD();
12283 + } else {
12284
12285 - YYIELD();
12286 + /* A full chunk. Read directly into the supplied buffer. */
12287 + yaffs_rd_data_obj(in, chunk, buffer);
12288
12289 - blk = blockIterator;
12290 + }
12291
12292 - bi = yaffs_GetBlockInfo(dev, blk);
12293 - state = bi->blockState;
12294 + n -= nToCopy;
12295 + offset += nToCopy;
12296 + buffer += nToCopy;
12297 + nDone += nToCopy;
12298
12299 - deleted = 0;
12300 + }
12301
12302 - /* For each chunk in each block that needs scanning....*/
12303 - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
12304 - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
12305 - /* Read the tags and decide what to do */
12306 - chunk = blk * dev->nChunksPerBlock + c;
12307 + return nDone;
12308 +}
12309
12310 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
12311 - &tags);
12312 +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
12313 + int n_bytes, int write_trhrough)
12314 +{
12315
12316 - /* Let's have a good look at this chunk... */
12317 + int chunk;
12318 + __u32 start;
12319 + int nToCopy;
12320 + int n = n_bytes;
12321 + int nDone = 0;
12322 + int nToWriteBack;
12323 + int startOfWrite = offset;
12324 + int chunkWritten = 0;
12325 + __u32 n_bytesRead;
12326 + __u32 chunkStart;
12327
12328 - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
12329 - /* YAFFS1 only...
12330 - * A deleted chunk
12331 - */
12332 - deleted++;
12333 - dev->nFreeChunks++;
12334 - /*T((" %d %d deleted\n",blk,c)); */
12335 - } else if (!tags.chunkUsed) {
12336 - /* An unassigned chunk in the block
12337 - * This means that either the block is empty or
12338 - * this is the one being allocated from
12339 - */
12340 + yaffs_dev_t *dev;
12341
12342 - if (c == 0) {
12343 - /* We're looking at the first chunk in the block so the block is unused */
12344 - state = YAFFS_BLOCK_STATE_EMPTY;
12345 - dev->nErasedBlocks++;
12346 - } else {
12347 - /* this is the block being allocated from */
12348 - T(YAFFS_TRACE_SCAN,
12349 - (TSTR
12350 - (" Allocating from %d %d" TENDSTR),
12351 - blk, c));
12352 - state = YAFFS_BLOCK_STATE_ALLOCATING;
12353 - dev->allocationBlock = blk;
12354 - dev->allocationPage = c;
12355 - dev->allocationBlockFinder = blk;
12356 - /* Set it to here to encourage the allocator to go forth from here. */
12357 + dev = in->my_dev;
12358
12359 - }
12360 + while (n > 0 && chunkWritten >= 0) {
12361 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
12362
12363 - dev->nFreeChunks += (dev->nChunksPerBlock - c);
12364 - } else if (tags.chunkId > 0) {
12365 - /* chunkId > 0 so it is a data chunk... */
12366 - unsigned int endpos;
12367 -
12368 - yaffs_SetChunkBit(dev, blk, c);
12369 - bi->pagesInUse++;
12370 -
12371 - in = yaffs_FindOrCreateObjectByNumber(dev,
12372 - tags.
12373 - objectId,
12374 - YAFFS_OBJECT_TYPE_FILE);
12375 - /* PutChunkIntoFile checks for a clash (two data chunks with
12376 - * the same chunkId).
12377 - */
12378 + if (chunk * dev->data_bytes_per_chunk + start != offset ||
12379 + start >= dev->data_bytes_per_chunk) {
12380 + T(YAFFS_TRACE_ERROR, (
12381 + TSTR("AddrToChunk of offset %d gives chunk %d start %d"
12382 + TENDSTR),
12383 + (int)offset, chunk, start));
12384 + }
12385 + chunk++; /* File pos to chunk in file offset */
12386
12387 - if (!in)
12388 - alloc_failed = 1;
12389 + /* OK now check for the curveball where the start and end are in
12390 + * the same chunk.
12391 + */
12392
12393 - if (in) {
12394 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
12395 - alloc_failed = 1;
12396 - }
12397 + if ((start + n) < dev->data_bytes_per_chunk) {
12398 + nToCopy = n;
12399
12400 - endpos =
12401 - (tags.chunkId - 1) * dev->nDataBytesPerChunk +
12402 - tags.byteCount;
12403 - if (in &&
12404 - in->variantType == YAFFS_OBJECT_TYPE_FILE
12405 - && in->variant.fileVariant.scannedFileSize <
12406 - endpos) {
12407 - in->variant.fileVariant.
12408 - scannedFileSize = endpos;
12409 - if (!dev->useHeaderFileSize) {
12410 - in->variant.fileVariant.
12411 - fileSize =
12412 - in->variant.fileVariant.
12413 - scannedFileSize;
12414 - }
12415 + /* Now folks, to calculate how many bytes to write back....
12416 + * If we're overwriting and not writing to then end of file then
12417 + * we need to write back as much as was there before.
12418 + */
12419
12420 - }
12421 - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
12422 - } else {
12423 - /* chunkId == 0, so it is an ObjectHeader.
12424 - * Thus, we read in the object header and make the object
12425 - */
12426 - yaffs_SetChunkBit(dev, blk, c);
12427 - bi->pagesInUse++;
12428 + chunkStart = ((chunk - 1) * dev->data_bytes_per_chunk);
12429
12430 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
12431 - chunkData,
12432 - NULL);
12433 -
12434 - oh = (yaffs_ObjectHeader *) chunkData;
12435 -
12436 - in = yaffs_FindObjectByNumber(dev,
12437 - tags.objectId);
12438 - if (in && in->variantType != oh->type) {
12439 - /* This should not happen, but somehow
12440 - * Wev'e ended up with an objectId that has been reused but not yet
12441 - * deleted, and worse still it has changed type. Delete the old object.
12442 - */
12443 + if (chunkStart > in->variant.file_variant.file_size)
12444 + n_bytesRead = 0; /* Past end of file */
12445 + else
12446 + n_bytesRead = in->variant.file_variant.file_size - chunkStart;
12447
12448 - yaffs_DeleteObject(in);
12449 + if (n_bytesRead > dev->data_bytes_per_chunk)
12450 + n_bytesRead = dev->data_bytes_per_chunk;
12451
12452 - in = 0;
12453 - }
12454 + nToWriteBack =
12455 + (n_bytesRead >
12456 + (start + n)) ? n_bytesRead : (start + n);
12457
12458 - in = yaffs_FindOrCreateObjectByNumber(dev,
12459 - tags.
12460 - objectId,
12461 - oh->type);
12462 -
12463 - if (!in)
12464 - alloc_failed = 1;
12465 -
12466 - if (in && oh->shadowsObject > 0) {
12467 -
12468 - struct yaffs_ShadowFixerStruct *fixer;
12469 - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
12470 - if (fixer) {
12471 - fixer->next = shadowFixerList;
12472 - shadowFixerList = fixer;
12473 - fixer->objectId = tags.objectId;
12474 - fixer->shadowedId = oh->shadowsObject;
12475 - }
12476 + if (nToWriteBack < 0 || nToWriteBack > dev->data_bytes_per_chunk)
12477 + YBUG();
12478 +
12479 + } else {
12480 + nToCopy = dev->data_bytes_per_chunk - start;
12481 + nToWriteBack = dev->data_bytes_per_chunk;
12482 + }
12483 +
12484 + if (nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
12485 + /* An incomplete start or end chunk (or maybe both start and end chunk),
12486 + * or we're using inband tags, so we want to use the cache buffers.
12487 + */
12488 + if (dev->param.n_caches > 0) {
12489 + yaffs_cache_t *cache;
12490 + /* If we can't find the data in the cache, then load the cache */
12491 + cache = yaffs_find_chunk_cache(in, chunk);
12492
12493 + if (!cache
12494 + && yaffs_check_alloc_available(dev, 1)) {
12495 + cache = yaffs_grab_chunk_cache(dev);
12496 + cache->object = in;
12497 + cache->chunk_id = chunk;
12498 + cache->dirty = 0;
12499 + cache->locked = 0;
12500 + yaffs_rd_data_obj(in, chunk,
12501 + cache->data);
12502 + } else if (cache &&
12503 + !cache->dirty &&
12504 + !yaffs_check_alloc_available(dev, 1)) {
12505 + /* Drop the cache if it was a read cache item and
12506 + * no space check has been made for it.
12507 + */
12508 + cache = NULL;
12509 }
12510
12511 - if (in && in->valid) {
12512 - /* We have already filled this one. We have a duplicate and need to resolve it. */
12513 + if (cache) {
12514 + yaffs_use_cache(dev, cache, 1);
12515 + cache->locked = 1;
12516
12517 - unsigned existingSerial = in->serial;
12518 - unsigned newSerial = tags.serialNumber;
12519
12520 - if (((existingSerial + 1) & 3) == newSerial) {
12521 - /* Use new one - destroy the exisiting one */
12522 - yaffs_DeleteChunk(dev,
12523 - in->hdrChunk,
12524 - 1, __LINE__);
12525 - in->valid = 0;
12526 - } else {
12527 - /* Use existing - destroy this one. */
12528 - yaffs_DeleteChunk(dev, chunk, 1,
12529 - __LINE__);
12530 + memcpy(&cache->data[start], buffer,
12531 + nToCopy);
12532 +
12533 +
12534 + cache->locked = 0;
12535 + cache->n_bytes = nToWriteBack;
12536 +
12537 + if (write_trhrough) {
12538 + chunkWritten =
12539 + yaffs_wr_data_obj
12540 + (cache->object,
12541 + cache->chunk_id,
12542 + cache->data, cache->n_bytes,
12543 + 1);
12544 + cache->dirty = 0;
12545 }
12546 +
12547 + } else {
12548 + chunkWritten = -1; /* fail the write */
12549 }
12550 + } else {
12551 + /* An incomplete start or end chunk (or maybe both start and end chunk)
12552 + * Read into the local buffer then copy, then copy over and write back.
12553 + */
12554
12555 - if (in && !in->valid &&
12556 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
12557 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
12558 - /* We only load some info, don't fiddle with directory structure */
12559 - in->valid = 1;
12560 - in->variantType = oh->type;
12561 + __u8 *localBuffer =
12562 + yaffs_get_temp_buffer(dev, __LINE__);
12563
12564 - in->yst_mode = oh->yst_mode;
12565 -#ifdef CONFIG_YAFFS_WINCE
12566 - in->win_atime[0] = oh->win_atime[0];
12567 - in->win_ctime[0] = oh->win_ctime[0];
12568 - in->win_mtime[0] = oh->win_mtime[0];
12569 - in->win_atime[1] = oh->win_atime[1];
12570 - in->win_ctime[1] = oh->win_ctime[1];
12571 - in->win_mtime[1] = oh->win_mtime[1];
12572 -#else
12573 - in->yst_uid = oh->yst_uid;
12574 - in->yst_gid = oh->yst_gid;
12575 - in->yst_atime = oh->yst_atime;
12576 - in->yst_mtime = oh->yst_mtime;
12577 - in->yst_ctime = oh->yst_ctime;
12578 - in->yst_rdev = oh->yst_rdev;
12579 -#endif
12580 - in->hdrChunk = chunk;
12581 - in->serial = tags.serialNumber;
12582 + yaffs_rd_data_obj(in, chunk,
12583 + localBuffer);
12584
12585 - } else if (in && !in->valid) {
12586 - /* we need to load this info */
12587
12588 - in->valid = 1;
12589 - in->variantType = oh->type;
12590
12591 - in->yst_mode = oh->yst_mode;
12592 -#ifdef CONFIG_YAFFS_WINCE
12593 - in->win_atime[0] = oh->win_atime[0];
12594 - in->win_ctime[0] = oh->win_ctime[0];
12595 - in->win_mtime[0] = oh->win_mtime[0];
12596 - in->win_atime[1] = oh->win_atime[1];
12597 - in->win_ctime[1] = oh->win_ctime[1];
12598 - in->win_mtime[1] = oh->win_mtime[1];
12599 -#else
12600 - in->yst_uid = oh->yst_uid;
12601 - in->yst_gid = oh->yst_gid;
12602 - in->yst_atime = oh->yst_atime;
12603 - in->yst_mtime = oh->yst_mtime;
12604 - in->yst_ctime = oh->yst_ctime;
12605 - in->yst_rdev = oh->yst_rdev;
12606 -#endif
12607 - in->hdrChunk = chunk;
12608 - in->serial = tags.serialNumber;
12609 + memcpy(&localBuffer[start], buffer, nToCopy);
12610
12611 - yaffs_SetObjectName(in, oh->name);
12612 - in->dirty = 0;
12613 + chunkWritten =
12614 + yaffs_wr_data_obj(in, chunk,
12615 + localBuffer,
12616 + nToWriteBack,
12617 + 0);
12618
12619 - /* directory stuff...
12620 - * hook up to parent
12621 - */
12622 + yaffs_release_temp_buffer(dev, localBuffer,
12623 + __LINE__);
12624
12625 - parent =
12626 - yaffs_FindOrCreateObjectByNumber
12627 - (dev, oh->parentObjectId,
12628 - YAFFS_OBJECT_TYPE_DIRECTORY);
12629 - if (!parent)
12630 - alloc_failed = 1;
12631 - if (parent && parent->variantType ==
12632 - YAFFS_OBJECT_TYPE_UNKNOWN) {
12633 - /* Set up as a directory */
12634 - parent->variantType =
12635 - YAFFS_OBJECT_TYPE_DIRECTORY;
12636 - YINIT_LIST_HEAD(&parent->variant.
12637 - directoryVariant.
12638 - children);
12639 - } else if (!parent || parent->variantType !=
12640 - YAFFS_OBJECT_TYPE_DIRECTORY) {
12641 - /* Hoosterman, another problem....
12642 - * We're trying to use a non-directory as a directory
12643 - */
12644 + }
12645
12646 - T(YAFFS_TRACE_ERROR,
12647 - (TSTR
12648 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
12649 - TENDSTR)));
12650 - parent = dev->lostNFoundDir;
12651 - }
12652 + } else {
12653 + /* A full chunk. Write directly from the supplied buffer. */
12654
12655 - yaffs_AddObjectToDirectory(parent, in);
12656
12657 - if (0 && (parent == dev->deletedDir ||
12658 - parent == dev->unlinkedDir)) {
12659 - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
12660 - dev->nDeletedFiles++;
12661 - }
12662 - /* Note re hardlinks.
12663 - * Since we might scan a hardlink before its equivalent object is scanned
12664 - * we put them all in a list.
12665 - * After scanning is complete, we should have all the objects, so we run through this
12666 - * list and fix up all the chains.
12667 - */
12668
12669 - switch (in->variantType) {
12670 - case YAFFS_OBJECT_TYPE_UNKNOWN:
12671 - /* Todo got a problem */
12672 - break;
12673 - case YAFFS_OBJECT_TYPE_FILE:
12674 - if (dev->useHeaderFileSize)
12675 -
12676 - in->variant.fileVariant.
12677 - fileSize =
12678 - oh->fileSize;
12679 -
12680 - break;
12681 - case YAFFS_OBJECT_TYPE_HARDLINK:
12682 - in->variant.hardLinkVariant.
12683 - equivalentObjectId =
12684 - oh->equivalentObjectId;
12685 - in->hardLinks.next =
12686 - (struct ylist_head *)
12687 - hardList;
12688 - hardList = in;
12689 - break;
12690 - case YAFFS_OBJECT_TYPE_DIRECTORY:
12691 - /* Do nothing */
12692 - break;
12693 - case YAFFS_OBJECT_TYPE_SPECIAL:
12694 - /* Do nothing */
12695 - break;
12696 - case YAFFS_OBJECT_TYPE_SYMLINK:
12697 - in->variant.symLinkVariant.alias =
12698 - yaffs_CloneString(oh->alias);
12699 - if (!in->variant.symLinkVariant.alias)
12700 - alloc_failed = 1;
12701 - break;
12702 - }
12703 + chunkWritten =
12704 + yaffs_wr_data_obj(in, chunk, buffer,
12705 + dev->data_bytes_per_chunk,
12706 + 0);
12707
12708 -/*
12709 - if (parent == dev->deletedDir) {
12710 - yaffs_DestroyObject(in);
12711 - bi->hasShrinkHeader = 1;
12712 - }
12713 -*/
12714 - }
12715 - }
12716 + /* Since we've overwritten the cached data, we better invalidate it. */
12717 + yaffs_invalidate_chunk_cache(in, chunk);
12718 }
12719
12720 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
12721 - /* If we got this far while scanning, then the block is fully allocated.*/
12722 - state = YAFFS_BLOCK_STATE_FULL;
12723 + if (chunkWritten >= 0) {
12724 + n -= nToCopy;
12725 + offset += nToCopy;
12726 + buffer += nToCopy;
12727 + nDone += nToCopy;
12728 }
12729
12730 - bi->blockState = state;
12731 + }
12732
12733 - /* Now let's see if it was dirty */
12734 - if (bi->pagesInUse == 0 &&
12735 - !bi->hasShrinkHeader &&
12736 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
12737 - yaffs_BlockBecameDirty(dev, blk);
12738 - }
12739 + /* Update file object */
12740
12741 - }
12742 + if ((startOfWrite + nDone) > in->variant.file_variant.file_size)
12743 + in->variant.file_variant.file_size = (startOfWrite + nDone);
12744
12745 + in->dirty = 1;
12746
12747 - /* Ok, we've done all the scanning.
12748 - * Fix up the hard link chains.
12749 - * We should now have scanned all the objects, now it's time to add these
12750 - * hardlinks.
12751 - */
12752 + return nDone;
12753 +}
12754
12755 - yaffs_HardlinkFixup(dev, hardList);
12756 +int yaffs_wr_file(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
12757 + int n_bytes, int write_trhrough)
12758 +{
12759 + yaffs2_handle_hole(in,offset);
12760 + return yaffs_do_file_wr(in,buffer,offset,n_bytes,write_trhrough);
12761 +}
12762
12763 - /* Fix up any shadowed objects */
12764 - {
12765 - struct yaffs_ShadowFixerStruct *fixer;
12766 - yaffs_Object *obj;
12767 -
12768 - while (shadowFixerList) {
12769 - fixer = shadowFixerList;
12770 - shadowFixerList = fixer->next;
12771 - /* Complete the rename transaction by deleting the shadowed object
12772 - * then setting the object header to unshadowed.
12773 - */
12774 - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
12775 - if (obj)
12776 - yaffs_DeleteObject(obj);
12777
12778 - obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
12779
12780 - if (obj)
12781 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
12782 +/* ---------------------- File resizing stuff ------------------ */
12783
12784 - YFREE(fixer);
12785 - }
12786 - }
12787 +static void yaffs_prune_chunks(yaffs_obj_t *in, int new_size)
12788 +{
12789
12790 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12791 + yaffs_dev_t *dev = in->my_dev;
12792 + int oldFileSize = in->variant.file_variant.file_size;
12793
12794 - if (alloc_failed)
12795 - return YAFFS_FAIL;
12796 + int lastDel = 1 + (oldFileSize - 1) / dev->data_bytes_per_chunk;
12797 +
12798 + int startDel = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
12799 + dev->data_bytes_per_chunk;
12800 + int i;
12801 + int chunk_id;
12802
12803 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
12804 + /* Delete backwards so that we don't end up with holes if
12805 + * power is lost part-way through the operation.
12806 + */
12807 + for (i = lastDel; i >= startDel; i--) {
12808 + /* NB this could be optimised somewhat,
12809 + * eg. could retrieve the tags and write them without
12810 + * using yaffs_chunk_del
12811 + */
12812
12813 + chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
12814 + if (chunk_id > 0) {
12815 + if (chunk_id <
12816 + (dev->internal_start_block * dev->param.chunks_per_block)
12817 + || chunk_id >=
12818 + ((dev->internal_end_block +
12819 + 1) * dev->param.chunks_per_block)) {
12820 + T(YAFFS_TRACE_ALWAYS,
12821 + (TSTR("Found daft chunk_id %d for %d" TENDSTR),
12822 + chunk_id, i));
12823 + } else {
12824 + in->n_data_chunks--;
12825 + yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
12826 + }
12827 + }
12828 + }
12829
12830 - return YAFFS_OK;
12831 }
12832
12833 -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
12834 -{
12835 - __u8 *chunkData;
12836 - yaffs_ObjectHeader *oh;
12837 - yaffs_Device *dev;
12838 - yaffs_ExtendedTags tags;
12839 - int result;
12840 - int alloc_failed = 0;
12841
12842 - if (!in)
12843 - return;
12844 +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size)
12845 +{
12846 + int newFullChunks;
12847 + __u32 new_sizeOfPartialChunk;
12848 + yaffs_dev_t *dev = obj->my_dev;
12849
12850 - dev = in->myDev;
12851 + yaffs_addr_to_chunk(dev, new_size, &newFullChunks, &new_sizeOfPartialChunk);
12852
12853 -#if 0
12854 - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
12855 - in->objectId,
12856 - in->lazyLoaded ? "not yet" : "already"));
12857 -#endif
12858 + yaffs_prune_chunks(obj, new_size);
12859
12860 - if (in->lazyLoaded && in->hdrChunk > 0) {
12861 - in->lazyLoaded = 0;
12862 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
12863 + if (new_sizeOfPartialChunk != 0) {
12864 + int lastChunk = 1 + newFullChunks;
12865 + __u8 *localBuffer = yaffs_get_temp_buffer(dev, __LINE__);
12866
12867 - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
12868 - oh = (yaffs_ObjectHeader *) chunkData;
12869 + /* Got to read and rewrite the last chunk with its new size and zero pad */
12870 + yaffs_rd_data_obj(obj, lastChunk, localBuffer);
12871 + memset(localBuffer + new_sizeOfPartialChunk, 0,
12872 + dev->data_bytes_per_chunk - new_sizeOfPartialChunk);
12873
12874 - in->yst_mode = oh->yst_mode;
12875 -#ifdef CONFIG_YAFFS_WINCE
12876 - in->win_atime[0] = oh->win_atime[0];
12877 - in->win_ctime[0] = oh->win_ctime[0];
12878 - in->win_mtime[0] = oh->win_mtime[0];
12879 - in->win_atime[1] = oh->win_atime[1];
12880 - in->win_ctime[1] = oh->win_ctime[1];
12881 - in->win_mtime[1] = oh->win_mtime[1];
12882 -#else
12883 - in->yst_uid = oh->yst_uid;
12884 - in->yst_gid = oh->yst_gid;
12885 - in->yst_atime = oh->yst_atime;
12886 - in->yst_mtime = oh->yst_mtime;
12887 - in->yst_ctime = oh->yst_ctime;
12888 - in->yst_rdev = oh->yst_rdev;
12889 + yaffs_wr_data_obj(obj, lastChunk, localBuffer,
12890 + new_sizeOfPartialChunk, 1);
12891
12892 -#endif
12893 - yaffs_SetObjectName(in, oh->name);
12894 + yaffs_release_temp_buffer(dev, localBuffer, __LINE__);
12895 + }
12896
12897 - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
12898 - in->variant.symLinkVariant.alias =
12899 - yaffs_CloneString(oh->alias);
12900 - if (!in->variant.symLinkVariant.alias)
12901 - alloc_failed = 1; /* Not returned to caller */
12902 - }
12903 + obj->variant.file_variant.file_size = new_size;
12904
12905 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
12906 - }
12907 + yaffs_prune_tree(dev, &obj->variant.file_variant);
12908 }
12909
12910 -static int yaffs_ScanBackwards(yaffs_Device *dev)
12911 -{
12912 - yaffs_ExtendedTags tags;
12913 - int blk;
12914 - int blockIterator;
12915 - int startIterator;
12916 - int endIterator;
12917 - int nBlocksToScan = 0;
12918 -
12919 - int chunk;
12920 - int result;
12921 - int c;
12922 - int deleted;
12923 - yaffs_BlockState state;
12924 - yaffs_Object *hardList = NULL;
12925 - yaffs_BlockInfo *bi;
12926 - __u32 sequenceNumber;
12927 - yaffs_ObjectHeader *oh;
12928 - yaffs_Object *in;
12929 - yaffs_Object *parent;
12930 - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
12931 - int itsUnlinked;
12932 - __u8 *chunkData;
12933
12934 - int fileSize;
12935 - int isShrink;
12936 - int foundChunksInBlock;
12937 - int equivalentObjectId;
12938 - int alloc_failed = 0;
12939 +int yaffs_resize_file(yaffs_obj_t *in, loff_t new_size)
12940 +{
12941 + yaffs_dev_t *dev = in->my_dev;
12942 + int oldFileSize = in->variant.file_variant.file_size;
12943
12944 + yaffs_flush_file_cache(in);
12945 + yaffs_invalidate_whole_cache(in);
12946
12947 - yaffs_BlockIndex *blockIndex = NULL;
12948 - int altBlockIndex = 0;
12949 + yaffs_check_gc(dev,0);
12950
12951 - if (!dev->isYaffs2) {
12952 - T(YAFFS_TRACE_SCAN,
12953 - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
12954 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
12955 return YAFFS_FAIL;
12956 - }
12957
12958 - T(YAFFS_TRACE_SCAN,
12959 - (TSTR
12960 - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
12961 - TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
12962 + if (new_size == oldFileSize)
12963 + return YAFFS_OK;
12964 +
12965 + if(new_size > oldFileSize){
12966 + yaffs2_handle_hole(in,new_size);
12967 + in->variant.file_variant.file_size = new_size;
12968 + } else {
12969 + /* new_size < oldFileSize */
12970 + yaffs_resize_file_down(in, new_size);
12971 + }
12972
12973 + /* Write a new object header to reflect the resize.
12974 + * show we've shrunk the file, if need be
12975 + * Do this only if the file is not in the deleted directories
12976 + * and is not shadowed.
12977 + */
12978 + if (in->parent &&
12979 + !in->is_shadowed &&
12980 + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
12981 + in->parent->obj_id != YAFFS_OBJECTID_DELETED)
12982 + yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
12983
12984 - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
12985
12986 - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
12987 + return YAFFS_OK;
12988 +}
12989
12990 - if (!blockIndex) {
12991 - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
12992 - altBlockIndex = 1;
12993 - }
12994 +loff_t yaffs_get_file_size(yaffs_obj_t *obj)
12995 +{
12996 + YCHAR *alias = NULL;
12997 + obj = yaffs_get_equivalent_obj(obj);
12998
12999 - if (!blockIndex) {
13000 - T(YAFFS_TRACE_SCAN,
13001 - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
13002 - return YAFFS_FAIL;
13003 + switch (obj->variant_type) {
13004 + case YAFFS_OBJECT_TYPE_FILE:
13005 + return obj->variant.file_variant.file_size;
13006 + case YAFFS_OBJECT_TYPE_SYMLINK:
13007 + alias = obj->variant.symlink_variant.alias;
13008 + if(!alias)
13009 + return 0;
13010 + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
13011 + default:
13012 + return 0;
13013 }
13014 +}
13015
13016 - dev->blocksInCheckpoint = 0;
13017 -
13018 - chunkData = yaffs_GetTempBuffer(dev, __LINE__);
13019 -
13020 - /* Scan all the blocks to determine their state */
13021 - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
13022 - bi = yaffs_GetBlockInfo(dev, blk);
13023 - yaffs_ClearChunkBits(dev, blk);
13024 - bi->pagesInUse = 0;
13025 - bi->softDeletions = 0;
13026 -
13027 - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
13028
13029 - bi->blockState = state;
13030 - bi->sequenceNumber = sequenceNumber;
13031
13032 - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
13033 - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
13034 - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
13035 - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
13036 +int yaffs_flush_file(yaffs_obj_t *in, int update_time, int data_sync)
13037 +{
13038 + int retVal;
13039 + if (in->dirty) {
13040 + yaffs_flush_file_cache(in);
13041 + if(data_sync) /* Only sync data */
13042 + retVal=YAFFS_OK;
13043 + else {
13044 + if (update_time) {
13045 +#ifdef CONFIG_YAFFS_WINCE
13046 + yfsd_win_file_time_now(in->win_mtime);
13047 +#else
13048
13049 - T(YAFFS_TRACE_SCAN_DEBUG,
13050 - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
13051 - state, sequenceNumber));
13052 + in->yst_mtime = Y_CURRENT_TIME;
13053
13054 +#endif
13055 + }
13056
13057 - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
13058 - dev->blocksInCheckpoint++;
13059 + retVal = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >=
13060 + 0) ? YAFFS_OK : YAFFS_FAIL;
13061 + }
13062 + } else {
13063 + retVal = YAFFS_OK;
13064 + }
13065
13066 - } else if (state == YAFFS_BLOCK_STATE_DEAD) {
13067 - T(YAFFS_TRACE_BAD_BLOCKS,
13068 - (TSTR("block %d is bad" TENDSTR), blk));
13069 - } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
13070 - T(YAFFS_TRACE_SCAN_DEBUG,
13071 - (TSTR("Block empty " TENDSTR)));
13072 - dev->nErasedBlocks++;
13073 - dev->nFreeChunks += dev->nChunksPerBlock;
13074 - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13075 + return retVal;
13076
13077 - /* Determine the highest sequence number */
13078 - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
13079 - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
13080 +}
13081
13082 - blockIndex[nBlocksToScan].seq = sequenceNumber;
13083 - blockIndex[nBlocksToScan].block = blk;
13084 +static int yaffs_generic_obj_del(yaffs_obj_t *in)
13085 +{
13086
13087 - nBlocksToScan++;
13088 + /* First off, invalidate the file's data in the cache, without flushing. */
13089 + yaffs_invalidate_whole_cache(in);
13090
13091 - if (sequenceNumber >= dev->sequenceNumber)
13092 - dev->sequenceNumber = sequenceNumber;
13093 - } else {
13094 - /* TODO: Nasty sequence number! */
13095 - T(YAFFS_TRACE_SCAN,
13096 - (TSTR
13097 - ("Block scanning block %d has bad sequence number %d"
13098 - TENDSTR), blk, sequenceNumber));
13099 + if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) {
13100 + /* Move to the unlinked directory so we have a record that it was deleted. */
13101 + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, 0);
13102
13103 - }
13104 - }
13105 }
13106
13107 - T(YAFFS_TRACE_SCAN,
13108 - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
13109 + yaffs_remove_obj_from_dir(in);
13110 + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
13111 + in->hdr_chunk = 0;
13112
13113 + yaffs_free_obj(in);
13114 + return YAFFS_OK;
13115
13116 +}
13117
13118 - YYIELD();
13119 +/* yaffs_del_file deletes the whole file data
13120 + * and the inode associated with the file.
13121 + * It does not delete the links associated with the file.
13122 + */
13123 +static int yaffs_unlink_file_if_needed(yaffs_obj_t *in)
13124 +{
13125
13126 - /* Sort the blocks */
13127 -#ifndef CONFIG_YAFFS_USE_OWN_SORT
13128 - {
13129 - /* Use qsort now. */
13130 - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
13131 - }
13132 -#else
13133 - {
13134 - /* Dungy old bubble sort... */
13135 + int retVal;
13136 + int immediateDeletion = 0;
13137 + yaffs_dev_t *dev = in->my_dev;
13138
13139 - yaffs_BlockIndex temp;
13140 - int i;
13141 - int j;
13142 + if (!in->my_inode)
13143 + immediateDeletion = 1;
13144
13145 - for (i = 0; i < nBlocksToScan; i++)
13146 - for (j = i + 1; j < nBlocksToScan; j++)
13147 - if (blockIndex[i].seq > blockIndex[j].seq) {
13148 - temp = blockIndex[j];
13149 - blockIndex[j] = blockIndex[i];
13150 - blockIndex[i] = temp;
13151 - }
13152 + if (immediateDeletion) {
13153 + retVal =
13154 + yaffs_change_obj_name(in, in->my_dev->del_dir,
13155 + _Y("deleted"), 0, 0);
13156 + T(YAFFS_TRACE_TRACING,
13157 + (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
13158 + in->obj_id));
13159 + in->deleted = 1;
13160 + in->my_dev->n_deleted_files++;
13161 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
13162 + yaffs_resize_file(in, 0);
13163 + yaffs_soft_del_file(in);
13164 + } else {
13165 + retVal =
13166 + yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
13167 + _Y("unlinked"), 0, 0);
13168 }
13169 -#endif
13170
13171 - YYIELD();
13172
13173 - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
13174 + return retVal;
13175 +}
13176
13177 - /* Now scan the blocks looking at the data. */
13178 - startIterator = 0;
13179 - endIterator = nBlocksToScan - 1;
13180 - T(YAFFS_TRACE_SCAN_DEBUG,
13181 - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
13182 +int yaffs_del_file(yaffs_obj_t *in)
13183 +{
13184 + int retVal = YAFFS_OK;
13185 + int deleted; /* Need to cache value on stack if in is freed */
13186 + yaffs_dev_t *dev = in->my_dev;
13187
13188 - /* For each block.... backwards */
13189 - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
13190 - blockIterator--) {
13191 - /* Cooperative multitasking! This loop can run for so
13192 - long that watchdog timers expire. */
13193 - YYIELD();
13194 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
13195 + yaffs_resize_file(in, 0);
13196
13197 - /* get the block to scan in the correct order */
13198 - blk = blockIndex[blockIterator].block;
13199 + if (in->n_data_chunks > 0) {
13200 + /* Use soft deletion if there is data in the file.
13201 + * That won't be the case if it has been resized to zero.
13202 + */
13203 + if (!in->unlinked)
13204 + retVal = yaffs_unlink_file_if_needed(in);
13205
13206 - bi = yaffs_GetBlockInfo(dev, blk);
13207 + deleted = in->deleted;
13208
13209 + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
13210 + in->deleted = 1;
13211 + deleted = 1;
13212 + in->my_dev->n_deleted_files++;
13213 + yaffs_soft_del_file(in);
13214 + }
13215 + return deleted ? YAFFS_OK : YAFFS_FAIL;
13216 + } else {
13217 + /* The file has no data chunks so we toss it immediately */
13218 + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
13219 + in->variant.file_variant.top = NULL;
13220 + yaffs_generic_obj_del(in);
13221
13222 - state = bi->blockState;
13223 + return YAFFS_OK;
13224 + }
13225 +}
13226
13227 - deleted = 0;
13228 +static int yaffs_is_non_empty_dir(yaffs_obj_t *obj)
13229 +{
13230 + return (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
13231 + !(ylist_empty(&obj->variant.dir_variant.children));
13232 +}
13233
13234 - /* For each chunk in each block that needs scanning.... */
13235 - foundChunksInBlock = 0;
13236 - for (c = dev->nChunksPerBlock - 1;
13237 - !alloc_failed && c >= 0 &&
13238 - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
13239 - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
13240 - /* Scan backwards...
13241 - * Read the tags and decide what to do
13242 - */
13243 +static int yaffs_del_dir(yaffs_obj_t *obj)
13244 +{
13245 + /* First check that the directory is empty. */
13246 + if (yaffs_is_non_empty_dir(obj))
13247 + return YAFFS_FAIL;
13248
13249 - chunk = blk * dev->nChunksPerBlock + c;
13250 + return yaffs_generic_obj_del(obj);
13251 +}
13252
13253 - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
13254 - &tags);
13255 +static int yaffs_del_symlink(yaffs_obj_t *in)
13256 +{
13257 + if(in->variant.symlink_variant.alias)
13258 + YFREE(in->variant.symlink_variant.alias);
13259 + in->variant.symlink_variant.alias=NULL;
13260
13261 - /* Let's have a good look at this chunk... */
13262 + return yaffs_generic_obj_del(in);
13263 +}
13264
13265 - if (!tags.chunkUsed) {
13266 - /* An unassigned chunk in the block.
13267 - * If there are used chunks after this one, then
13268 - * it is a chunk that was skipped due to failing the erased
13269 - * check. Just skip it so that it can be deleted.
13270 - * But, more typically, We get here when this is an unallocated
13271 - * chunk and his means that either the block is empty or
13272 - * this is the one being allocated from
13273 - */
13274 +static int yaffs_del_link(yaffs_obj_t *in)
13275 +{
13276 + /* remove this hardlink from the list assocaited with the equivalent
13277 + * object
13278 + */
13279 + ylist_del_init(&in->hard_links);
13280 + return yaffs_generic_obj_del(in);
13281 +}
13282
13283 - if (foundChunksInBlock) {
13284 - /* This is a chunk that was skipped due to failing the erased check */
13285 - } else if (c == 0) {
13286 - /* We're looking at the first chunk in the block so the block is unused */
13287 - state = YAFFS_BLOCK_STATE_EMPTY;
13288 - dev->nErasedBlocks++;
13289 - } else {
13290 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
13291 - state == YAFFS_BLOCK_STATE_ALLOCATING) {
13292 - if (dev->sequenceNumber == bi->sequenceNumber) {
13293 - /* this is the block being allocated from */
13294 -
13295 - T(YAFFS_TRACE_SCAN,
13296 - (TSTR
13297 - (" Allocating from %d %d"
13298 - TENDSTR), blk, c));
13299 -
13300 - state = YAFFS_BLOCK_STATE_ALLOCATING;
13301 - dev->allocationBlock = blk;
13302 - dev->allocationPage = c;
13303 - dev->allocationBlockFinder = blk;
13304 - } else {
13305 - /* This is a partially written block that is not
13306 - * the current allocation block. This block must have
13307 - * had a write failure, so set up for retirement.
13308 - */
13309 -
13310 - /* bi->needsRetiring = 1; ??? TODO */
13311 - bi->gcPrioritise = 1;
13312 -
13313 - T(YAFFS_TRACE_ALWAYS,
13314 - (TSTR("Partially written block %d detected" TENDSTR),
13315 - blk));
13316 - }
13317 - }
13318 - }
13319 +int yaffs_del_obj(yaffs_obj_t *obj)
13320 +{
13321 +int retVal = -1;
13322 + switch (obj->variant_type) {
13323 + case YAFFS_OBJECT_TYPE_FILE:
13324 + retVal = yaffs_del_file(obj);
13325 + break;
13326 + case YAFFS_OBJECT_TYPE_DIRECTORY:
13327 + if(!ylist_empty(&obj->variant.dir_variant.dirty)){
13328 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->obj_id));
13329 + ylist_del_init(&obj->variant.dir_variant.dirty);
13330 + }
13331 + return yaffs_del_dir(obj);
13332 + break;
13333 + case YAFFS_OBJECT_TYPE_SYMLINK:
13334 + retVal = yaffs_del_symlink(obj);
13335 + break;
13336 + case YAFFS_OBJECT_TYPE_HARDLINK:
13337 + retVal = yaffs_del_link(obj);
13338 + break;
13339 + case YAFFS_OBJECT_TYPE_SPECIAL:
13340 + retVal = yaffs_generic_obj_del(obj);
13341 + break;
13342 + case YAFFS_OBJECT_TYPE_UNKNOWN:
13343 + retVal = 0;
13344 + break; /* should not happen. */
13345 + }
13346
13347 - dev->nFreeChunks++;
13348 + return retVal;
13349 +}
13350
13351 - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
13352 - T(YAFFS_TRACE_SCAN,
13353 - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
13354 - blk, c));
13355 -
13356 - dev->nFreeChunks++;
13357 -
13358 - } else if (tags.chunkId > 0) {
13359 - /* chunkId > 0 so it is a data chunk... */
13360 - unsigned int endpos;
13361 - __u32 chunkBase =
13362 - (tags.chunkId - 1) * dev->nDataBytesPerChunk;
13363 -
13364 - foundChunksInBlock = 1;
13365 -
13366 -
13367 - yaffs_SetChunkBit(dev, blk, c);
13368 - bi->pagesInUse++;
13369 -
13370 - in = yaffs_FindOrCreateObjectByNumber(dev,
13371 - tags.
13372 - objectId,
13373 - YAFFS_OBJECT_TYPE_FILE);
13374 - if (!in) {
13375 - /* Out of memory */
13376 - alloc_failed = 1;
13377 - }
13378 +static int yaffs_unlink_worker(yaffs_obj_t *obj)
13379 +{
13380
13381 - if (in &&
13382 - in->variantType == YAFFS_OBJECT_TYPE_FILE
13383 - && chunkBase <
13384 - in->variant.fileVariant.shrinkSize) {
13385 - /* This has not been invalidated by a resize */
13386 - if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
13387 - chunk, -1)) {
13388 - alloc_failed = 1;
13389 - }
13390 + int immediateDeletion = 0;
13391
13392 - /* File size is calculated by looking at the data chunks if we have not
13393 - * seen an object header yet. Stop this practice once we find an object header.
13394 - */
13395 - endpos =
13396 - (tags.chunkId -
13397 - 1) * dev->nDataBytesPerChunk +
13398 - tags.byteCount;
13399 -
13400 - if (!in->valid && /* have not got an object header yet */
13401 - in->variant.fileVariant.
13402 - scannedFileSize < endpos) {
13403 - in->variant.fileVariant.
13404 - scannedFileSize = endpos;
13405 - in->variant.fileVariant.
13406 - fileSize =
13407 - in->variant.fileVariant.
13408 - scannedFileSize;
13409 - }
13410 + if (!obj->my_inode)
13411 + immediateDeletion = 1;
13412
13413 - } else if (in) {
13414 - /* This chunk has been invalidated by a resize, so delete */
13415 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13416 + if(obj)
13417 + yaffs_update_parent(obj->parent);
13418
13419 - }
13420 - } else {
13421 - /* chunkId == 0, so it is an ObjectHeader.
13422 - * Thus, we read in the object header and make the object
13423 - */
13424 - foundChunksInBlock = 1;
13425 + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
13426 + return yaffs_del_link(obj);
13427 + } else if (!ylist_empty(&obj->hard_links)) {
13428 + /* Curve ball: We're unlinking an object that has a hardlink.
13429 + *
13430 + * This problem arises because we are not strictly following
13431 + * The Linux link/inode model.
13432 + *
13433 + * We can't really delete the object.
13434 + * Instead, we do the following:
13435 + * - Select a hardlink.
13436 + * - Unhook it from the hard links
13437 + * - Move it from its parent directory (so that the rename can work)
13438 + * - Rename the object to the hardlink's name.
13439 + * - Delete the hardlink
13440 + */
13441
13442 - yaffs_SetChunkBit(dev, blk, c);
13443 - bi->pagesInUse++;
13444 + yaffs_obj_t *hl;
13445 + yaffs_obj_t *parent;
13446 + int retVal;
13447 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
13448
13449 - oh = NULL;
13450 - in = NULL;
13451 + hl = ylist_entry(obj->hard_links.next, yaffs_obj_t, hard_links);
13452
13453 - if (tags.extraHeaderInfoAvailable) {
13454 - in = yaffs_FindOrCreateObjectByNumber
13455 - (dev, tags.objectId,
13456 - tags.extraObjectType);
13457 - if (!in)
13458 - alloc_failed = 1;
13459 - }
13460 + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
13461 + parent = hl->parent;
13462
13463 - if (!in ||
13464 -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
13465 - !in->valid ||
13466 -#endif
13467 - tags.extraShadows ||
13468 - (!in->valid &&
13469 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13470 - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
13471 -
13472 - /* If we don't have valid info then we need to read the chunk
13473 - * TODO In future we can probably defer reading the chunk and
13474 - * living with invalid data until needed.
13475 - */
13476 + ylist_del_init(&hl->hard_links);
13477
13478 - result = yaffs_ReadChunkWithTagsFromNAND(dev,
13479 - chunk,
13480 - chunkData,
13481 - NULL);
13482 -
13483 - oh = (yaffs_ObjectHeader *) chunkData;
13484 -
13485 - if (dev->inbandTags) {
13486 - /* Fix up the header if they got corrupted by inband tags */
13487 - oh->shadowsObject = oh->inbandShadowsObject;
13488 - oh->isShrink = oh->inbandIsShrink;
13489 - }
13490 + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
13491
13492 - if (!in) {
13493 - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
13494 - if (!in)
13495 - alloc_failed = 1;
13496 - }
13497 + retVal = yaffs_change_obj_name(obj,parent, name, 0, 0);
13498
13499 - }
13500 + if (retVal == YAFFS_OK)
13501 + retVal = yaffs_generic_obj_del(hl);
13502
13503 - if (!in) {
13504 - /* TODO Hoosterman we have a problem! */
13505 - T(YAFFS_TRACE_ERROR,
13506 - (TSTR
13507 - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
13508 - TENDSTR), tags.objectId, chunk));
13509 - continue;
13510 - }
13511 + return retVal;
13512
13513 - if (in->valid) {
13514 - /* We have already filled this one.
13515 - * We have a duplicate that will be discarded, but
13516 - * we first have to suck out resize info if it is a file.
13517 - */
13518 + } else if (immediateDeletion) {
13519 + switch (obj->variant_type) {
13520 + case YAFFS_OBJECT_TYPE_FILE:
13521 + return yaffs_del_file(obj);
13522 + break;
13523 + case YAFFS_OBJECT_TYPE_DIRECTORY:
13524 + ylist_del_init(&obj->variant.dir_variant.dirty);
13525 + return yaffs_del_dir(obj);
13526 + break;
13527 + case YAFFS_OBJECT_TYPE_SYMLINK:
13528 + return yaffs_del_symlink(obj);
13529 + break;
13530 + case YAFFS_OBJECT_TYPE_SPECIAL:
13531 + return yaffs_generic_obj_del(obj);
13532 + break;
13533 + case YAFFS_OBJECT_TYPE_HARDLINK:
13534 + case YAFFS_OBJECT_TYPE_UNKNOWN:
13535 + default:
13536 + return YAFFS_FAIL;
13537 + }
13538 + } else if(yaffs_is_non_empty_dir(obj))
13539 + return YAFFS_FAIL;
13540 + else
13541 + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
13542 + _Y("unlinked"), 0, 0);
13543 +}
13544
13545 - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
13546 - ((oh &&
13547 - oh->type == YAFFS_OBJECT_TYPE_FILE) ||
13548 - (tags.extraHeaderInfoAvailable &&
13549 - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
13550 - __u32 thisSize =
13551 - (oh) ? oh->fileSize : tags.
13552 - extraFileLength;
13553 - __u32 parentObjectId =
13554 - (oh) ? oh->
13555 - parentObjectId : tags.
13556 - extraParentObjectId;
13557 -
13558 -
13559 - isShrink =
13560 - (oh) ? oh->isShrink : tags.
13561 - extraIsShrinkHeader;
13562
13563 - /* If it is deleted (unlinked at start also means deleted)
13564 - * we treat the file size as being zeroed at this point.
13565 - */
13566 - if (parentObjectId ==
13567 - YAFFS_OBJECTID_DELETED
13568 - || parentObjectId ==
13569 - YAFFS_OBJECTID_UNLINKED) {
13570 - thisSize = 0;
13571 - isShrink = 1;
13572 - }
13573 +static int yaffs_unlink_obj(yaffs_obj_t *obj)
13574 +{
13575
13576 - if (isShrink &&
13577 - in->variant.fileVariant.
13578 - shrinkSize > thisSize) {
13579 - in->variant.fileVariant.
13580 - shrinkSize =
13581 - thisSize;
13582 - }
13583 + if (obj && obj->unlink_allowed)
13584 + return yaffs_unlink_worker(obj);
13585
13586 - if (isShrink)
13587 - bi->hasShrinkHeader = 1;
13588 + return YAFFS_FAIL;
13589
13590 - }
13591 - /* Use existing - destroy this one. */
13592 - yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
13593 +}
13594 +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name)
13595 +{
13596 + yaffs_obj_t *obj;
13597
13598 - }
13599 + obj = yaffs_find_by_name(dir, name);
13600 + return yaffs_unlink_obj(obj);
13601 +}
13602
13603 - if (!in->valid && in->variantType !=
13604 - (oh ? oh->type : tags.extraObjectType))
13605 - T(YAFFS_TRACE_ERROR, (
13606 - TSTR("yaffs tragedy: Bad object type, "
13607 - TCONT("%d != %d, for object %d at chunk ")
13608 - TCONT("%d during scan")
13609 - TENDSTR), oh ?
13610 - oh->type : tags.extraObjectType,
13611 - in->variantType, tags.objectId,
13612 - chunk));
13613 -
13614 - if (!in->valid &&
13615 - (tags.objectId == YAFFS_OBJECTID_ROOT ||
13616 - tags.objectId ==
13617 - YAFFS_OBJECTID_LOSTNFOUND)) {
13618 - /* We only load some info, don't fiddle with directory structure */
13619 - in->valid = 1;
13620 +/*----------------------- Initialisation Scanning ---------------------- */
13621
13622 - if (oh) {
13623 - in->variantType = oh->type;
13624 +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
13625 + int backward_scanning)
13626 +{
13627 + yaffs_obj_t *obj;
13628
13629 - in->yst_mode = oh->yst_mode;
13630 -#ifdef CONFIG_YAFFS_WINCE
13631 - in->win_atime[0] = oh->win_atime[0];
13632 - in->win_ctime[0] = oh->win_ctime[0];
13633 - in->win_mtime[0] = oh->win_mtime[0];
13634 - in->win_atime[1] = oh->win_atime[1];
13635 - in->win_ctime[1] = oh->win_ctime[1];
13636 - in->win_mtime[1] = oh->win_mtime[1];
13637 -#else
13638 - in->yst_uid = oh->yst_uid;
13639 - in->yst_gid = oh->yst_gid;
13640 - in->yst_atime = oh->yst_atime;
13641 - in->yst_mtime = oh->yst_mtime;
13642 - in->yst_ctime = oh->yst_ctime;
13643 - in->yst_rdev = oh->yst_rdev;
13644 + if (!backward_scanning) {
13645 + /* Handle YAFFS1 forward scanning case
13646 + * For YAFFS1 we always do the deletion
13647 + */
13648
13649 -#endif
13650 - } else {
13651 - in->variantType = tags.extraObjectType;
13652 - in->lazyLoaded = 1;
13653 - }
13654 + } else {
13655 + /* Handle YAFFS2 case (backward scanning)
13656 + * If the shadowed object exists then ignore.
13657 + */
13658 + obj = yaffs_find_by_number(dev, obj_id);
13659 + if(obj)
13660 + return;
13661 + }
13662
13663 - in->hdrChunk = chunk;
13664 + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
13665 + * We put it in unlinked dir to be cleaned up after the scanning
13666 + */
13667 + obj =
13668 + yaffs_find_or_create_by_number(dev, obj_id,
13669 + YAFFS_OBJECT_TYPE_FILE);
13670 + if (!obj)
13671 + return;
13672 + obj->is_shadowed = 1;
13673 + yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
13674 + obj->variant.file_variant.shrink_size = 0;
13675 + obj->valid = 1; /* So that we don't read any other info for this file */
13676
13677 - } else if (!in->valid) {
13678 - /* we need to load this info */
13679 +}
13680
13681 - in->valid = 1;
13682 - in->hdrChunk = chunk;
13683
13684 - if (oh) {
13685 - in->variantType = oh->type;
13686 +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list)
13687 +{
13688 + yaffs_obj_t *hl;
13689 + yaffs_obj_t *in;
13690
13691 - in->yst_mode = oh->yst_mode;
13692 -#ifdef CONFIG_YAFFS_WINCE
13693 - in->win_atime[0] = oh->win_atime[0];
13694 - in->win_ctime[0] = oh->win_ctime[0];
13695 - in->win_mtime[0] = oh->win_mtime[0];
13696 - in->win_atime[1] = oh->win_atime[1];
13697 - in->win_ctime[1] = oh->win_ctime[1];
13698 - in->win_mtime[1] = oh->win_mtime[1];
13699 -#else
13700 - in->yst_uid = oh->yst_uid;
13701 - in->yst_gid = oh->yst_gid;
13702 - in->yst_atime = oh->yst_atime;
13703 - in->yst_mtime = oh->yst_mtime;
13704 - in->yst_ctime = oh->yst_ctime;
13705 - in->yst_rdev = oh->yst_rdev;
13706 -#endif
13707 + while (hard_list) {
13708 + hl = hard_list;
13709 + hard_list = (yaffs_obj_t *) (hard_list->hard_links.next);
13710 +
13711 + in = yaffs_find_by_number(dev,
13712 + hl->variant.hardlink_variant.
13713 + equiv_id);
13714
13715 - if (oh->shadowsObject > 0)
13716 - yaffs_HandleShadowedObject(dev,
13717 - oh->
13718 - shadowsObject,
13719 - 1);
13720 -
13721 -
13722 - yaffs_SetObjectName(in, oh->name);
13723 - parent =
13724 - yaffs_FindOrCreateObjectByNumber
13725 - (dev, oh->parentObjectId,
13726 - YAFFS_OBJECT_TYPE_DIRECTORY);
13727 -
13728 - fileSize = oh->fileSize;
13729 - isShrink = oh->isShrink;
13730 - equivalentObjectId = oh->equivalentObjectId;
13731 + if (in) {
13732 + /* Add the hardlink pointers */
13733 + hl->variant.hardlink_variant.equiv_obj = in;
13734 + ylist_add(&hl->hard_links, &in->hard_links);
13735 + } else {
13736 + /* Todo Need to report/handle this better.
13737 + * Got a problem... hardlink to a non-existant object
13738 + */
13739 + hl->variant.hardlink_variant.equiv_obj = NULL;
13740 + YINIT_LIST_HEAD(&hl->hard_links);
13741
13742 - } else {
13743 - in->variantType = tags.extraObjectType;
13744 - parent =
13745 - yaffs_FindOrCreateObjectByNumber
13746 - (dev, tags.extraParentObjectId,
13747 - YAFFS_OBJECT_TYPE_DIRECTORY);
13748 - fileSize = tags.extraFileLength;
13749 - isShrink = tags.extraIsShrinkHeader;
13750 - equivalentObjectId = tags.extraEquivalentObjectId;
13751 - in->lazyLoaded = 1;
13752 + }
13753 + }
13754 +}
13755
13756 - }
13757 - in->dirty = 0;
13758
13759 - if (!parent)
13760 - alloc_failed = 1;
13761 +static void yaffs_strip_deleted_objs(yaffs_dev_t *dev)
13762 +{
13763 + /*
13764 + * Sort out state of unlinked and deleted objects after scanning.
13765 + */
13766 + struct ylist_head *i;
13767 + struct ylist_head *n;
13768 + yaffs_obj_t *l;
13769
13770 - /* directory stuff...
13771 - * hook up to parent
13772 - */
13773 + if (dev->read_only)
13774 + return;
13775
13776 - if (parent && parent->variantType ==
13777 - YAFFS_OBJECT_TYPE_UNKNOWN) {
13778 - /* Set up as a directory */
13779 - parent->variantType =
13780 - YAFFS_OBJECT_TYPE_DIRECTORY;
13781 - YINIT_LIST_HEAD(&parent->variant.
13782 - directoryVariant.
13783 - children);
13784 - } else if (!parent || parent->variantType !=
13785 - YAFFS_OBJECT_TYPE_DIRECTORY) {
13786 - /* Hoosterman, another problem....
13787 - * We're trying to use a non-directory as a directory
13788 - */
13789 + /* Soft delete all the unlinked files */
13790 + ylist_for_each_safe(i, n,
13791 + &dev->unlinked_dir->variant.dir_variant.children) {
13792 + if (i) {
13793 + l = ylist_entry(i, yaffs_obj_t, siblings);
13794 + yaffs_del_obj(l);
13795 + }
13796 + }
13797
13798 - T(YAFFS_TRACE_ERROR,
13799 - (TSTR
13800 - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
13801 - TENDSTR)));
13802 - parent = dev->lostNFoundDir;
13803 - }
13804 + ylist_for_each_safe(i, n,
13805 + &dev->del_dir->variant.dir_variant.children) {
13806 + if (i) {
13807 + l = ylist_entry(i, yaffs_obj_t, siblings);
13808 + yaffs_del_obj(l);
13809 + }
13810 + }
13811
13812 - yaffs_AddObjectToDirectory(parent, in);
13813 +}
13814
13815 - itsUnlinked = (parent == dev->deletedDir) ||
13816 - (parent == dev->unlinkedDir);
13817 +/*
13818 + * This code iterates through all the objects making sure that they are rooted.
13819 + * Any unrooted objects are re-rooted in lost+found.
13820 + * An object needs to be in one of:
13821 + * - Directly under deleted, unlinked
13822 + * - Directly or indirectly under root.
13823 + *
13824 + * Note:
13825 + * This code assumes that we don't ever change the current relationships between
13826 + * directories:
13827 + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
13828 + * lostNfound->parent == root_dir
13829 + *
13830 + * This fixes the problem where directories might have inadvertently been deleted
13831 + * leaving the object "hanging" without being rooted in the directory tree.
13832 + */
13833 +
13834 +static int yaffs_has_null_parent(yaffs_dev_t *dev, yaffs_obj_t *obj)
13835 +{
13836 + return (obj == dev->del_dir ||
13837 + obj == dev->unlinked_dir||
13838 + obj == dev->root_dir);
13839 +}
13840
13841 - if (isShrink) {
13842 - /* Mark the block as having a shrinkHeader */
13843 - bi->hasShrinkHeader = 1;
13844 - }
13845 +static void yaffs_fix_hanging_objs(yaffs_dev_t *dev)
13846 +{
13847 + yaffs_obj_t *obj;
13848 + yaffs_obj_t *parent;
13849 + int i;
13850 + struct ylist_head *lh;
13851 + struct ylist_head *n;
13852 + int depthLimit;
13853 + int hanging;
13854
13855 - /* Note re hardlinks.
13856 - * Since we might scan a hardlink before its equivalent object is scanned
13857 - * we put them all in a list.
13858 - * After scanning is complete, we should have all the objects, so we run
13859 - * through this list and fix up all the chains.
13860 - */
13861 + if (dev->read_only)
13862 + return;
13863
13864 - switch (in->variantType) {
13865 - case YAFFS_OBJECT_TYPE_UNKNOWN:
13866 - /* Todo got a problem */
13867 - break;
13868 - case YAFFS_OBJECT_TYPE_FILE:
13869 -
13870 - if (in->variant.fileVariant.
13871 - scannedFileSize < fileSize) {
13872 - /* This covers the case where the file size is greater
13873 - * than where the data is
13874 - * This will happen if the file is resized to be larger
13875 - * than its current data extents.
13876 - */
13877 - in->variant.fileVariant.fileSize = fileSize;
13878 - in->variant.fileVariant.scannedFileSize =
13879 - in->variant.fileVariant.fileSize;
13880 - }
13881 + /* Iterate through the objects in each hash entry,
13882 + * looking at each object.
13883 + * Make sure it is rooted.
13884 + */
13885
13886 - if (isShrink &&
13887 - in->variant.fileVariant.shrinkSize > fileSize) {
13888 - in->variant.fileVariant.shrinkSize = fileSize;
13889 - }
13890 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
13891 + ylist_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
13892 + if (lh) {
13893 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
13894 + parent= obj->parent;
13895 +
13896 + if(yaffs_has_null_parent(dev,obj)){
13897 + /* These directories are not hanging */
13898 + hanging = 0;
13899 + }
13900 + else if(!parent || parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
13901 + hanging = 1;
13902 + else if(yaffs_has_null_parent(dev,parent))
13903 + hanging = 0;
13904 + else {
13905 + /*
13906 + * Need to follow the parent chain to see if it is hanging.
13907 + */
13908 + hanging = 0;
13909 + depthLimit=100;
13910
13911 - break;
13912 - case YAFFS_OBJECT_TYPE_HARDLINK:
13913 - if (!itsUnlinked) {
13914 - in->variant.hardLinkVariant.equivalentObjectId =
13915 - equivalentObjectId;
13916 - in->hardLinks.next =
13917 - (struct ylist_head *) hardList;
13918 - hardList = in;
13919 - }
13920 - break;
13921 - case YAFFS_OBJECT_TYPE_DIRECTORY:
13922 - /* Do nothing */
13923 - break;
13924 - case YAFFS_OBJECT_TYPE_SPECIAL:
13925 - /* Do nothing */
13926 - break;
13927 - case YAFFS_OBJECT_TYPE_SYMLINK:
13928 - if (oh) {
13929 - in->variant.symLinkVariant.alias =
13930 - yaffs_CloneString(oh->alias);
13931 - if (!in->variant.symLinkVariant.alias)
13932 - alloc_failed = 1;
13933 - }
13934 - break;
13935 + while(parent != dev->root_dir &&
13936 + parent->parent &&
13937 + parent->parent->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
13938 + depthLimit > 0){
13939 + parent = parent->parent;
13940 + depthLimit--;
13941 }
13942 -
13943 + if(parent != dev->root_dir)
13944 + hanging = 1;
13945 + }
13946 + if(hanging){
13947 + T(YAFFS_TRACE_SCAN,
13948 + (TSTR("Hanging object %d moved to lost and found" TENDSTR),
13949 + obj->obj_id));
13950 + yaffs_add_obj_to_dir(dev->lost_n_found,obj);
13951 }
13952 -
13953 }
13954 + }
13955 + }
13956 +}
13957
13958 - } /* End of scanning for each chunk */
13959
13960 - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
13961 - /* If we got this far while scanning, then the block is fully allocated. */
13962 - state = YAFFS_BLOCK_STATE_FULL;
13963 - }
13964 +/*
13965 + * Delete directory contents for cleaning up lost and found.
13966 + */
13967 +static void yaffs_del_dir_contents(yaffs_obj_t *dir)
13968 +{
13969 + yaffs_obj_t *obj;
13970 + struct ylist_head *lh;
13971 + struct ylist_head *n;
13972
13973 - bi->blockState = state;
13974 + if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
13975 + YBUG();
13976 +
13977 + ylist_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
13978 + if (lh) {
13979 + obj = ylist_entry(lh, yaffs_obj_t, siblings);
13980 + if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
13981 + yaffs_del_dir_contents(obj);
13982 +
13983 + T(YAFFS_TRACE_SCAN,
13984 + (TSTR("Deleting lost_found object %d" TENDSTR),
13985 + obj->obj_id));
13986
13987 - /* Now let's see if it was dirty */
13988 - if (bi->pagesInUse == 0 &&
13989 - !bi->hasShrinkHeader &&
13990 - bi->blockState == YAFFS_BLOCK_STATE_FULL) {
13991 - yaffs_BlockBecameDirty(dev, blk);
13992 + /* Need to use UnlinkObject since Delete would not handle
13993 + * hardlinked objects correctly.
13994 + */
13995 + yaffs_unlink_obj(obj);
13996 }
13997 -
13998 }
13999 +
14000 +}
14001
14002 - if (altBlockIndex)
14003 - YFREE_ALT(blockIndex);
14004 - else
14005 - YFREE(blockIndex);
14006 +static void yaffs_empty_l_n_f(yaffs_dev_t *dev)
14007 +{
14008 + yaffs_del_dir_contents(dev->lost_n_found);
14009 +}
14010
14011 - /* Ok, we've done all the scanning.
14012 - * Fix up the hard link chains.
14013 - * We should now have scanned all the objects, now it's time to add these
14014 - * hardlinks.
14015 - */
14016 - yaffs_HardlinkFixup(dev, hardList);
14017 +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in)
14018 +{
14019 + __u8 *chunkData;
14020 + yaffs_obj_header *oh;
14021 + yaffs_dev_t *dev;
14022 + yaffs_ext_tags tags;
14023 + int result;
14024 + int alloc_failed = 0;
14025
14026 + if (!in)
14027 + return;
14028
14029 - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
14030 + dev = in->my_dev;
14031
14032 - if (alloc_failed)
14033 - return YAFFS_FAIL;
14034 +#if 0
14035 + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
14036 + in->obj_id,
14037 + in->lazy_loaded ? "not yet" : "already"));
14038 +#endif
14039
14040 - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
14041 + if (in->lazy_loaded && in->hdr_chunk > 0) {
14042 + in->lazy_loaded = 0;
14043 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
14044
14045 - return YAFFS_OK;
14046 -}
14047 + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunkData, &tags);
14048 + oh = (yaffs_obj_header *) chunkData;
14049
14050 -/*------------------------------ Directory Functions ----------------------------- */
14051 + in->yst_mode = oh->yst_mode;
14052 +#ifdef CONFIG_YAFFS_WINCE
14053 + in->win_atime[0] = oh->win_atime[0];
14054 + in->win_ctime[0] = oh->win_ctime[0];
14055 + in->win_mtime[0] = oh->win_mtime[0];
14056 + in->win_atime[1] = oh->win_atime[1];
14057 + in->win_ctime[1] = oh->win_ctime[1];
14058 + in->win_mtime[1] = oh->win_mtime[1];
14059 +#else
14060 + in->yst_uid = oh->yst_uid;
14061 + in->yst_gid = oh->yst_gid;
14062 + in->yst_atime = oh->yst_atime;
14063 + in->yst_mtime = oh->yst_mtime;
14064 + in->yst_ctime = oh->yst_ctime;
14065 + in->yst_rdev = oh->yst_rdev;
14066
14067 -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
14068 -{
14069 - struct ylist_head *lh;
14070 - yaffs_Object *listObj;
14071 +#endif
14072 + yaffs_set_obj_name_from_oh(in, oh);
14073
14074 - int count = 0;
14075 + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
14076 + in->variant.symlink_variant.alias =
14077 + yaffs_clone_str(oh->alias);
14078 + if (!in->variant.symlink_variant.alias)
14079 + alloc_failed = 1; /* Not returned to caller */
14080 + }
14081
14082 - if (!obj) {
14083 - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
14084 - YBUG();
14085 - return;
14086 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
14087 }
14088 +}
14089
14090 - if (yaffs_SkipVerification(obj->myDev))
14091 - return;
14092 +/*------------------------------ Directory Functions ----------------------------- */
14093
14094 - if (!obj->parent) {
14095 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
14096 - YBUG();
14097 +/*
14098 + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
14099 + * link (ie. name) is created or deleted in the directory.
14100 + *
14101 + * ie.
14102 + * create dir/a : update dir's mtime/ctime
14103 + * rm dir/a: update dir's mtime/ctime
14104 + * modify dir/a: don't update dir's mtimme/ctime
14105 + *
14106 + * This can be handled immediately or defered. Defering helps reduce the number
14107 + * of updates when many files in a directory are changed within a brief period.
14108 + *
14109 + * If the directory updating is defered then yaffs_update_dirty_dirs must be
14110 + * called periodically.
14111 + */
14112 +
14113 +static void yaffs_update_parent(yaffs_obj_t *obj)
14114 +{
14115 + yaffs_dev_t *dev;
14116 + if(!obj)
14117 return;
14118 - }
14119 -
14120 - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14121 - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
14122 - YBUG();
14123 - }
14124 -
14125 - /* Iterate through the objects in each hash entry */
14126 +#ifndef CONFIG_YAFFS_WINCE
14127
14128 - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
14129 - if (lh) {
14130 - listObj = ylist_entry(lh, yaffs_Object, siblings);
14131 - yaffs_VerifyObject(listObj);
14132 - if (obj == listObj)
14133 - count++;
14134 + dev = obj->my_dev;
14135 + obj->dirty = 1;
14136 + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
14137 + if(dev->param.defered_dir_update){
14138 + struct ylist_head *link = &obj->variant.dir_variant.dirty;
14139 +
14140 + if(ylist_empty(link)){
14141 + ylist_add(link,&dev->dirty_dirs);
14142 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->obj_id));
14143 }
14144 - }
14145
14146 - if (count != 1) {
14147 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
14148 - YBUG();
14149 - }
14150 + } else
14151 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
14152 +#endif
14153 }
14154
14155 -static void yaffs_VerifyDirectory(yaffs_Object *directory)
14156 +void yaffs_update_dirty_dirs(yaffs_dev_t *dev)
14157 {
14158 - struct ylist_head *lh;
14159 - yaffs_Object *listObj;
14160 -
14161 - if (!directory) {
14162 - YBUG();
14163 - return;
14164 - }
14165 + struct ylist_head *link;
14166 + yaffs_obj_t *obj;
14167 + yaffs_dir_s *dS;
14168 + yaffs_obj_variant *oV;
14169
14170 - if (yaffs_SkipFullVerification(directory->myDev))
14171 - return;
14172 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
14173
14174 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14175 - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
14176 - YBUG();
14177 - }
14178 + while(!ylist_empty(&dev->dirty_dirs)){
14179 + link = dev->dirty_dirs.next;
14180 + ylist_del_init(link);
14181 +
14182 + dS=ylist_entry(link,yaffs_dir_s,dirty);
14183 + oV = ylist_entry(dS,yaffs_obj_variant,dir_variant);
14184 + obj = ylist_entry(oV,yaffs_obj_t,variant);
14185
14186 - /* Iterate through the objects in each hash entry */
14187 + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->obj_id));
14188
14189 - ylist_for_each(lh, &directory->variant.directoryVariant.children) {
14190 - if (lh) {
14191 - listObj = ylist_entry(lh, yaffs_Object, siblings);
14192 - if (listObj->parent != directory) {
14193 - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
14194 - YBUG();
14195 - }
14196 - yaffs_VerifyObjectInDirectory(listObj);
14197 - }
14198 + if(obj->dirty)
14199 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
14200 }
14201 }
14202
14203 -
14204 -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
14205 +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj)
14206 {
14207 - yaffs_Device *dev = obj->myDev;
14208 - yaffs_Object *parent;
14209 + yaffs_dev_t *dev = obj->my_dev;
14210 + yaffs_obj_t *parent;
14211
14212 - yaffs_VerifyObjectInDirectory(obj);
14213 + yaffs_verify_obj_in_dir(obj);
14214 parent = obj->parent;
14215
14216 - yaffs_VerifyDirectory(parent);
14217 + yaffs_verify_dir(parent);
14218
14219 - if (dev && dev->removeObjectCallback)
14220 - dev->removeObjectCallback(obj);
14221 + if (dev && dev->param.remove_obj_fn)
14222 + dev->param.remove_obj_fn(obj);
14223
14224
14225 ylist_del_init(&obj->siblings);
14226 obj->parent = NULL;
14227 -
14228 - yaffs_VerifyDirectory(parent);
14229 +
14230 + yaffs_verify_dir(parent);
14231 }
14232
14233 -
14234 -static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
14235 - yaffs_Object *obj)
14236 +void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
14237 + yaffs_obj_t *obj)
14238 {
14239 if (!directory) {
14240 T(YAFFS_TRACE_ALWAYS,
14241 @@ -6699,7 +4495,7 @@ static void yaffs_AddObjectToDirectory(y
14242 YBUG();
14243 return;
14244 }
14245 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14246 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14247 T(YAFFS_TRACE_ALWAYS,
14248 (TSTR
14249 ("tragedy: Trying to add an object to a non-directory"
14250 @@ -6713,27 +4509,27 @@ static void yaffs_AddObjectToDirectory(y
14251 }
14252
14253
14254 - yaffs_VerifyDirectory(directory);
14255 + yaffs_verify_dir(directory);
14256
14257 - yaffs_RemoveObjectFromDirectory(obj);
14258 + yaffs_remove_obj_from_dir(obj);
14259
14260
14261 /* Now add it */
14262 - ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
14263 + ylist_add(&obj->siblings, &directory->variant.dir_variant.children);
14264 obj->parent = directory;
14265
14266 - if (directory == obj->myDev->unlinkedDir
14267 - || directory == obj->myDev->deletedDir) {
14268 + if (directory == obj->my_dev->unlinked_dir
14269 + || directory == obj->my_dev->del_dir) {
14270 obj->unlinked = 1;
14271 - obj->myDev->nUnlinkedFiles++;
14272 - obj->renameAllowed = 0;
14273 + obj->my_dev->n_unlinked_files++;
14274 + obj->rename_allowed = 0;
14275 }
14276
14277 - yaffs_VerifyDirectory(directory);
14278 - yaffs_VerifyObjectInDirectory(obj);
14279 + yaffs_verify_dir(directory);
14280 + yaffs_verify_obj_in_dir(obj);
14281 }
14282
14283 -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,
14284 +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *directory,
14285 const YCHAR *name)
14286 {
14287 int sum;
14288 @@ -6741,7 +4537,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14289 struct ylist_head *i;
14290 YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
14291
14292 - yaffs_Object *l;
14293 + yaffs_obj_t *l;
14294
14295 if (!name)
14296 return NULL;
14297 @@ -6749,39 +4545,39 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14298 if (!directory) {
14299 T(YAFFS_TRACE_ALWAYS,
14300 (TSTR
14301 - ("tragedy: yaffs_FindObjectByName: null pointer directory"
14302 + ("tragedy: yaffs_find_by_name: null pointer directory"
14303 TENDSTR)));
14304 YBUG();
14305 return NULL;
14306 }
14307 - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14308 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14309 T(YAFFS_TRACE_ALWAYS,
14310 (TSTR
14311 - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
14312 + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
14313 YBUG();
14314 }
14315
14316 - sum = yaffs_CalcNameSum(name);
14317 + sum = yaffs_calc_name_sum(name);
14318
14319 - ylist_for_each(i, &directory->variant.directoryVariant.children) {
14320 + ylist_for_each(i, &directory->variant.dir_variant.children) {
14321 if (i) {
14322 - l = ylist_entry(i, yaffs_Object, siblings);
14323 + l = ylist_entry(i, yaffs_obj_t, siblings);
14324
14325 if (l->parent != directory)
14326 YBUG();
14327
14328 - yaffs_CheckObjectDetailsLoaded(l);
14329 + yaffs_check_obj_details_loaded(l);
14330
14331 /* Special case for lost-n-found */
14332 - if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
14333 + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
14334 if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
14335 return l;
14336 - } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {
14337 + } else if (yaffs_sum_cmp(l->sum, sum) || l->hdr_chunk <= 0) {
14338 /* LostnFound chunk called Objxxx
14339 * Do a real check
14340 */
14341 - yaffs_GetObjectName(l, buffer,
14342 - YAFFS_MAX_NAME_LENGTH);
14343 + yaffs_get_obj_name(l, buffer,
14344 + YAFFS_MAX_NAME_LENGTH + 1);
14345 if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
14346 return l;
14347 }
14348 @@ -6793,31 +4589,31 @@ yaffs_Object *yaffs_FindObjectByName(yaf
14349
14350
14351 #if 0
14352 -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
14353 - int (*fn) (yaffs_Object *))
14354 +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
14355 + int (*fn) (yaffs_obj_t *))
14356 {
14357 struct ylist_head *i;
14358 - yaffs_Object *l;
14359 + yaffs_obj_t *l;
14360
14361 - if (!theDir) {
14362 + if (!the_dir) {
14363 T(YAFFS_TRACE_ALWAYS,
14364 (TSTR
14365 - ("tragedy: yaffs_FindObjectByName: null pointer directory"
14366 + ("tragedy: yaffs_find_by_name: null pointer directory"
14367 TENDSTR)));
14368 YBUG();
14369 return YAFFS_FAIL;
14370 }
14371 - if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
14372 + if (the_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
14373 T(YAFFS_TRACE_ALWAYS,
14374 (TSTR
14375 - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
14376 + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
14377 YBUG();
14378 return YAFFS_FAIL;
14379 }
14380
14381 - ylist_for_each(i, &theDir->variant.directoryVariant.children) {
14382 + ylist_for_each(i, &the_dir->variant.dir_variant.children) {
14383 if (i) {
14384 - l = ylist_entry(i, yaffs_Object, siblings);
14385 + l = ylist_entry(i, yaffs_obj_t, siblings);
14386 if (l && !fn(l))
14387 return YAFFS_FAIL;
14388 }
14389 @@ -6832,82 +4628,175 @@ int yaffs_ApplyToDirectoryChildren(yaffs
14390 * actual object.
14391 */
14392
14393 -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
14394 +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj)
14395 {
14396 - if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
14397 + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
14398 /* We want the object id of the equivalent object, not this one */
14399 - obj = obj->variant.hardLinkVariant.equivalentObject;
14400 - yaffs_CheckObjectDetailsLoaded(obj);
14401 + obj = obj->variant.hardlink_variant.equiv_obj;
14402 + yaffs_check_obj_details_loaded(obj);
14403 }
14404 return obj;
14405 }
14406
14407 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
14408 -{
14409 - memset(name, 0, buffSize * sizeof(YCHAR));
14410 -
14411 - yaffs_CheckObjectDetailsLoaded(obj);
14412 +/*
14413 + * A note or two on object names.
14414 + * * If the object name is missing, we then make one up in the form objnnn
14415 + *
14416 + * * ASCII names are stored in the object header's name field from byte zero
14417 + * * Unicode names are historically stored starting from byte zero.
14418 + *
14419 + * Then there are automatic Unicode names...
14420 + * The purpose of these is to save names in a way that can be read as
14421 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
14422 + * system to share files.
14423 + *
14424 + * These automatic unicode are stored slightly differently...
14425 + * - If the name can fit in the ASCII character space then they are saved as
14426 + * ascii names as per above.
14427 + * - If the name needs Unicode then the name is saved in Unicode
14428 + * starting at oh->name[1].
14429
14430 - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
14431 - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
14432 - } else if (obj->hdrChunk <= 0) {
14433 + */
14434 +static void yaffs_fix_null_name(yaffs_obj_t * obj,YCHAR * name, int buffer_size)
14435 +{
14436 + /* Create an object name if we could not find one. */
14437 + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
14438 YCHAR locName[20];
14439 YCHAR numString[20];
14440 YCHAR *x = &numString[19];
14441 - unsigned v = obj->objectId;
14442 + unsigned v = obj->obj_id;
14443 numString[19] = 0;
14444 - while (v > 0) {
14445 + while(v>0){
14446 x--;
14447 *x = '0' + (v % 10);
14448 v /= 10;
14449 }
14450 /* make up a name */
14451 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
14452 - yaffs_strcat(locName, x);
14453 - yaffs_strncpy(name, locName, buffSize - 1);
14454 + yaffs_strcat(locName,x);
14455 + yaffs_strncpy(name, locName, buffer_size - 1);
14456 + }
14457 +}
14458 +
14459 +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
14460 +{
14461 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14462 + if(dev->param.auto_unicode){
14463 + if(*ohName){
14464 + /* It is an ASCII name, so do an ASCII to unicode conversion */
14465 + const char *asciiOhName = (const char *)ohName;
14466 + int n = bufferSize - 1;
14467 + while(n > 0 && *asciiOhName){
14468 + *name = *asciiOhName;
14469 + name++;
14470 + asciiOhName++;
14471 + n--;
14472 + }
14473 + } else
14474 + yaffs_strncpy(name,ohName+1, bufferSize -1);
14475 + } else
14476 +#endif
14477 + yaffs_strncpy(name, ohName, bufferSize - 1);
14478 +}
14479 +
14480 +
14481 +static void yaffs_load_oh_from_name(yaffs_dev_t *dev, YCHAR *ohName, const YCHAR *name)
14482 +{
14483 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
14484 +
14485 + int isAscii;
14486 + YCHAR *w;
14487 +
14488 + if(dev->param.auto_unicode){
14489 +
14490 + isAscii = 1;
14491 + w = name;
14492 +
14493 + /* Figure out if the name will fit in ascii character set */
14494 + while(isAscii && *w){
14495 + if((*w) & 0xff00)
14496 + isAscii = 0;
14497 + w++;
14498 + }
14499
14500 + if(isAscii){
14501 + /* It is an ASCII name, so do a unicode to ascii conversion */
14502 + char *asciiOhName = (char *)ohName;
14503 + int n = YAFFS_MAX_NAME_LENGTH - 1;
14504 + while(n > 0 && *name){
14505 + *asciiOhName= *name;
14506 + name++;
14507 + asciiOhName++;
14508 + n--;
14509 + }
14510 + } else{
14511 + /* It is a unicode name, so save starting at the second YCHAR */
14512 + *ohName = 0;
14513 + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
14514 + }
14515 }
14516 + else
14517 +#endif
14518 + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
14519 +
14520 +}
14521 +
14522 +int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size)
14523 +{
14524 + memset(name, 0, buffer_size * sizeof(YCHAR));
14525 +
14526 + yaffs_check_obj_details_loaded(obj);
14527 +
14528 + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
14529 + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
14530 + }
14531 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
14532 - else if (obj->shortName[0])
14533 - yaffs_strcpy(name, obj->shortName);
14534 + else if (obj->short_name[0]) {
14535 + yaffs_strcpy(name, obj->short_name);
14536 + }
14537 #endif
14538 - else {
14539 + else if(obj->hdr_chunk > 0) {
14540 int result;
14541 - __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
14542 + __u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__);
14543
14544 - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
14545 + yaffs_obj_header *oh = (yaffs_obj_header *) buffer;
14546
14547 - memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
14548 + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
14549
14550 - if (obj->hdrChunk > 0) {
14551 - result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
14552 - obj->hdrChunk, buffer,
14553 + if (obj->hdr_chunk > 0) {
14554 + result = yaffs_rd_chunk_tags_nand(obj->my_dev,
14555 + obj->hdr_chunk, buffer,
14556 NULL);
14557 }
14558 - yaffs_strncpy(name, oh->name, buffSize - 1);
14559 + yaffs_load_name_from_oh(obj->my_dev,name,oh->name,buffer_size);
14560
14561 - yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
14562 + yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__);
14563 }
14564
14565 - return yaffs_strlen(name);
14566 + yaffs_fix_null_name(obj,name,buffer_size);
14567 +
14568 + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
14569 }
14570
14571 -int yaffs_GetObjectFileLength(yaffs_Object *obj)
14572 +
14573 +int yaffs_get_obj_length(yaffs_obj_t *obj)
14574 {
14575 /* Dereference any hard linking */
14576 - obj = yaffs_GetEquivalentObject(obj);
14577 + obj = yaffs_get_equivalent_obj(obj);
14578
14579 - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
14580 - return obj->variant.fileVariant.fileSize;
14581 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
14582 - return yaffs_strlen(obj->variant.symLinkVariant.alias);
14583 - else {
14584 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
14585 + return obj->variant.file_variant.file_size;
14586 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
14587 + if(!obj->variant.symlink_variant.alias)
14588 + return 0;
14589 + return yaffs_strnlen(obj->variant.symlink_variant.alias,YAFFS_MAX_ALIAS_LENGTH);
14590 + } else {
14591 /* Only a directory should drop through to here */
14592 - return obj->myDev->nDataBytesPerChunk;
14593 + return obj->my_dev->data_bytes_per_chunk;
14594 }
14595 }
14596
14597 -int yaffs_GetObjectLinkCount(yaffs_Object *obj)
14598 +int yaffs_get_obj_link_count(yaffs_obj_t *obj)
14599 {
14600 int count = 0;
14601 struct ylist_head *i;
14602 @@ -6915,24 +4804,24 @@ int yaffs_GetObjectLinkCount(yaffs_Objec
14603 if (!obj->unlinked)
14604 count++; /* the object itself */
14605
14606 - ylist_for_each(i, &obj->hardLinks)
14607 + ylist_for_each(i, &obj->hard_links)
14608 count++; /* add the hard links; */
14609
14610 return count;
14611 }
14612
14613 -int yaffs_GetObjectInode(yaffs_Object *obj)
14614 +int yaffs_get_obj_inode(yaffs_obj_t *obj)
14615 {
14616 - obj = yaffs_GetEquivalentObject(obj);
14617 + obj = yaffs_get_equivalent_obj(obj);
14618
14619 - return obj->objectId;
14620 + return obj->obj_id;
14621 }
14622
14623 -unsigned yaffs_GetObjectType(yaffs_Object *obj)
14624 +unsigned yaffs_get_obj_type(yaffs_obj_t *obj)
14625 {
14626 - obj = yaffs_GetEquivalentObject(obj);
14627 + obj = yaffs_get_equivalent_obj(obj);
14628
14629 - switch (obj->variantType) {
14630 + switch (obj->variant_type) {
14631 case YAFFS_OBJECT_TYPE_FILE:
14632 return DT_REG;
14633 break;
14634 @@ -6960,18 +4849,18 @@ unsigned yaffs_GetObjectType(yaffs_Objec
14635 }
14636 }
14637
14638 -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
14639 +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj)
14640 {
14641 - obj = yaffs_GetEquivalentObject(obj);
14642 - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
14643 - return yaffs_CloneString(obj->variant.symLinkVariant.alias);
14644 + obj = yaffs_get_equivalent_obj(obj);
14645 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
14646 + return yaffs_clone_str(obj->variant.symlink_variant.alias);
14647 else
14648 - return yaffs_CloneString(_Y(""));
14649 + return yaffs_clone_str(_Y(""));
14650 }
14651
14652 #ifndef CONFIG_YAFFS_WINCE
14653
14654 -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
14655 +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr)
14656 {
14657 unsigned int valid = attr->ia_valid;
14658
14659 @@ -6990,14 +4879,14 @@ int yaffs_SetAttributes(yaffs_Object *ob
14660 obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
14661
14662 if (valid & ATTR_SIZE)
14663 - yaffs_ResizeFile(obj, attr->ia_size);
14664 + yaffs_resize_file(obj, attr->ia_size);
14665
14666 - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
14667 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
14668
14669 return YAFFS_OK;
14670
14671 }
14672 -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
14673 +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr)
14674 {
14675 unsigned int valid = 0;
14676
14677 @@ -7015,7 +4904,7 @@ int yaffs_GetAttributes(yaffs_Object *ob
14678 Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
14679 valid |= ATTR_MTIME;
14680
14681 - attr->ia_size = yaffs_GetFileSize(obj);
14682 + attr->ia_size = yaffs_get_file_size(obj);
14683 valid |= ATTR_SIZE;
14684
14685 attr->ia_valid = valid;
14686 @@ -7025,20 +4914,137 @@ int yaffs_GetAttributes(yaffs_Object *ob
14687
14688 #endif
14689
14690 +
14691 +static int yaffs_do_xattrib_mod(yaffs_obj_t *obj, int set, const YCHAR *name, const void *value, int size, int flags)
14692 +{
14693 + yaffs_xattr_mod xmod;
14694 +
14695 + int result;
14696 +
14697 + xmod.set = set;
14698 + xmod.name = name;
14699 + xmod.data = value;
14700 + xmod.size = size;
14701 + xmod.flags = flags;
14702 + xmod.result = -ENOSPC;
14703 +
14704 + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
14705 +
14706 + if(result > 0)
14707 + return xmod.result;
14708 + else
14709 + return -ENOSPC;
14710 +}
14711 +
14712 +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod)
14713 +{
14714 + int retval = 0;
14715 + int x_offs = sizeof(yaffs_obj_header);
14716 + yaffs_dev_t *dev = obj->my_dev;
14717 + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
14718 +
14719 + char * x_buffer = buffer + x_offs;
14720 +
14721 + if(xmod->set)
14722 + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
14723 + else
14724 + retval = nval_del(x_buffer, x_size, xmod->name);
14725 +
14726 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
14727 + obj->xattr_known = 1;
14728 +
14729 + xmod->result = retval;
14730 +
14731 + return retval;
14732 +}
14733 +
14734 +static int yaffs_do_xattrib_fetch(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
14735 +{
14736 + char *buffer = NULL;
14737 + int result;
14738 + yaffs_ext_tags tags;
14739 + yaffs_dev_t *dev = obj->my_dev;
14740 + int x_offs = sizeof(yaffs_obj_header);
14741 + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
14742 +
14743 + char * x_buffer;
14744 +
14745 + int retval = 0;
14746 +
14747 + if(obj->hdr_chunk < 1)
14748 + return -ENODATA;
14749 +
14750 + /* If we know that the object has no xattribs then don't do all the
14751 + * reading and parsing.
14752 + */
14753 + if(obj->xattr_known && !obj->has_xattr){
14754 + if(name)
14755 + return -ENODATA;
14756 + else
14757 + return 0;
14758 + }
14759 +
14760 + buffer = (char *) yaffs_get_temp_buffer(dev, __LINE__);
14761 + if(!buffer)
14762 + return -ENOMEM;
14763 +
14764 + result = yaffs_rd_chunk_tags_nand(dev,obj->hdr_chunk, (__u8 *)buffer, &tags);
14765 +
14766 + if(result != YAFFS_OK)
14767 + retval = -ENOENT;
14768 + else{
14769 + x_buffer = buffer + x_offs;
14770 +
14771 + if (!obj->xattr_known){
14772 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
14773 + obj->xattr_known = 1;
14774 + }
14775 +
14776 + if(name)
14777 + retval = nval_get(x_buffer, x_size, name, value, size);
14778 + else
14779 + retval = nval_list(x_buffer, x_size, value,size);
14780 + }
14781 + yaffs_release_temp_buffer(dev,(__u8 *)buffer,__LINE__);
14782 + return retval;
14783 +}
14784 +
14785 +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags)
14786 +{
14787 + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
14788 +}
14789 +
14790 +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name)
14791 +{
14792 + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
14793 +}
14794 +
14795 +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
14796 +{
14797 + return yaffs_do_xattrib_fetch(obj, name, value, size);
14798 +}
14799 +
14800 +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size)
14801 +{
14802 + return yaffs_do_xattrib_fetch(obj, NULL, buffer,size);
14803 +}
14804 +
14805 +
14806 +
14807 #if 0
14808 -int yaffs_DumpObject(yaffs_Object *obj)
14809 +int yaffs_dump_obj(yaffs_obj_t *obj)
14810 {
14811 YCHAR name[257];
14812
14813 - yaffs_GetObjectName(obj, name, 256);
14814 + yaffs_get_obj_name(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
14815
14816 T(YAFFS_TRACE_ALWAYS,
14817 (TSTR
14818 ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
14819 " chunk %d type %d size %d\n"
14820 - TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
14821 - obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
14822 - yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
14823 + TENDSTR), obj->obj_id, yaffs_get_obj_inode(obj), name,
14824 + obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdr_chunk,
14825 + yaffs_get_obj_type(obj), yaffs_get_obj_length(obj)));
14826
14827 return YAFFS_OK;
14828 }
14829 @@ -7046,72 +5052,74 @@ int yaffs_DumpObject(yaffs_Object *obj)
14830
14831 /*---------------------------- Initialisation code -------------------------------------- */
14832
14833 -static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
14834 +static int yaffs_cehck_dev_fns(const yaffs_dev_t *dev)
14835 {
14836
14837 /* Common functions, gotta have */
14838 - if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
14839 + if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
14840 return 0;
14841
14842 #ifdef CONFIG_YAFFS_YAFFS2
14843
14844 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
14845 - if (dev->writeChunkWithTagsToNAND &&
14846 - dev->readChunkWithTagsFromNAND &&
14847 - !dev->writeChunkToNAND &&
14848 - !dev->readChunkFromNAND &&
14849 - dev->markNANDBlockBad && dev->queryNANDBlock)
14850 + if (dev->param.write_chunk_tags_fn &&
14851 + dev->param.read_chunk_tags_fn &&
14852 + !dev->param.write_chunk_fn &&
14853 + !dev->param.read_chunk_fn &&
14854 + dev->param.bad_block_fn &&
14855 + dev->param.query_block_fn)
14856 return 1;
14857 #endif
14858
14859 /* Can use the "spare" style interface for yaffs1 */
14860 - if (!dev->isYaffs2 &&
14861 - !dev->writeChunkWithTagsToNAND &&
14862 - !dev->readChunkWithTagsFromNAND &&
14863 - dev->writeChunkToNAND &&
14864 - dev->readChunkFromNAND &&
14865 - !dev->markNANDBlockBad && !dev->queryNANDBlock)
14866 + if (!dev->param.is_yaffs2 &&
14867 + !dev->param.write_chunk_tags_fn &&
14868 + !dev->param.read_chunk_tags_fn &&
14869 + dev->param.write_chunk_fn &&
14870 + dev->param.read_chunk_fn &&
14871 + !dev->param.bad_block_fn &&
14872 + !dev->param.query_block_fn)
14873 return 1;
14874
14875 - return 0; /* bad */
14876 + return 0; /* bad */
14877 }
14878
14879
14880 -static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
14881 +static int yaffs_create_initial_dir(yaffs_dev_t *dev)
14882 {
14883 /* Initialise the unlinked, deleted, root and lost and found directories */
14884
14885 - dev->lostNFoundDir = dev->rootDir = NULL;
14886 - dev->unlinkedDir = dev->deletedDir = NULL;
14887 + dev->lost_n_found = dev->root_dir = NULL;
14888 + dev->unlinked_dir = dev->del_dir = NULL;
14889
14890 - dev->unlinkedDir =
14891 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
14892 + dev->unlinked_dir =
14893 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
14894
14895 - dev->deletedDir =
14896 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
14897 + dev->del_dir =
14898 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
14899
14900 - dev->rootDir =
14901 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
14902 + dev->root_dir =
14903 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
14904 YAFFS_ROOT_MODE | S_IFDIR);
14905 - dev->lostNFoundDir =
14906 - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
14907 + dev->lost_n_found =
14908 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
14909 YAFFS_LOSTNFOUND_MODE | S_IFDIR);
14910
14911 - if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) {
14912 - yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
14913 + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir && dev->del_dir) {
14914 + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
14915 return YAFFS_OK;
14916 }
14917
14918 return YAFFS_FAIL;
14919 }
14920
14921 -int yaffs_GutsInitialise(yaffs_Device *dev)
14922 +int yaffs_guts_initialise(yaffs_dev_t *dev)
14923 {
14924 int init_failed = 0;
14925 unsigned x;
14926 int bits;
14927
14928 - T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
14929 + T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR)));
14930
14931 /* Check stuff that must be set */
14932
14933 @@ -7120,52 +5128,52 @@ int yaffs_GutsInitialise(yaffs_Device *d
14934 return YAFFS_FAIL;
14935 }
14936
14937 - dev->internalStartBlock = dev->startBlock;
14938 - dev->internalEndBlock = dev->endBlock;
14939 - dev->blockOffset = 0;
14940 - dev->chunkOffset = 0;
14941 - dev->nFreeChunks = 0;
14942 -
14943 - dev->gcBlock = -1;
14944 -
14945 - if (dev->startBlock == 0) {
14946 - dev->internalStartBlock = dev->startBlock + 1;
14947 - dev->internalEndBlock = dev->endBlock + 1;
14948 - dev->blockOffset = 1;
14949 - dev->chunkOffset = dev->nChunksPerBlock;
14950 + dev->internal_start_block = dev->param.start_block;
14951 + dev->internal_end_block = dev->param.end_block;
14952 + dev->block_offset = 0;
14953 + dev->chunk_offset = 0;
14954 + dev->n_free_chunks = 0;
14955 +
14956 + dev->gc_block = 0;
14957 +
14958 + if (dev->param.start_block == 0) {
14959 + dev->internal_start_block = dev->param.start_block + 1;
14960 + dev->internal_end_block = dev->param.end_block + 1;
14961 + dev->block_offset = 1;
14962 + dev->chunk_offset = dev->param.chunks_per_block;
14963 }
14964
14965 /* Check geometry parameters. */
14966
14967 - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
14968 - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
14969 - (dev->inbandTags && !dev->isYaffs2) ||
14970 - dev->nChunksPerBlock < 2 ||
14971 - dev->nReservedBlocks < 2 ||
14972 - dev->internalStartBlock <= 0 ||
14973 - dev->internalEndBlock <= 0 ||
14974 - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
14975 + if ((!dev->param.inband_tags && dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 1024) ||
14976 + (!dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 512) ||
14977 + (dev->param.inband_tags && !dev->param.is_yaffs2) ||
14978 + dev->param.chunks_per_block < 2 ||
14979 + dev->param.n_reserved_blocks < 2 ||
14980 + dev->internal_start_block <= 0 ||
14981 + dev->internal_end_block <= 0 ||
14982 + dev->internal_end_block <= (dev->internal_start_block + dev->param.n_reserved_blocks + 2)) { /* otherwise it is too small */
14983 T(YAFFS_TRACE_ALWAYS,
14984 (TSTR
14985 - ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
14986 - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
14987 + ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d "
14988 + TENDSTR), dev->param.total_bytes_per_chunk, dev->param.is_yaffs2 ? "2" : "", dev->param.inband_tags));
14989 return YAFFS_FAIL;
14990 }
14991
14992 - if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
14993 + if (yaffs_init_nand(dev) != YAFFS_OK) {
14994 T(YAFFS_TRACE_ALWAYS,
14995 (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
14996 return YAFFS_FAIL;
14997 }
14998
14999 /* Sort out space for inband tags, if required */
15000 - if (dev->inbandTags)
15001 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
15002 + if (dev->param.inband_tags)
15003 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk - sizeof(yaffs_PackedTags2TagsPart);
15004 else
15005 - dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
15006 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
15007
15008 /* Got the right mix of functions? */
15009 - if (!yaffs_CheckDevFunctions(dev)) {
15010 + if (!yaffs_cehck_dev_fns(dev)) {
15011 /* Function missing */
15012 T(YAFFS_TRACE_ALWAYS,
15013 (TSTR
15014 @@ -7175,13 +5183,13 @@ int yaffs_GutsInitialise(yaffs_Device *d
15015 }
15016
15017 /* This is really a compilation check. */
15018 - if (!yaffs_CheckStructures()) {
15019 + if (!yaffs_check_structures()) {
15020 T(YAFFS_TRACE_ALWAYS,
15021 - (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
15022 + (TSTR("yaffs_check_structures failed\n" TENDSTR)));
15023 return YAFFS_FAIL;
15024 }
15025
15026 - if (dev->isMounted) {
15027 + if (dev->is_mounted) {
15028 T(YAFFS_TRACE_ALWAYS,
15029 (TSTR("yaffs: device already mounted\n" TENDSTR)));
15030 return YAFFS_FAIL;
15031 @@ -7189,59 +5197,62 @@ int yaffs_GutsInitialise(yaffs_Device *d
15032
15033 /* Finished with most checks. One or two more checks happen later on too. */
15034
15035 - dev->isMounted = 1;
15036 + dev->is_mounted = 1;
15037
15038 /* OK now calculate a few things for the device */
15039
15040 /*
15041 * Calculate all the chunk size manipulation numbers:
15042 */
15043 - x = dev->nDataBytesPerChunk;
15044 - /* We always use dev->chunkShift and dev->chunkDiv */
15045 - dev->chunkShift = Shifts(x);
15046 - x >>= dev->chunkShift;
15047 - dev->chunkDiv = x;
15048 - /* We only use chunk mask if chunkDiv is 1 */
15049 - dev->chunkMask = (1<<dev->chunkShift) - 1;
15050 + x = dev->data_bytes_per_chunk;
15051 + /* We always use dev->chunk_shift and dev->chunk_div */
15052 + dev->chunk_shift = Shifts(x);
15053 + x >>= dev->chunk_shift;
15054 + dev->chunk_div = x;
15055 + /* We only use chunk mask if chunk_div is 1 */
15056 + dev->chunk_mask = (1<<dev->chunk_shift) - 1;
15057
15058 /*
15059 - * Calculate chunkGroupBits.
15060 - * We need to find the next power of 2 > than internalEndBlock
15061 + * Calculate chunk_grp_bits.
15062 + * We need to find the next power of 2 > than internal_end_block
15063 */
15064
15065 - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
15066 + x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
15067
15068 bits = ShiftsGE(x);
15069
15070 /* Set up tnode width if wide tnodes are enabled. */
15071 - if (!dev->wideTnodesDisabled) {
15072 + if (!dev->param.wide_tnodes_disabled) {
15073 /* bits must be even so that we end up with 32-bit words */
15074 if (bits & 1)
15075 bits++;
15076 if (bits < 16)
15077 - dev->tnodeWidth = 16;
15078 + dev->tnode_width = 16;
15079 else
15080 - dev->tnodeWidth = bits;
15081 + dev->tnode_width = bits;
15082 } else
15083 - dev->tnodeWidth = 16;
15084 + dev->tnode_width = 16;
15085
15086 - dev->tnodeMask = (1<<dev->tnodeWidth)-1;
15087 + dev->tnode_mask = (1<<dev->tnode_width)-1;
15088
15089 /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
15090 * so if the bitwidth of the
15091 * chunk range we're using is greater than 16 we need
15092 - * to figure out chunk shift and chunkGroupSize
15093 + * to figure out chunk shift and chunk_grp_size
15094 */
15095
15096 - if (bits <= dev->tnodeWidth)
15097 - dev->chunkGroupBits = 0;
15098 + if (bits <= dev->tnode_width)
15099 + dev->chunk_grp_bits = 0;
15100 else
15101 - dev->chunkGroupBits = bits - dev->tnodeWidth;
15102 + dev->chunk_grp_bits = bits - dev->tnode_width;
15103
15104 + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8;
15105 + if(dev->tnode_size < sizeof(yaffs_tnode_t))
15106 + dev->tnode_size = sizeof(yaffs_tnode_t);
15107
15108 - dev->chunkGroupSize = 1 << dev->chunkGroupBits;
15109 + dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
15110
15111 - if (dev->nChunksPerBlock < dev->chunkGroupSize) {
15112 + if (dev->param.chunks_per_block < dev->chunk_grp_size) {
15113 /* We have a problem because the soft delete won't work if
15114 * the chunk group size > chunks per block.
15115 * This can be remedied by using larger "virtual blocks".
15116 @@ -7255,85 +5266,89 @@ int yaffs_GutsInitialise(yaffs_Device *d
15117 /* OK, we've finished verifying the device, lets continue with initialisation */
15118
15119 /* More device initialisation */
15120 - dev->garbageCollections = 0;
15121 - dev->passiveGarbageCollections = 0;
15122 - dev->currentDirtyChecker = 0;
15123 - dev->bufferedBlock = -1;
15124 - dev->doingBufferedBlockRewrite = 0;
15125 - dev->nDeletedFiles = 0;
15126 - dev->nBackgroundDeletions = 0;
15127 - dev->nUnlinkedFiles = 0;
15128 - dev->eccFixed = 0;
15129 - dev->eccUnfixed = 0;
15130 - dev->tagsEccFixed = 0;
15131 - dev->tagsEccUnfixed = 0;
15132 - dev->nErasureFailures = 0;
15133 - dev->nErasedBlocks = 0;
15134 - dev->isDoingGC = 0;
15135 - dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
15136 + dev->all_gcs = 0;
15137 + dev->passive_gc_count = 0;
15138 + dev->oldest_dirty_gc_count = 0;
15139 + dev->bg_gcs = 0;
15140 + dev->gc_block_finder = 0;
15141 + dev->buffered_block = -1;
15142 + dev->doing_buffered_block_rewrite = 0;
15143 + dev->n_deleted_files = 0;
15144 + dev->n_bg_deletions = 0;
15145 + dev->n_unlinked_files = 0;
15146 + dev->n_ecc_fixed = 0;
15147 + dev->n_ecc_unfixed = 0;
15148 + dev->n_tags_ecc_fixed = 0;
15149 + dev->n_tags_ecc_unfixed = 0;
15150 + dev->n_erase_failures = 0;
15151 + dev->n_erased_blocks = 0;
15152 + dev->gc_disable= 0;
15153 + dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */
15154 + YINIT_LIST_HEAD(&dev->dirty_dirs);
15155 + dev->oldest_dirty_seq = 0;
15156 + dev->oldest_dirty_block = 0;
15157
15158 /* Initialise temporary buffers and caches. */
15159 - if (!yaffs_InitialiseTempBuffers(dev))
15160 + if (!yaffs_init_tmp_buffers(dev))
15161 init_failed = 1;
15162
15163 - dev->srCache = NULL;
15164 - dev->gcCleanupList = NULL;
15165 + dev->cache = NULL;
15166 + dev->gc_cleanup_list = NULL;
15167
15168
15169 if (!init_failed &&
15170 - dev->nShortOpCaches > 0) {
15171 + dev->param.n_caches > 0) {
15172 int i;
15173 void *buf;
15174 - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
15175 + int cacheBytes = dev->param.n_caches * sizeof(yaffs_cache_t);
15176
15177 - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
15178 - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
15179 + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
15180 + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
15181
15182 - dev->srCache = YMALLOC(srCacheBytes);
15183 + dev->cache = YMALLOC(cacheBytes);
15184
15185 - buf = (__u8 *) dev->srCache;
15186 + buf = (__u8 *) dev->cache;
15187
15188 - if (dev->srCache)
15189 - memset(dev->srCache, 0, srCacheBytes);
15190 + if (dev->cache)
15191 + memset(dev->cache, 0, cacheBytes);
15192
15193 - for (i = 0; i < dev->nShortOpCaches && buf; i++) {
15194 - dev->srCache[i].object = NULL;
15195 - dev->srCache[i].lastUse = 0;
15196 - dev->srCache[i].dirty = 0;
15197 - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
15198 + for (i = 0; i < dev->param.n_caches && buf; i++) {
15199 + dev->cache[i].object = NULL;
15200 + dev->cache[i].last_use = 0;
15201 + dev->cache[i].dirty = 0;
15202 + dev->cache[i].data = buf = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
15203 }
15204 if (!buf)
15205 init_failed = 1;
15206
15207 - dev->srLastUse = 0;
15208 + dev->cache_last_use = 0;
15209 }
15210
15211 - dev->cacheHits = 0;
15212 + dev->cache_hits = 0;
15213
15214 if (!init_failed) {
15215 - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
15216 - if (!dev->gcCleanupList)
15217 + dev->gc_cleanup_list = YMALLOC(dev->param.chunks_per_block * sizeof(__u32));
15218 + if (!dev->gc_cleanup_list)
15219 init_failed = 1;
15220 }
15221
15222 - if (dev->isYaffs2)
15223 - dev->useHeaderFileSize = 1;
15224 + if (dev->param.is_yaffs2)
15225 + dev->param.use_header_file_size = 1;
15226
15227 - if (!init_failed && !yaffs_InitialiseBlocks(dev))
15228 + if (!init_failed && !yaffs_init_blocks(dev))
15229 init_failed = 1;
15230
15231 - yaffs_InitialiseTnodes(dev);
15232 - yaffs_InitialiseObjects(dev);
15233 + yaffs_init_tnodes_and_objs(dev);
15234
15235 - if (!init_failed && !yaffs_CreateInitialDirectories(dev))
15236 + if (!init_failed && !yaffs_create_initial_dir(dev))
15237 init_failed = 1;
15238
15239
15240 if (!init_failed) {
15241 /* Now scan the flash. */
15242 - if (dev->isYaffs2) {
15243 - if (yaffs_CheckpointRestore(dev)) {
15244 - yaffs_CheckObjectDetailsLoaded(dev->rootDir);
15245 + if (dev->param.is_yaffs2) {
15246 + if (yaffs2_checkpt_restore(dev)) {
15247 + yaffs_check_obj_details_loaded(dev->root_dir);
15248 T(YAFFS_TRACE_ALWAYS,
15249 (TSTR("yaffs: restored from checkpoint" TENDSTR)));
15250 } else {
15251 @@ -7341,128 +5356,129 @@ int yaffs_GutsInitialise(yaffs_Device *d
15252 /* Clean up the mess caused by an aborted checkpoint load
15253 * and scan backwards.
15254 */
15255 - yaffs_DeinitialiseBlocks(dev);
15256 - yaffs_DeinitialiseTnodes(dev);
15257 - yaffs_DeinitialiseObjects(dev);
15258 + yaffs_deinit_blocks(dev);
15259
15260 + yaffs_deinit_tnodes_and_objs(dev);
15261
15262 - dev->nErasedBlocks = 0;
15263 - dev->nFreeChunks = 0;
15264 - dev->allocationBlock = -1;
15265 - dev->allocationPage = -1;
15266 - dev->nDeletedFiles = 0;
15267 - dev->nUnlinkedFiles = 0;
15268 - dev->nBackgroundDeletions = 0;
15269 - dev->oldestDirtySequence = 0;
15270 + dev->n_erased_blocks = 0;
15271 + dev->n_free_chunks = 0;
15272 + dev->alloc_block = -1;
15273 + dev->alloc_page = -1;
15274 + dev->n_deleted_files = 0;
15275 + dev->n_unlinked_files = 0;
15276 + dev->n_bg_deletions = 0;
15277
15278 - if (!init_failed && !yaffs_InitialiseBlocks(dev))
15279 + if (!init_failed && !yaffs_init_blocks(dev))
15280 init_failed = 1;
15281
15282 - yaffs_InitialiseTnodes(dev);
15283 - yaffs_InitialiseObjects(dev);
15284 + yaffs_init_tnodes_and_objs(dev);
15285
15286 - if (!init_failed && !yaffs_CreateInitialDirectories(dev))
15287 + if (!init_failed && !yaffs_create_initial_dir(dev))
15288 init_failed = 1;
15289
15290 - if (!init_failed && !yaffs_ScanBackwards(dev))
15291 + if (!init_failed && !yaffs2_scan_backwards(dev))
15292 init_failed = 1;
15293 }
15294 - } else if (!yaffs_Scan(dev))
15295 + } else if (!yaffs1_scan(dev))
15296 init_failed = 1;
15297
15298 - yaffs_StripDeletedObjects(dev);
15299 + yaffs_strip_deleted_objs(dev);
15300 + yaffs_fix_hanging_objs(dev);
15301 + if(dev->param.empty_lost_n_found)
15302 + yaffs_empty_l_n_f(dev);
15303 }
15304
15305 if (init_failed) {
15306 /* Clean up the mess */
15307 T(YAFFS_TRACE_TRACING,
15308 - (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
15309 + (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR)));
15310
15311 - yaffs_Deinitialise(dev);
15312 + yaffs_deinitialise(dev);
15313 return YAFFS_FAIL;
15314 }
15315
15316 /* Zero out stats */
15317 - dev->nPageReads = 0;
15318 - dev->nPageWrites = 0;
15319 - dev->nBlockErasures = 0;
15320 - dev->nGCCopies = 0;
15321 - dev->nRetriedWrites = 0;
15322 -
15323 - dev->nRetiredBlocks = 0;
15324 -
15325 - yaffs_VerifyFreeChunks(dev);
15326 - yaffs_VerifyBlocks(dev);
15327 -
15328 + dev->n_page_reads = 0;
15329 + dev->n_page_writes = 0;
15330 + dev->n_erasures = 0;
15331 + dev->n_gc_copies = 0;
15332 + dev->n_retired_writes = 0;
15333 +
15334 + dev->n_retired_blocks = 0;
15335 +
15336 + yaffs_verify_free_chunks(dev);
15337 + yaffs_verify_blocks(dev);
15338 +
15339 + /* Clean up any aborted checkpoint data */
15340 + if(!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
15341 + yaffs2_checkpt_invalidate(dev);
15342
15343 T(YAFFS_TRACE_TRACING,
15344 - (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
15345 + (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR)));
15346 return YAFFS_OK;
15347
15348 }
15349
15350 -void yaffs_Deinitialise(yaffs_Device *dev)
15351 +void yaffs_deinitialise(yaffs_dev_t *dev)
15352 {
15353 - if (dev->isMounted) {
15354 + if (dev->is_mounted) {
15355 int i;
15356
15357 - yaffs_DeinitialiseBlocks(dev);
15358 - yaffs_DeinitialiseTnodes(dev);
15359 - yaffs_DeinitialiseObjects(dev);
15360 - if (dev->nShortOpCaches > 0 &&
15361 - dev->srCache) {
15362 + yaffs_deinit_blocks(dev);
15363 + yaffs_deinit_tnodes_and_objs(dev);
15364 + if (dev->param.n_caches > 0 &&
15365 + dev->cache) {
15366
15367 - for (i = 0; i < dev->nShortOpCaches; i++) {
15368 - if (dev->srCache[i].data)
15369 - YFREE(dev->srCache[i].data);
15370 - dev->srCache[i].data = NULL;
15371 + for (i = 0; i < dev->param.n_caches; i++) {
15372 + if (dev->cache[i].data)
15373 + YFREE(dev->cache[i].data);
15374 + dev->cache[i].data = NULL;
15375 }
15376
15377 - YFREE(dev->srCache);
15378 - dev->srCache = NULL;
15379 + YFREE(dev->cache);
15380 + dev->cache = NULL;
15381 }
15382
15383 - YFREE(dev->gcCleanupList);
15384 + YFREE(dev->gc_cleanup_list);
15385
15386 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
15387 - YFREE(dev->tempBuffer[i].buffer);
15388 + YFREE(dev->temp_buffer[i].buffer);
15389
15390 - dev->isMounted = 0;
15391 + dev->is_mounted = 0;
15392
15393 - if (dev->deinitialiseNAND)
15394 - dev->deinitialiseNAND(dev);
15395 + if (dev->param.deinitialise_flash_fn)
15396 + dev->param.deinitialise_flash_fn(dev);
15397 }
15398 }
15399
15400 -static int yaffs_CountFreeChunks(yaffs_Device *dev)
15401 +int yaffs_count_free_chunks(yaffs_dev_t *dev)
15402 {
15403 - int nFree;
15404 + int nFree=0;
15405 int b;
15406
15407 - yaffs_BlockInfo *blk;
15408 -
15409 - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
15410 - b++) {
15411 - blk = yaffs_GetBlockInfo(dev, b);
15412 + yaffs_block_info_t *blk;
15413
15414 - switch (blk->blockState) {
15415 + blk = dev->block_info;
15416 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
15417 + switch (blk->block_state) {
15418 case YAFFS_BLOCK_STATE_EMPTY:
15419 case YAFFS_BLOCK_STATE_ALLOCATING:
15420 case YAFFS_BLOCK_STATE_COLLECTING:
15421 case YAFFS_BLOCK_STATE_FULL:
15422 nFree +=
15423 - (dev->nChunksPerBlock - blk->pagesInUse +
15424 - blk->softDeletions);
15425 + (dev->param.chunks_per_block - blk->pages_in_use +
15426 + blk->soft_del_pages);
15427 break;
15428 default:
15429 break;
15430 }
15431 + blk++;
15432 }
15433
15434 return nFree;
15435 }
15436
15437 -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
15438 +int yaffs_get_n_free_chunks(yaffs_dev_t *dev)
15439 {
15440 /* This is what we report to the outside world */
15441
15442 @@ -7472,30 +5488,28 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
15443 int i;
15444
15445 #if 1
15446 - nFree = dev->nFreeChunks;
15447 + nFree = dev->n_free_chunks;
15448 #else
15449 - nFree = yaffs_CountFreeChunks(dev);
15450 + nFree = yaffs_count_free_chunks(dev);
15451 #endif
15452
15453 - nFree += dev->nDeletedFiles;
15454 + nFree += dev->n_deleted_files;
15455
15456 /* Now count the number of dirty chunks in the cache and subtract those */
15457
15458 - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
15459 - if (dev->srCache[i].dirty)
15460 + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.n_caches; i++) {
15461 + if (dev->cache[i].dirty)
15462 nDirtyCacheChunks++;
15463 }
15464
15465 nFree -= nDirtyCacheChunks;
15466
15467 - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
15468 + nFree -= ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
15469
15470 /* Now we figure out how much to reserve for the checkpoint and report that... */
15471 - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
15472 - if (blocksForCheckpoint < 0)
15473 - blocksForCheckpoint = 0;
15474 + blocksForCheckpoint = yaffs_calc_checkpt_blocks_required(dev);
15475
15476 - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
15477 + nFree -= (blocksForCheckpoint * dev->param.chunks_per_block);
15478
15479 if (nFree < 0)
15480 nFree = 0;
15481 @@ -7504,49 +5518,27 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De
15482
15483 }
15484
15485 -static int yaffs_freeVerificationFailures;
15486 -
15487 -static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
15488 -{
15489 - int counted;
15490 - int difference;
15491 -
15492 - if (yaffs_SkipVerification(dev))
15493 - return;
15494 -
15495 - counted = yaffs_CountFreeChunks(dev);
15496 -
15497 - difference = dev->nFreeChunks - counted;
15498 -
15499 - if (difference) {
15500 - T(YAFFS_TRACE_ALWAYS,
15501 - (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
15502 - dev->nFreeChunks, counted, difference));
15503 - yaffs_freeVerificationFailures++;
15504 - }
15505 -}
15506
15507 /*---------------------------------------- YAFFS test code ----------------------*/
15508
15509 -#define yaffs_CheckStruct(structure, syze, name) \
15510 +#define yaffs_check_struct(structure, syze, name) \
15511 do { \
15512 if (sizeof(structure) != syze) { \
15513 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
15514 - name, syze, sizeof(structure))); \
15515 + name, syze, (int) sizeof(structure))); \
15516 return YAFFS_FAIL; \
15517 } \
15518 } while (0)
15519
15520 -static int yaffs_CheckStructures(void)
15521 +static int yaffs_check_structures(void)
15522 {
15523 -/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
15524 -/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
15525 -/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
15526 -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
15527 - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
15528 -#endif
15529 +/* yaffs_check_struct(yaffs_tags_t,8,"yaffs_tags_t"); */
15530 +/* yaffs_check_struct(yaffs_tags_union_t,8,"yaffs_tags_union_t"); */
15531 +/* yaffs_check_struct(yaffs_spare,16,"yaffs_spare"); */
15532 +/* yaffs_check_struct(yaffs_tnode_t, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_tnode_t"); */
15533 +
15534 #ifndef CONFIG_YAFFS_WINCE
15535 - yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
15536 + yaffs_check_struct(yaffs_obj_header, 512, "yaffs_obj_header");
15537 #endif
15538 return YAFFS_OK;
15539 }
15540 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.h
15541 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_guts.h 2010-10-20 13:17:58.954000294 +0300
15542 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_guts.h 2010-10-20 13:28:16.061000294 +0300
15543 @@ -1,7 +1,7 @@
15544 /*
15545 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
15546 *
15547 - * Copyright (C) 2002-2007 Aleph One Ltd.
15548 + * Copyright (C) 2002-2010 Aleph One Ltd.
15549 * for Toby Churchill Ltd and Brightstar Engineering
15550 *
15551 * Created by Charles Manning <charles@aleph1.co.uk>
15552 @@ -16,8 +16,9 @@
15553 #ifndef __YAFFS_GUTS_H__
15554 #define __YAFFS_GUTS_H__
15555
15556 -#include "devextras.h"
15557 #include "yportenv.h"
15558 +#include "devextras.h"
15559 +#include "yaffs_list.h"
15560
15561 #define YAFFS_OK 1
15562 #define YAFFS_FAIL 0
15563 @@ -52,7 +53,6 @@
15564
15565 #define YAFFS_MAX_CHUNK_ID 0x000FFFFF
15566
15567 -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
15568
15569 #define YAFFS_ALLOCATION_NOBJECTS 100
15570 #define YAFFS_ALLOCATION_NTNODES 100
15571 @@ -62,8 +62,9 @@
15572
15573
15574 #define YAFFS_OBJECT_SPACE 0x40000
15575 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
15576
15577 -#define YAFFS_CHECKPOINT_VERSION 3
15578 +#define YAFFS_CHECKPOINT_VERSION 4
15579
15580 #ifdef CONFIG_YAFFS_UNICODE
15581 #define YAFFS_MAX_NAME_LENGTH 127
15582 @@ -81,12 +82,11 @@
15583 #define YAFFS_OBJECTID_UNLINKED 3
15584 #define YAFFS_OBJECTID_DELETED 4
15585
15586 -/* Sseudo object ids for checkpointing */
15587 +/* Pseudo object ids for checkpointing */
15588 #define YAFFS_OBJECTID_SB_HEADER 0x10
15589 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
15590 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
15591
15592 -/* */
15593
15594 #define YAFFS_MAX_SHORT_OP_CACHES 20
15595
15596 @@ -113,18 +113,14 @@
15597
15598 /* ChunkCache is used for short read/write operations.*/
15599 typedef struct {
15600 - struct yaffs_ObjectStruct *object;
15601 - int chunkId;
15602 - int lastUse;
15603 + struct yaffs_obj_s *object;
15604 + int chunk_id;
15605 + int last_use;
15606 int dirty;
15607 - int nBytes; /* Only valid if the cache is dirty */
15608 + int n_bytes; /* Only valid if the cache is dirty */
15609 int locked; /* Can't push out or flush while locked. */
15610 -#ifdef CONFIG_YAFFS_YAFFS2
15611 __u8 *data;
15612 -#else
15613 - __u8 data[YAFFS_BYTES_PER_CHUNK];
15614 -#endif
15615 -} yaffs_ChunkCache;
15616 +} yaffs_cache_t;
15617
15618
15619
15620 @@ -135,18 +131,18 @@ typedef struct {
15621
15622 #ifndef CONFIG_YAFFS_NO_YAFFS1
15623 typedef struct {
15624 - unsigned chunkId:20;
15625 - unsigned serialNumber:2;
15626 - unsigned byteCountLSB:10;
15627 - unsigned objectId:18;
15628 + unsigned chunk_id:20;
15629 + unsigned serial_number:2;
15630 + unsigned n_bytes_lsb:10;
15631 + unsigned obj_id:18;
15632 unsigned ecc:12;
15633 - unsigned byteCountMSB:2;
15634 -} yaffs_Tags;
15635 + unsigned n_bytes_msb:2;
15636 +} yaffs_tags_t;
15637
15638 typedef union {
15639 - yaffs_Tags asTags;
15640 - __u8 asBytes[8];
15641 -} yaffs_TagsUnion;
15642 + yaffs_tags_t as_tags;
15643 + __u8 as_bytes[8];
15644 +} yaffs_tags_union_t;
15645
15646 #endif
15647
15648 @@ -157,7 +153,7 @@ typedef enum {
15649 YAFFS_ECC_RESULT_NO_ERROR,
15650 YAFFS_ECC_RESULT_FIXED,
15651 YAFFS_ECC_RESULT_UNFIXED
15652 -} yaffs_ECCResult;
15653 +} yaffs_ecc_result;
15654
15655 typedef enum {
15656 YAFFS_OBJECT_TYPE_UNKNOWN,
15657 @@ -166,64 +162,64 @@ typedef enum {
15658 YAFFS_OBJECT_TYPE_DIRECTORY,
15659 YAFFS_OBJECT_TYPE_HARDLINK,
15660 YAFFS_OBJECT_TYPE_SPECIAL
15661 -} yaffs_ObjectType;
15662 +} yaffs_obj_type;
15663
15664 #define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
15665
15666 typedef struct {
15667
15668 - unsigned validMarker0;
15669 - unsigned chunkUsed; /* Status of the chunk: used or unused */
15670 - unsigned objectId; /* If 0 then this is not part of an object (unused) */
15671 - unsigned chunkId; /* If 0 then this is a header, else a data chunk */
15672 - unsigned byteCount; /* Only valid for data chunks */
15673 + unsigned validity1;
15674 + unsigned chunk_used; /* Status of the chunk: used or unused */
15675 + unsigned obj_id; /* If 0 then this is not part of an object (unused) */
15676 + unsigned chunk_id; /* If 0 then this is a header, else a data chunk */
15677 + unsigned n_bytes; /* Only valid for data chunks */
15678
15679 /* The following stuff only has meaning when we read */
15680 - yaffs_ECCResult eccResult;
15681 - unsigned blockBad;
15682 + yaffs_ecc_result ecc_result;
15683 + unsigned block_bad;
15684
15685 /* YAFFS 1 stuff */
15686 - unsigned chunkDeleted; /* The chunk is marked deleted */
15687 - unsigned serialNumber; /* Yaffs1 2-bit serial number */
15688 + unsigned is_deleted; /* The chunk is marked deleted */
15689 + unsigned serial_number; /* Yaffs1 2-bit serial number */
15690
15691 /* YAFFS2 stuff */
15692 - unsigned sequenceNumber; /* The sequence number of this block */
15693 + unsigned seq_number; /* The sequence number of this block */
15694
15695 /* Extra info if this is an object header (YAFFS2 only) */
15696
15697 - unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
15698 - unsigned extraParentObjectId; /* The parent object */
15699 - unsigned extraIsShrinkHeader; /* Is it a shrink header? */
15700 - unsigned extraShadows; /* Does this shadow another object? */
15701 + unsigned extra_available; /* There is extra info available if this is not zero */
15702 + unsigned extra_parent_id; /* The parent object */
15703 + unsigned extra_is_shrink; /* Is it a shrink header? */
15704 + unsigned extra_shadows; /* Does this shadow another object? */
15705
15706 - yaffs_ObjectType extraObjectType; /* What object type? */
15707 + yaffs_obj_type extra_obj_type; /* What object type? */
15708
15709 - unsigned extraFileLength; /* Length if it is a file */
15710 - unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
15711 + unsigned extra_length; /* Length if it is a file */
15712 + unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */
15713
15714 - unsigned validMarker1;
15715 + unsigned validty1;
15716
15717 -} yaffs_ExtendedTags;
15718 +} yaffs_ext_tags;
15719
15720 /* Spare structure for YAFFS1 */
15721 typedef struct {
15722 - __u8 tagByte0;
15723 - __u8 tagByte1;
15724 - __u8 tagByte2;
15725 - __u8 tagByte3;
15726 - __u8 pageStatus; /* set to 0 to delete the chunk */
15727 - __u8 blockStatus;
15728 - __u8 tagByte4;
15729 - __u8 tagByte5;
15730 + __u8 tb0;
15731 + __u8 tb1;
15732 + __u8 tb2;
15733 + __u8 tb3;
15734 + __u8 page_status; /* set to 0 to delete the chunk */
15735 + __u8 block_status;
15736 + __u8 tb4;
15737 + __u8 tb5;
15738 __u8 ecc1[3];
15739 - __u8 tagByte6;
15740 - __u8 tagByte7;
15741 + __u8 tb6;
15742 + __u8 tb7;
15743 __u8 ecc2[3];
15744 -} yaffs_Spare;
15745 +} yaffs_spare;
15746
15747 /*Special structure for passing through to mtd */
15748 -struct yaffs_NANDSpare {
15749 - yaffs_Spare spare;
15750 +struct yaffs_nand_spare {
15751 + yaffs_spare spare;
15752 int eccres1;
15753 int eccres2;
15754 };
15755 @@ -234,6 +230,8 @@ typedef enum {
15756 YAFFS_BLOCK_STATE_UNKNOWN = 0,
15757
15758 YAFFS_BLOCK_STATE_SCANNING,
15759 + /* Being scanned */
15760 +
15761 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
15762 /* The block might have something on it (ie it is allocating or full, perhaps empty)
15763 * but it needs to be scanned to determine its true state.
15764 @@ -249,67 +247,69 @@ typedef enum {
15765 /* This block is partially allocated.
15766 * At least one page holds valid data.
15767 * This is the one currently being used for page
15768 - * allocation. Should never be more than one of these
15769 + * allocation. Should never be more than one of these.
15770 + * If a block is only partially allocated at mount it is treated as full.
15771 */
15772
15773 YAFFS_BLOCK_STATE_FULL,
15774 /* All the pages in this block have been allocated.
15775 + * If a block was only partially allocated when mounted we treat
15776 + * it as fully allocated.
15777 */
15778
15779 YAFFS_BLOCK_STATE_DIRTY,
15780 - /* All pages have been allocated and deleted.
15781 + /* The block was full and now all chunks have been deleted.
15782 * Erase me, reuse me.
15783 */
15784
15785 YAFFS_BLOCK_STATE_CHECKPOINT,
15786 - /* This block is assigned to holding checkpoint data.
15787 - */
15788 + /* This block is assigned to holding checkpoint data. */
15789
15790 YAFFS_BLOCK_STATE_COLLECTING,
15791 /* This block is being garbage collected */
15792
15793 YAFFS_BLOCK_STATE_DEAD
15794 /* This block has failed and is not in use */
15795 -} yaffs_BlockState;
15796 +} yaffs_block_state_t;
15797
15798 #define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
15799
15800
15801 typedef struct {
15802
15803 - int softDeletions:10; /* number of soft deleted pages */
15804 - int pagesInUse:10; /* number of pages in use */
15805 - unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
15806 - __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
15807 + int soft_del_pages:10; /* number of soft deleted pages */
15808 + int pages_in_use:10; /* number of pages in use */
15809 + unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
15810 + __u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */
15811 /* and retire the block. */
15812 - __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */
15813 - __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block.
15814 + __u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */
15815 + __u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block.
15816 It should be prioritised for GC */
15817 - __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
15818 + __u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
15819
15820 #ifdef CONFIG_YAFFS_YAFFS2
15821 - __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
15822 - __u32 sequenceNumber; /* block sequence number for yaffs2 */
15823 + __u32 has_shrink_hdr:1; /* This block has at least one shrink object header */
15824 + __u32 seq_number; /* block sequence number for yaffs2 */
15825 #endif
15826
15827 -} yaffs_BlockInfo;
15828 +} yaffs_block_info_t;
15829
15830 /* -------------------------- Object structure -------------------------------*/
15831 /* This is the object structure as stored on NAND */
15832
15833 typedef struct {
15834 - yaffs_ObjectType type;
15835 + yaffs_obj_type type;
15836
15837 /* Apply to everything */
15838 - int parentObjectId;
15839 - __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
15840 + int parent_obj_id;
15841 + __u16 sum_no_longer_used; /* checksum of name. No longer used */
15842 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
15843
15844 /* The following apply to directories, files, symlinks - not hard links */
15845 __u32 yst_mode; /* protection */
15846
15847 #ifdef CONFIG_YAFFS_WINCE
15848 - __u32 notForWinCE[5];
15849 + __u32 not_for_wince[5];
15850 #else
15851 __u32 yst_uid;
15852 __u32 yst_gid;
15853 @@ -319,10 +319,10 @@ typedef struct {
15854 #endif
15855
15856 /* File size applies to files only */
15857 - int fileSize;
15858 + int file_size;
15859
15860 /* Equivalent object id applies to hard links only. */
15861 - int equivalentObjectId;
15862 + int equiv_id;
15863
15864 /* Alias is for symlinks only. */
15865 YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
15866 @@ -334,40 +334,29 @@ typedef struct {
15867 __u32 win_atime[2];
15868 __u32 win_mtime[2];
15869 #else
15870 - __u32 roomToGrow[6];
15871 + __u32 room_to_grow[6];
15872
15873 #endif
15874 - __u32 inbandShadowsObject;
15875 - __u32 inbandIsShrink;
15876 + __u32 inband_shadowed_obj_id;
15877 + __u32 inband_is_shrink;
15878
15879 - __u32 reservedSpace[2];
15880 - int shadowsObject; /* This object header shadows the specified object if > 0 */
15881 + __u32 reserved[2];
15882 + int shadows_obj; /* This object header shadows the specified object if > 0 */
15883
15884 - /* isShrink applies to object headers written when we shrink the file (ie resize) */
15885 - __u32 isShrink;
15886 + /* is_shrink applies to object headers written when we shrink the file (ie resize) */
15887 + __u32 is_shrink;
15888
15889 -} yaffs_ObjectHeader;
15890 +} yaffs_obj_header;
15891
15892 /*--------------------------- Tnode -------------------------- */
15893
15894 -union yaffs_Tnode_union {
15895 -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
15896 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
15897 -#else
15898 - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
15899 -#endif
15900 -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
15901 +union yaffs_tnode_union {
15902 + union yaffs_tnode_union *internal[YAFFS_NTNODES_INTERNAL];
15903
15904 };
15905
15906 -typedef union yaffs_Tnode_union yaffs_Tnode;
15907 +typedef union yaffs_tnode_union yaffs_tnode_t;
15908
15909 -struct yaffs_TnodeList_struct {
15910 - struct yaffs_TnodeList_struct *next;
15911 - yaffs_Tnode *tnodes;
15912 -};
15913 -
15914 -typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
15915
15916 /*------------------------ Object -----------------------------*/
15917 /* An object can be one of:
15918 @@ -378,82 +367,85 @@ typedef struct yaffs_TnodeList_struct ya
15919 */
15920
15921 typedef struct {
15922 - __u32 fileSize;
15923 - __u32 scannedFileSize;
15924 - __u32 shrinkSize;
15925 - int topLevel;
15926 - yaffs_Tnode *top;
15927 -} yaffs_FileStructure;
15928 + __u32 file_size;
15929 + __u32 scanned_size;
15930 + __u32 shrink_size;
15931 + int top_level;
15932 + yaffs_tnode_t *top;
15933 +} yaffs_file_s;
15934
15935 typedef struct {
15936 struct ylist_head children; /* list of child links */
15937 -} yaffs_DirectoryStructure;
15938 + struct ylist_head dirty; /* Entry for list of dirty directories */
15939 +} yaffs_dir_s;
15940
15941 typedef struct {
15942 YCHAR *alias;
15943 -} yaffs_SymLinkStructure;
15944 +} yaffs_symlink_t;
15945
15946 typedef struct {
15947 - struct yaffs_ObjectStruct *equivalentObject;
15948 - __u32 equivalentObjectId;
15949 -} yaffs_HardLinkStructure;
15950 + struct yaffs_obj_s *equiv_obj;
15951 + __u32 equiv_id;
15952 +} yaffs_hard_link_s;
15953
15954 typedef union {
15955 - yaffs_FileStructure fileVariant;
15956 - yaffs_DirectoryStructure directoryVariant;
15957 - yaffs_SymLinkStructure symLinkVariant;
15958 - yaffs_HardLinkStructure hardLinkVariant;
15959 -} yaffs_ObjectVariant;
15960 + yaffs_file_s file_variant;
15961 + yaffs_dir_s dir_variant;
15962 + yaffs_symlink_t symlink_variant;
15963 + yaffs_hard_link_s hardlink_variant;
15964 +} yaffs_obj_variant;
15965 +
15966 +
15967
15968 -struct yaffs_ObjectStruct {
15969 +struct yaffs_obj_s {
15970 __u8 deleted:1; /* This should only apply to unlinked files. */
15971 - __u8 softDeleted:1; /* it has also been soft deleted */
15972 + __u8 soft_del:1; /* it has also been soft deleted */
15973 __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
15974 __u8 fake:1; /* A fake object has no presence on NAND. */
15975 - __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
15976 - __u8 unlinkAllowed:1;
15977 + __u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */
15978 + __u8 unlink_allowed:1;
15979 __u8 dirty:1; /* the object needs to be written to flash */
15980 __u8 valid:1; /* When the file system is being loaded up, this
15981 * object might be created before the data
15982 * is available (ie. file data records appear before the header).
15983 */
15984 - __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
15985 + __u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */
15986
15987 - __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
15988 + __u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is
15989 * still in the inode cache. Free of object is defered.
15990 * until the inode is released.
15991 */
15992 - __u8 beingCreated:1; /* This object is still being created so skip some checks. */
15993 + __u8 being_created:1; /* This object is still being created so skip some checks. */
15994 + __u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */
15995 +
15996 + __u8 xattr_known:1; /* We know if this has object has xattribs or not. */
15997 + __u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */
15998
15999 __u8 serial; /* serial number of chunk in NAND. Cached here */
16000 __u16 sum; /* sum of the name to speed searching */
16001
16002 - struct yaffs_DeviceStruct *myDev; /* The device I'm on */
16003 + struct yaffs_dev_s *my_dev; /* The device I'm on */
16004
16005 - struct ylist_head hashLink; /* list of objects in this hash bucket */
16006 + struct ylist_head hash_link; /* list of objects in this hash bucket */
16007
16008 - struct ylist_head hardLinks; /* all the equivalent hard linked objects */
16009 + struct ylist_head hard_links; /* all the equivalent hard linked objects */
16010
16011 /* directory structure stuff */
16012 /* also used for linking up the free list */
16013 - struct yaffs_ObjectStruct *parent;
16014 + struct yaffs_obj_s *parent;
16015 struct ylist_head siblings;
16016
16017 /* Where's my object header in NAND? */
16018 - int hdrChunk;
16019 + int hdr_chunk;
16020
16021 - int nDataChunks; /* Number of data chunks attached to the file. */
16022 + int n_data_chunks; /* Number of data chunks attached to the file. */
16023
16024 - __u32 objectId; /* the object id value */
16025 + __u32 obj_id; /* the object id value */
16026
16027 __u32 yst_mode;
16028
16029 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
16030 - YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
16031 -#endif
16032 -
16033 -#ifndef __KERNEL__
16034 - __u32 inUse;
16035 + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
16036 #endif
16037
16038 #ifdef CONFIG_YAFFS_WINCE
16039 @@ -470,53 +462,43 @@ struct yaffs_ObjectStruct {
16040
16041 __u32 yst_rdev;
16042
16043 -#ifdef __KERNEL__
16044 - struct inode *myInode;
16045 + void *my_inode;
16046
16047 -#endif
16048 + yaffs_obj_type variant_type;
16049
16050 - yaffs_ObjectType variantType;
16051 + yaffs_obj_variant variant;
16052
16053 - yaffs_ObjectVariant variant;
16054 -
16055 -};
16056 -
16057 -typedef struct yaffs_ObjectStruct yaffs_Object;
16058 -
16059 -struct yaffs_ObjectList_struct {
16060 - yaffs_Object *objects;
16061 - struct yaffs_ObjectList_struct *next;
16062 };
16063
16064 -typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
16065 +typedef struct yaffs_obj_s yaffs_obj_t;
16066
16067 typedef struct {
16068 struct ylist_head list;
16069 int count;
16070 -} yaffs_ObjectBucket;
16071 +} yaffs_obj_bucket;
16072
16073
16074 -/* yaffs_CheckpointObject holds the definition of an object as dumped
16075 +/* yaffs_checkpt_obj_t holds the definition of an object as dumped
16076 * by checkpointing.
16077 */
16078
16079 typedef struct {
16080 - int structType;
16081 - __u32 objectId;
16082 - __u32 parentId;
16083 - int hdrChunk;
16084 - yaffs_ObjectType variantType:3;
16085 + int struct_type;
16086 + __u32 obj_id;
16087 + __u32 parent_id;
16088 + int hdr_chunk;
16089 + yaffs_obj_type variant_type:3;
16090 __u8 deleted:1;
16091 - __u8 softDeleted:1;
16092 + __u8 soft_del:1;
16093 __u8 unlinked:1;
16094 __u8 fake:1;
16095 - __u8 renameAllowed:1;
16096 - __u8 unlinkAllowed:1;
16097 + __u8 rename_allowed:1;
16098 + __u8 unlink_allowed:1;
16099 __u8 serial;
16100
16101 - int nDataChunks;
16102 - __u32 fileSizeOrEquivalentObjectId;
16103 -} yaffs_CheckpointObject;
16104 + int n_data_chunks;
16105 + __u32 size_or_equiv_obj;
16106 +} yaffs_checkpt_obj_t;
16107
16108 /*--------------------- Temporary buffers ----------------
16109 *
16110 @@ -526,379 +508,462 @@ typedef struct {
16111 typedef struct {
16112 __u8 *buffer;
16113 int line; /* track from whence this buffer was allocated */
16114 - int maxLine;
16115 -} yaffs_TempBuffer;
16116 + int max_line;
16117 +} yaffs_buffer_t;
16118
16119 /*----------------- Device ---------------------------------*/
16120
16121 -struct yaffs_DeviceStruct {
16122 - struct ylist_head devList;
16123 - const char *name;
16124 -
16125 - /* Entry parameters set up way early. Yaffs sets up the rest.*/
16126 - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
16127 - int nChunksPerBlock; /* does not need to be a power of 2 */
16128 - int spareBytesPerChunk; /* spare area size */
16129 - int startBlock; /* Start block we're allowed to use */
16130 - int endBlock; /* End block we're allowed to use */
16131 - int nReservedBlocks; /* We want this tuneable so that we can reduce */
16132 - /* reserved blocks on NOR and RAM. */
16133 -
16134
16135 - /* Stuff used by the shared space checkpointing mechanism */
16136 - /* If this value is zero, then this mechanism is disabled */
16137 +struct yaffs_param_s {
16138 + const YCHAR *name;
16139
16140 -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
16141 + /*
16142 + * Entry parameters set up way early. Yaffs sets up the rest.
16143 + * The structure should be zeroed out before use so that unused
16144 + * and defualt values are zero.
16145 + */
16146 +
16147 + int inband_tags; /* Use unband tags */
16148 + __u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */
16149 + int chunks_per_block; /* does not need to be a power of 2 */
16150 + int spare_bytes_per_chunk; /* spare area size */
16151 + int start_block; /* Start block we're allowed to use */
16152 + int end_block; /* End block we're allowed to use */
16153 + int n_reserved_blocks; /* We want this tuneable so that we can reduce */
16154 + /* reserved blocks on NOR and RAM. */
16155
16156
16157 - int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
16158 - * the number of short op caches (don't use too many)
16159 + int n_caches; /* If <= 0, then short op caching is disabled, else
16160 + * the number of short op caches (don't use too many).
16161 + * 10 to 20 is a good bet.
16162 */
16163 + int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
16164 + int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
16165
16166 - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
16167 + int is_yaffs2; /* Use yaffs2 mode on this device */
16168
16169 - int useNANDECC; /* Flag to decide whether or not to use NANDECC */
16170 + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
16171
16172 - void *genericDevice; /* Pointer to device context
16173 - * On an mtd this holds the mtd pointer.
16174 - */
16175 - void *superBlock;
16176 + int refresh_period; /* How often we should check to do a block refresh */
16177 +
16178 + /* Checkpoint control. Can be set before or after initialisation */
16179 + __u8 skip_checkpt_rd;
16180 + __u8 skip_checkpt_wr;
16181 +
16182 + int enable_xattr; /* Enable xattribs */
16183
16184 /* NAND access functions (Must be set before calling YAFFS)*/
16185
16186 - int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,
16187 - int chunkInNAND, const __u8 *data,
16188 - const yaffs_Spare *spare);
16189 - int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev,
16190 - int chunkInNAND, __u8 *data,
16191 - yaffs_Spare *spare);
16192 - int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev,
16193 - int blockInNAND);
16194 - int (*initialiseNAND) (struct yaffs_DeviceStruct *dev);
16195 - int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev);
16196 + int (*write_chunk_fn) (struct yaffs_dev_s *dev,
16197 + int nand_chunk, const __u8 *data,
16198 + const yaffs_spare *spare);
16199 + int (*read_chunk_fn) (struct yaffs_dev_s *dev,
16200 + int nand_chunk, __u8 *data,
16201 + yaffs_spare *spare);
16202 + int (*erase_fn) (struct yaffs_dev_s *dev,
16203 + int flash_block);
16204 + int (*initialise_flash_fn) (struct yaffs_dev_s *dev);
16205 + int (*deinitialise_flash_fn) (struct yaffs_dev_s *dev);
16206
16207 #ifdef CONFIG_YAFFS_YAFFS2
16208 - int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev,
16209 - int chunkInNAND, const __u8 *data,
16210 - const yaffs_ExtendedTags *tags);
16211 - int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev,
16212 - int chunkInNAND, __u8 *data,
16213 - yaffs_ExtendedTags *tags);
16214 - int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo);
16215 - int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo,
16216 - yaffs_BlockState *state, __u32 *sequenceNumber);
16217 -#endif
16218 -
16219 - int isYaffs2;
16220 -
16221 - /* The removeObjectCallback function must be supplied by OS flavours that
16222 - * need it. The Linux kernel does not use this, but yaffs direct does use
16223 - * it to implement the faster readdir
16224 + int (*write_chunk_tags_fn) (struct yaffs_dev_s *dev,
16225 + int nand_chunk, const __u8 *data,
16226 + const yaffs_ext_tags *tags);
16227 + int (*read_chunk_tags_fn) (struct yaffs_dev_s *dev,
16228 + int nand_chunk, __u8 *data,
16229 + yaffs_ext_tags *tags);
16230 + int (*bad_block_fn) (struct yaffs_dev_s *dev, int block_no);
16231 + int (*query_block_fn) (struct yaffs_dev_s *dev, int block_no,
16232 + yaffs_block_state_t *state, __u32 *seq_number);
16233 +#endif
16234 +
16235 + /* The remove_obj_fn function must be supplied by OS flavours that
16236 + * need it.
16237 + * yaffs direct uses it to implement the faster readdir.
16238 + * Linux uses it to protect the directory during unlocking.
16239 */
16240 - void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
16241 + void (*remove_obj_fn)(struct yaffs_obj_s *obj);
16242
16243 - /* Callback to mark the superblock dirsty */
16244 - void (*markSuperBlockDirty)(void *superblock);
16245 + /* Callback to mark the superblock dirty */
16246 + void (*sb_dirty_fn)(struct yaffs_dev_s *dev);
16247 +
16248 + /* Callback to control garbage collection. */
16249 + unsigned (*gc_control)(struct yaffs_dev_s *dev);
16250 +
16251 + /* Debug control flags. Don't use unless you know what you're doing */
16252 + int use_header_file_size; /* Flag to determine if we should use file sizes from the header */
16253 + int disable_lazy_load; /* Disable lazy loading on this device */
16254 + int wide_tnodes_disabled; /* Set to disable wide tnodes */
16255 + int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */
16256 +
16257 + int defered_dir_update; /* Set to defer directory updates */
16258
16259 - int wideTnodesDisabled; /* Set to disable wide tnodes */
16260 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
16261 + int auto_unicode;
16262 +#endif
16263 + int always_check_erased; /* Force chunk erased check always on */
16264 +};
16265
16266 - YCHAR *pathDividers; /* String of legal path dividers */
16267 +typedef struct yaffs_param_s yaffs_param_t;
16268
16269 +struct yaffs_dev_s {
16270 + struct yaffs_param_s param;
16271
16272 - /* End of stuff that must be set before initialisation. */
16273 + /* Context storage. Holds extra OS specific data for this device */
16274
16275 - /* Checkpoint control. Can be set before or after initialisation */
16276 - __u8 skipCheckpointRead;
16277 - __u8 skipCheckpointWrite;
16278 + void *os_context;
16279 + void *driver_context;
16280 +
16281 + struct ylist_head dev_list;
16282
16283 /* Runtime parameters. Set up by YAFFS. */
16284 + int data_bytes_per_chunk;
16285
16286 - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
16287 - __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
16288 + /* Non-wide tnode stuff */
16289 + __u16 chunk_grp_bits; /* Number of bits that need to be resolved if
16290 + * the tnodes are not wide enough.
16291 + */
16292 + __u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
16293
16294 /* Stuff to support wide tnodes */
16295 - __u32 tnodeWidth;
16296 - __u32 tnodeMask;
16297 + __u32 tnode_width;
16298 + __u32 tnode_mask;
16299 + __u32 tnode_size;
16300
16301 /* Stuff for figuring out file offset to chunk conversions */
16302 - __u32 chunkShift; /* Shift value */
16303 - __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
16304 - __u32 chunkMask; /* Mask to use for power-of-2 case */
16305 -
16306 - /* Stuff to handle inband tags */
16307 - int inbandTags;
16308 - __u32 totalBytesPerChunk;
16309 -
16310 -#ifdef __KERNEL__
16311 -
16312 - struct semaphore sem; /* Semaphore for waiting on erasure.*/
16313 - struct semaphore grossLock; /* Gross locking semaphore */
16314 - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
16315 - * at compile time so we have to allocate it.
16316 - */
16317 - void (*putSuperFunc) (struct super_block *sb);
16318 -#endif
16319 + __u32 chunk_shift; /* Shift value */
16320 + __u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */
16321 + __u32 chunk_mask; /* Mask to use for power-of-2 case */
16322
16323 - int isMounted;
16324
16325 - int isCheckpointed;
16326 +
16327 + int is_mounted;
16328 + int read_only;
16329 + int is_checkpointed;
16330
16331
16332 /* Stuff to support block offsetting to support start block zero */
16333 - int internalStartBlock;
16334 - int internalEndBlock;
16335 - int blockOffset;
16336 - int chunkOffset;
16337 + int internal_start_block;
16338 + int internal_end_block;
16339 + int block_offset;
16340 + int chunk_offset;
16341
16342
16343 /* Runtime checkpointing stuff */
16344 - int checkpointPageSequence; /* running sequence number of checkpoint pages */
16345 - int checkpointByteCount;
16346 - int checkpointByteOffset;
16347 - __u8 *checkpointBuffer;
16348 - int checkpointOpenForWrite;
16349 - int blocksInCheckpoint;
16350 - int checkpointCurrentChunk;
16351 - int checkpointCurrentBlock;
16352 - int checkpointNextBlock;
16353 - int *checkpointBlockList;
16354 - int checkpointMaxBlocks;
16355 - __u32 checkpointSum;
16356 - __u32 checkpointXor;
16357 + int checkpt_page_seq; /* running sequence number of checkpoint pages */
16358 + int checkpt_byte_count;
16359 + int checkpt_byte_offs;
16360 + __u8 *checkpt_buffer;
16361 + int checkpt_open_write;
16362 + int blocks_in_checkpt;
16363 + int checkpt_cur_chunk;
16364 + int checkpt_cur_block;
16365 + int checkpt_next_block;
16366 + int *checkpt_block_list;
16367 + int checkpt_max_blocks;
16368 + __u32 checkpt_sum;
16369 + __u32 checkpt_xor;
16370
16371 - int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
16372 + int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */
16373
16374 /* Block Info */
16375 - yaffs_BlockInfo *blockInfo;
16376 - __u8 *chunkBits; /* bitmap of chunks in use */
16377 - unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
16378 - unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
16379 - int chunkBitmapStride; /* Number of bytes of chunkBits per block.
16380 - * Must be consistent with nChunksPerBlock.
16381 + yaffs_block_info_t *block_info;
16382 + __u8 *chunk_bits; /* bitmap of chunks in use */
16383 + unsigned block_info_alt:1; /* was allocated using alternative strategy */
16384 + unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */
16385 + int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
16386 + * Must be consistent with chunks_per_block.
16387 */
16388
16389 - int nErasedBlocks;
16390 - int allocationBlock; /* Current block being allocated off */
16391 - __u32 allocationPage;
16392 - int allocationBlockFinder; /* Used to search for next allocation block */
16393 -
16394 - /* Runtime state */
16395 - int nTnodesCreated;
16396 - yaffs_Tnode *freeTnodes;
16397 - int nFreeTnodes;
16398 - yaffs_TnodeList *allocatedTnodeList;
16399 -
16400 - int isDoingGC;
16401 - int gcBlock;
16402 - int gcChunk;
16403 -
16404 - int nObjectsCreated;
16405 - yaffs_Object *freeObjects;
16406 - int nFreeObjects;
16407 -
16408 - int nHardLinks;
16409 -
16410 - yaffs_ObjectList *allocatedObjectList;
16411 -
16412 - yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
16413 -
16414 - int nFreeChunks;
16415 -
16416 - int currentDirtyChecker; /* Used to find current dirtiest block */
16417 -
16418 - __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
16419 - int nonAggressiveSkip; /* GC state/mode */
16420 -
16421 - /* Statistcs */
16422 - int nPageWrites;
16423 - int nPageReads;
16424 - int nBlockErasures;
16425 - int nErasureFailures;
16426 - int nGCCopies;
16427 - int garbageCollections;
16428 - int passiveGarbageCollections;
16429 - int nRetriedWrites;
16430 - int nRetiredBlocks;
16431 - int eccFixed;
16432 - int eccUnfixed;
16433 - int tagsEccFixed;
16434 - int tagsEccUnfixed;
16435 - int nDeletions;
16436 - int nUnmarkedDeletions;
16437 -
16438 - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
16439 + int n_erased_blocks;
16440 + int alloc_block; /* Current block being allocated off */
16441 + __u32 alloc_page;
16442 + int alloc_block_finder; /* Used to search for next allocation block */
16443 +
16444 + /* Object and Tnode memory management */
16445 + void *allocator;
16446 + int n_obj;
16447 + int n_tnodes;
16448 +
16449 + int n_hardlinks;
16450 +
16451 + yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
16452 + __u32 bucket_finder;
16453 +
16454 + int n_free_chunks;
16455 +
16456 + /* Garbage collection control */
16457 + __u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
16458 + __u32 n_clean_ups;
16459 +
16460 + unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */
16461 + unsigned gc_disable;
16462 + unsigned gc_block_finder;
16463 + unsigned gc_dirtiest;
16464 + unsigned gc_pages_in_use;
16465 + unsigned gc_not_done;
16466 + unsigned gc_block;
16467 + unsigned gc_chunk;
16468 + unsigned gc_skip;
16469
16470 /* Special directories */
16471 - yaffs_Object *rootDir;
16472 - yaffs_Object *lostNFoundDir;
16473 + yaffs_obj_t *root_dir;
16474 + yaffs_obj_t *lost_n_found;
16475
16476 /* Buffer areas for storing data to recover from write failures TODO
16477 - * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
16478 - * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
16479 + * __u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
16480 + * yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK];
16481 */
16482
16483 - int bufferedBlock; /* Which block is buffered here? */
16484 - int doingBufferedBlockRewrite;
16485 -
16486 - yaffs_ChunkCache *srCache;
16487 - int srLastUse;
16488 + int buffered_block; /* Which block is buffered here? */
16489 + int doing_buffered_block_rewrite;
16490
16491 - int cacheHits;
16492 + yaffs_cache_t *cache;
16493 + int cache_last_use;
16494
16495 /* Stuff for background deletion and unlinked files.*/
16496 - yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
16497 - yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
16498 - yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
16499 - int nDeletedFiles; /* Count of files awaiting deletion;*/
16500 - int nUnlinkedFiles; /* Count of unlinked files. */
16501 - int nBackgroundDeletions; /* Count of background deletions. */
16502 -
16503 + yaffs_obj_t *unlinked_dir; /* Directory where unlinked and deleted files live. */
16504 + yaffs_obj_t *del_dir; /* Directory where deleted objects are sent to disappear. */
16505 + yaffs_obj_t *unlinked_deletion; /* Current file being background deleted.*/
16506 + int n_deleted_files; /* Count of files awaiting deletion;*/
16507 + int n_unlinked_files; /* Count of unlinked files. */
16508 + int n_bg_deletions; /* Count of background deletions. */
16509
16510 /* Temporary buffer management */
16511 - yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
16512 - int maxTemp;
16513 - int tempInUse;
16514 - int unmanagedTempAllocations;
16515 - int unmanagedTempDeallocations;
16516 + yaffs_buffer_t temp_buffer[YAFFS_N_TEMP_BUFFERS];
16517 + int max_temp;
16518 + int temp_in_use;
16519 + int unmanaged_buffer_allocs;
16520 + int unmanaged_buffer_deallocs;
16521
16522 /* yaffs2 runtime stuff */
16523 - unsigned sequenceNumber; /* Sequence number of currently allocating block */
16524 - unsigned oldestDirtySequence;
16525 + unsigned seq_number; /* Sequence number of currently allocating block */
16526 + unsigned oldest_dirty_seq;
16527 + unsigned oldest_dirty_block;
16528 +
16529 + /* Block refreshing */
16530 + int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */
16531 +
16532 + /* Dirty directory handling */
16533 + struct ylist_head dirty_dirs; /* List of dirty directories */
16534 +
16535 +
16536 + /* Statistcs */
16537 + __u32 n_page_writes;
16538 + __u32 n_page_reads;
16539 + __u32 n_erasures;
16540 + __u32 n_erase_failures;
16541 + __u32 n_gc_copies;
16542 + __u32 all_gcs;
16543 + __u32 passive_gc_count;
16544 + __u32 oldest_dirty_gc_count;
16545 + __u32 n_gc_blocks;
16546 + __u32 bg_gcs;
16547 + __u32 n_retired_writes;
16548 + __u32 n_retired_blocks;
16549 + __u32 n_ecc_fixed;
16550 + __u32 n_ecc_unfixed;
16551 + __u32 n_tags_ecc_fixed;
16552 + __u32 n_tags_ecc_unfixed;
16553 + __u32 n_deletions;
16554 + __u32 n_unmarked_deletions;
16555 + __u32 refresh_count;
16556 + __u32 cache_hits;
16557
16558 };
16559
16560 -typedef struct yaffs_DeviceStruct yaffs_Device;
16561 +typedef struct yaffs_dev_s yaffs_dev_t;
16562
16563 /* The static layout of block usage etc is stored in the super block header */
16564 typedef struct {
16565 int StructType;
16566 int version;
16567 - int checkpointStartBlock;
16568 - int checkpointEndBlock;
16569 - int startBlock;
16570 - int endBlock;
16571 + int checkpt_start_block;
16572 + int checkpt_end_block;
16573 + int start_block;
16574 + int end_block;
16575 int rfu[100];
16576 -} yaffs_SuperBlockHeader;
16577 +} yaffs_sb_header;
16578
16579 /* The CheckpointDevice structure holds the device information that changes at runtime and
16580 * must be preserved over unmount/mount cycles.
16581 */
16582 typedef struct {
16583 - int structType;
16584 - int nErasedBlocks;
16585 - int allocationBlock; /* Current block being allocated off */
16586 - __u32 allocationPage;
16587 - int nFreeChunks;
16588 -
16589 - int nDeletedFiles; /* Count of files awaiting deletion;*/
16590 - int nUnlinkedFiles; /* Count of unlinked files. */
16591 - int nBackgroundDeletions; /* Count of background deletions. */
16592 + int struct_type;
16593 + int n_erased_blocks;
16594 + int alloc_block; /* Current block being allocated off */
16595 + __u32 alloc_page;
16596 + int n_free_chunks;
16597 +
16598 + int n_deleted_files; /* Count of files awaiting deletion;*/
16599 + int n_unlinked_files; /* Count of unlinked files. */
16600 + int n_bg_deletions; /* Count of background deletions. */
16601
16602 /* yaffs2 runtime stuff */
16603 - unsigned sequenceNumber; /* Sequence number of currently allocating block */
16604 - unsigned oldestDirtySequence;
16605 + unsigned seq_number; /* Sequence number of currently allocating block */
16606
16607 -} yaffs_CheckpointDevice;
16608 +} yaffs_checkpt_dev_t;
16609
16610
16611 typedef struct {
16612 - int structType;
16613 + int struct_type;
16614 __u32 magic;
16615 __u32 version;
16616 __u32 head;
16617 -} yaffs_CheckpointValidity;
16618 +} yaffs_checkpt_validty_t;
16619 +
16620 +
16621 +struct yaffs_shadow_fixer_s {
16622 + int obj_id;
16623 + int shadowed_id;
16624 + struct yaffs_shadow_fixer_s *next;
16625 +};
16626 +
16627 +/* Structure for doing xattr modifications */
16628 +typedef struct {
16629 + int set; /* If 0 then this is a deletion */
16630 + const YCHAR *name;
16631 + const void *data;
16632 + int size;
16633 + int flags;
16634 + int result;
16635 +}yaffs_xattr_mod;
16636
16637
16638 /*----------------------- YAFFS Functions -----------------------*/
16639
16640 -int yaffs_GutsInitialise(yaffs_Device *dev);
16641 -void yaffs_Deinitialise(yaffs_Device *dev);
16642 +int yaffs_guts_initialise(yaffs_dev_t *dev);
16643 +void yaffs_deinitialise(yaffs_dev_t *dev);
16644
16645 -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
16646 +int yaffs_get_n_free_chunks(yaffs_dev_t *dev);
16647
16648 -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
16649 - yaffs_Object *newDir, const YCHAR *newName);
16650 +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
16651 + yaffs_obj_t *new_dir, const YCHAR *new_name);
16652
16653 -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
16654 -int yaffs_DeleteObject(yaffs_Object *obj);
16655 +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name);
16656 +int yaffs_del_obj(yaffs_obj_t *obj);
16657
16658 -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize);
16659 -int yaffs_GetObjectFileLength(yaffs_Object *obj);
16660 -int yaffs_GetObjectInode(yaffs_Object *obj);
16661 -unsigned yaffs_GetObjectType(yaffs_Object *obj);
16662 -int yaffs_GetObjectLinkCount(yaffs_Object *obj);
16663 +int yaffs_get_obj_name(yaffs_obj_t *obj, YCHAR *name, int buffer_size);
16664 +int yaffs_get_obj_length(yaffs_obj_t *obj);
16665 +int yaffs_get_obj_inode(yaffs_obj_t *obj);
16666 +unsigned yaffs_get_obj_type(yaffs_obj_t *obj);
16667 +int yaffs_get_obj_link_count(yaffs_obj_t *obj);
16668
16669 -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
16670 -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
16671 +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr);
16672 +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr);
16673
16674 /* File operations */
16675 -int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset,
16676 - int nBytes);
16677 -int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset,
16678 - int nBytes, int writeThrough);
16679 -int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize);
16680 +int yaffs_file_rd(yaffs_obj_t *obj, __u8 *buffer, loff_t offset,
16681 + int n_bytes);
16682 +int yaffs_wr_file(yaffs_obj_t *obj, const __u8 *buffer, loff_t offset,
16683 + int n_bytes, int write_trhrough);
16684 +int yaffs_resize_file(yaffs_obj_t *obj, loff_t new_size);
16685
16686 -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
16687 +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
16688 __u32 mode, __u32 uid, __u32 gid);
16689 -int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
16690 +
16691 +int yaffs_flush_file(yaffs_obj_t *obj, int update_time, int data_sync);
16692
16693 /* Flushing and checkpointing */
16694 -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
16695 +void yaffs_flush_whole_cache(yaffs_dev_t *dev);
16696
16697 -int yaffs_CheckpointSave(yaffs_Device *dev);
16698 -int yaffs_CheckpointRestore(yaffs_Device *dev);
16699 +int yaffs_checkpoint_save(yaffs_dev_t *dev);
16700 +int yaffs_checkpoint_restore(yaffs_dev_t *dev);
16701
16702 /* Directory operations */
16703 -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
16704 +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
16705 __u32 mode, __u32 uid, __u32 gid);
16706 -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name);
16707 -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
16708 - int (*fn) (yaffs_Object *));
16709 +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *the_dir, const YCHAR *name);
16710 +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
16711 + int (*fn) (yaffs_obj_t *));
16712
16713 -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number);
16714 +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number);
16715
16716 /* Link operations */
16717 -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
16718 - yaffs_Object *equivalentObject);
16719 +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
16720 + yaffs_obj_t *equiv_obj);
16721
16722 -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
16723 +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj);
16724
16725 /* Symlink operations */
16726 -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
16727 +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
16728 __u32 mode, __u32 uid, __u32 gid,
16729 const YCHAR *alias);
16730 -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
16731 +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj);
16732
16733 /* Special inodes (fifos, sockets and devices) */
16734 -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
16735 +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
16736 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
16737
16738 +
16739 +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags);
16740 +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size);
16741 +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size);
16742 +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name);
16743 +
16744 /* Special directories */
16745 -yaffs_Object *yaffs_Root(yaffs_Device *dev);
16746 -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
16747 +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev);
16748 +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev);
16749
16750 #ifdef CONFIG_YAFFS_WINCE
16751 /* CONFIG_YAFFS_WINCE special stuff */
16752 -void yfsd_WinFileTimeNow(__u32 target[2]);
16753 +void yfsd_win_file_time_now(__u32 target[2]);
16754 #endif
16755
16756 -#ifdef __KERNEL__
16757 +void yaffs_handle_defered_free(yaffs_obj_t *obj);
16758
16759 -void yaffs_HandleDeferedFree(yaffs_Object *obj);
16760 -#endif
16761 +void yaffs_update_dirty_dirs(yaffs_dev_t *dev);
16762 +
16763 +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency);
16764
16765 /* Debug dump */
16766 -int yaffs_DumpObject(yaffs_Object *obj);
16767 +int yaffs_dump_obj(yaffs_obj_t *obj);
16768
16769 -void yaffs_GutsTest(yaffs_Device *dev);
16770 +void yaffs_guts_test(yaffs_dev_t *dev);
16771
16772 -/* A few useful functions */
16773 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
16774 -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
16775 -int yaffs_CheckFF(__u8 *buffer, int nBytes);
16776 -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
16777 +/* A few useful functions to be used within the core files*/
16778 +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn);
16779 +int yaffs_check_ff(__u8 *buffer, int n_bytes);
16780 +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi);
16781 +
16782 +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no);
16783 +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer, int line_no);
16784 +
16785 +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
16786 + int number,
16787 + yaffs_obj_type type);
16788 +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
16789 + int nand_chunk, int in_scan);
16790 +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name);
16791 +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh);
16792 +void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
16793 + yaffs_obj_t *obj);
16794 +YCHAR *yaffs_clone_str(const YCHAR *str);
16795 +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list);
16796 +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no);
16797 +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name,
16798 + int force, int is_shrink, int shadows,
16799 + yaffs_xattr_mod *xop);
16800 +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
16801 + int backward_scanning);
16802 +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks);
16803 +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev);
16804 +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
16805 + yaffs_file_s *file_struct,
16806 + __u32 chunk_id,
16807 + yaffs_tnode_t *passed_tn);
16808 +
16809 +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
16810 + int n_bytes, int write_trhrough);
16811 +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size);
16812 +void yaffs_skip_rest_of_block(yaffs_dev_t *dev);
16813 +
16814 +int yaffs_count_free_chunks(yaffs_dev_t *dev);
16815 +
16816 +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
16817 + yaffs_file_s *file_struct,
16818 + __u32 chunk_id);
16819
16820 -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
16821 -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
16822 +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos);
16823
16824 #endif
16825 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffsinterface.h linux-2.6.36-rc8.new/fs/yaffs2/yaffsinterface.h
16826 --- linux-2.6.36-rc8/fs/yaffs2/yaffsinterface.h 2010-10-20 13:17:58.955000294 +0300
16827 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffsinterface.h 2010-10-20 13:28:16.061000294 +0300
16828 @@ -1,7 +1,7 @@
16829 /*
16830 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16831 *
16832 - * Copyright (C) 2002-2007 Aleph One Ltd.
16833 + * Copyright (C) 2002-2010 Aleph One Ltd.
16834 * for Toby Churchill Ltd and Brightstar Engineering
16835 *
16836 * Created by Charles Manning <charles@aleph1.co.uk>
16837 @@ -16,6 +16,6 @@
16838 #ifndef __YAFFSINTERFACE_H__
16839 #define __YAFFSINTERFACE_H__
16840
16841 -int yaffs_Initialise(unsigned nBlocks);
16842 +int yaffs_initialise(unsigned nBlocks);
16843
16844 #endif
16845 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_linux_allocator.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux_allocator.c
16846 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_linux_allocator.c 1970-01-01 02:00:00.000000000 +0200
16847 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux_allocator.c 2010-10-20 13:28:16.028000294 +0300
16848 @@ -0,0 +1,200 @@
16849 +/*
16850 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16851 + *
16852 + * Copyright (C) 2002-2010 Aleph One Ltd.
16853 + * for Toby Churchill Ltd and Brightstar Engineering
16854 + *
16855 + * Created by Charles Manning <charles@aleph1.co.uk>
16856 + *
16857 + * This program is free software; you can redistribute it and/or modify
16858 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16859 + * published by the Free Software Foundation.
16860 + *
16861 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16862 + *
16863 + * Note: Tis code is currently unused. Being checked in in case it becomes useful.
16864 + */
16865 +
16866 +
16867 +#include "yaffs_allocator.h"
16868 +#include "yaffs_guts.h"
16869 +#include "yaffs_trace.h"
16870 +#include "yportenv.h"
16871 +#include "yaffs_linux.h"
16872 +/*
16873 + * Start out with the same allocator as yaffs direct.
16874 + * Todo: Change to Linux slab allocator.
16875 + */
16876 +
16877 +
16878 +
16879 +#define NAMELEN 20
16880 +struct yaffs_AllocatorStruct {
16881 + char tnode_name[NAMELEN+1];
16882 + char object_name[NAMELEN+1];
16883 + struct kmem_cache *tnode_cache;
16884 + struct kmem_cache *object_cache;
16885 +};
16886 +
16887 +typedef struct yaffs_AllocatorStruct yaffs_Allocator;
16888 +
16889 +int mount_id;
16890 +
16891 +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
16892 +{
16893 + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
16894 +
16895 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
16896 +
16897 + if(allocator){
16898 + if(allocator->tnode_cache){
16899 + kmem_cache_destroy(allocator->tnode_cache);
16900 + allocator->tnode_cache = NULL;
16901 + } else {
16902 + T(YAFFS_TRACE_ALWAYS,
16903 + (TSTR("NULL tnode cache\n")));
16904 + YBUG();
16905 + }
16906 +
16907 + if(allocator->object_cache){
16908 + kmem_cache_destroy(allocator->object_cache);
16909 + allocator->object_cache = NULL;
16910 + } else {
16911 + T(YAFFS_TRACE_ALWAYS,
16912 + (TSTR("NULL object cache\n")));
16913 + YBUG();
16914 + }
16915 +
16916 + YFREE(allocator);
16917 +
16918 + } else {
16919 + T(YAFFS_TRACE_ALWAYS,
16920 + (TSTR("Deinitialising NULL allocator\n")));
16921 + YBUG();
16922 + }
16923 + dev->allocator = NULL;
16924 +}
16925 +
16926 +
16927 +static void fake_ctor0(void *data){data = data;}
16928 +static void fake_ctor1(void *data){data = data;}
16929 +static void fake_ctor2(void *data){data = data;}
16930 +static void fake_ctor3(void *data){data = data;}
16931 +static void fake_ctor4(void *data){data = data;}
16932 +static void fake_ctor5(void *data){data = data;}
16933 +static void fake_ctor6(void *data){data = data;}
16934 +static void fake_ctor7(void *data){data = data;}
16935 +static void fake_ctor8(void *data){data = data;}
16936 +static void fake_ctor9(void *data){data = data;}
16937 +
16938 +static void (*fake_ctor_list[10]) (void *) = {
16939 + fake_ctor0,
16940 + fake_ctor1,
16941 + fake_ctor2,
16942 + fake_ctor3,
16943 + fake_ctor4,
16944 + fake_ctor5,
16945 + fake_ctor6,
16946 + fake_ctor7,
16947 + fake_ctor8,
16948 + fake_ctor9,
16949 +};
16950 +
16951 +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
16952 +{
16953 + yaffs_Allocator *allocator;
16954 + unsigned mount_id = yaffs_dev_to_lc(dev)->mount_id;
16955 +
16956 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
16957 +
16958 + if(dev->allocator)
16959 + YBUG();
16960 + else if(mount_id >= 10){
16961 + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
16962 + } else {
16963 + allocator = YMALLOC(sizeof(yaffs_Allocator));
16964 + memset(allocator,0,sizeof(yaffs_Allocator));
16965 + dev->allocator = allocator;
16966 +
16967 + if(!dev->allocator){
16968 + T(YAFFS_TRACE_ALWAYS,
16969 + (TSTR("yaffs allocator creation failed\n")));
16970 + YBUG();
16971 + return;
16972 +
16973 + }
16974 +
16975 + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
16976 + sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
16977 +
16978 + allocator->tnode_cache =
16979 + kmem_cache_create(allocator->tnode_name,
16980 + dev->tnode_size,
16981 + 0, 0,
16982 + fake_ctor_list[mount_id]);
16983 + if(allocator->tnode_cache)
16984 + T(YAFFS_TRACE_ALLOCATE,
16985 + (TSTR("tnode cache \"%s\" %p\n"),
16986 + allocator->tnode_name,allocator->tnode_cache));
16987 + else {
16988 + T(YAFFS_TRACE_ALWAYS,
16989 + (TSTR("yaffs cache creation failed\n")));
16990 + YBUG();
16991 + }
16992 +
16993 +
16994 + allocator->object_cache =
16995 + kmem_cache_create(allocator->object_name,
16996 + sizeof(yaffs_obj_t),
16997 + 0, 0,
16998 + fake_ctor_list[mount_id]);
16999 +
17000 + if(allocator->object_cache)
17001 + T(YAFFS_TRACE_ALLOCATE,
17002 + (TSTR("object cache \"%s\" %p\n"),
17003 + allocator->object_name,allocator->object_cache));
17004 +
17005 + else {
17006 + T(YAFFS_TRACE_ALWAYS,
17007 + (TSTR("yaffs cache creation failed\n")));
17008 + YBUG();
17009 + }
17010 + }
17011 +}
17012 +
17013 +
17014 +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
17015 +{
17016 + yaffs_Allocator *allocator = dev->allocator;
17017 + if(!allocator || !allocator->tnode_cache){
17018 + YBUG();
17019 + return NULL;
17020 + }
17021 + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
17022 +}
17023 +
17024 +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
17025 +{
17026 + yaffs_Allocator *allocator = dev->allocator;
17027 + kmem_cache_free(allocator->tnode_cache,tn);
17028 +}
17029 +
17030 +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
17031 +{
17032 + yaffs_Allocator *allocator = dev->allocator;
17033 + if(!allocator){
17034 + YBUG();
17035 + return NULL;
17036 + }
17037 + if(!allocator->object_cache){
17038 + YBUG();
17039 + return NULL;
17040 + }
17041 + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
17042 +}
17043 +
17044 +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
17045 +{
17046 + yaffs_Allocator *allocator = dev->allocator;
17047 + kmem_cache_free(allocator->object_cache,obj);
17048 +}
17049 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_linux.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux.h
17050 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_linux.h 1970-01-01 02:00:00.000000000 +0200
17051 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_linux.h 2010-10-20 13:28:16.061000294 +0300
17052 @@ -0,0 +1,43 @@
17053 +/*
17054 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17055 + *
17056 + * Copyright (C) 2002-2010 Aleph One Ltd.
17057 + * for Toby Churchill Ltd and Brightstar Engineering
17058 + *
17059 + * Created by Charles Manning <charles@aleph1.co.uk>
17060 + *
17061 + * This program is free software; you can redistribute it and/or modify
17062 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17063 + * published by the Free Software Foundation.
17064 + *
17065 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17066 + */
17067 +
17068 +#ifndef __YAFFS_LINUX_H__
17069 +#define __YAFFS_LINUX_H__
17070 +
17071 +#include "devextras.h"
17072 +#include "yportenv.h"
17073 +
17074 +struct yaffs_LinuxContext {
17075 + struct ylist_head contextList; /* List of these we have mounted */
17076 + struct yaffs_dev_s *dev;
17077 + struct super_block * superBlock;
17078 + struct task_struct *bgThread; /* Background thread for this device */
17079 + int bgRunning;
17080 + struct semaphore grossLock; /* Gross locking semaphore */
17081 + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
17082 + * at compile time so we have to allocate it.
17083 + */
17084 + struct ylist_head searchContexts;
17085 + void (*putSuperFunc)(struct super_block *sb);
17086 +
17087 + struct task_struct *readdirProcess;
17088 + unsigned mount_id;
17089 +};
17090 +
17091 +#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
17092 +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
17093 +
17094 +#endif
17095 +
17096 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_list.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_list.h
17097 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_list.h 1970-01-01 02:00:00.000000000 +0200
17098 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_list.h 2010-10-20 13:28:16.062000294 +0300
17099 @@ -0,0 +1,127 @@
17100 +/*
17101 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
17102 + *
17103 + * Copyright (C) 2002-2010 Aleph One Ltd.
17104 + * for Toby Churchill Ltd and Brightstar Engineering
17105 + *
17106 + * Created by Charles Manning <charles@aleph1.co.uk>
17107 + *
17108 + * This program is free software; you can redistribute it and/or modify
17109 + * it under the terms of the GNU Lesser General Public License version 2.1 as
17110 + * published by the Free Software Foundation.
17111 + *
17112 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
17113 + */
17114 +
17115 +/*
17116 + * This file is just holds extra declarations of macros that would normally
17117 + * be providesd in the Linux kernel. These macros have been written from
17118 + * scratch but are functionally equivalent to the Linux ones.
17119 + *
17120 + */
17121 +
17122 +#ifndef __YAFFS_LIST_H__
17123 +#define __YAFFS_LIST_H__
17124 +
17125 +
17126 +#include "yportenv.h"
17127 +
17128 +/*
17129 + * This is a simple doubly linked list implementation that matches the
17130 + * way the Linux kernel doubly linked list implementation works.
17131 + */
17132 +
17133 +struct ylist_head {
17134 + struct ylist_head *next; /* next in chain */
17135 + struct ylist_head *prev; /* previous in chain */
17136 +};
17137 +
17138 +
17139 +/* Initialise a static list */
17140 +#define YLIST_HEAD(name) \
17141 +struct ylist_head name = { &(name), &(name)}
17142 +
17143 +
17144 +
17145 +/* Initialise a list head to an empty list */
17146 +#define YINIT_LIST_HEAD(p) \
17147 +do { \
17148 + (p)->next = (p);\
17149 + (p)->prev = (p); \
17150 +} while (0)
17151 +
17152 +
17153 +/* Add an element to a list */
17154 +static Y_INLINE void ylist_add(struct ylist_head *newEntry,
17155 + struct ylist_head *list)
17156 +{
17157 + struct ylist_head *listNext = list->next;
17158 +
17159 + list->next = newEntry;
17160 + newEntry->prev = list;
17161 + newEntry->next = listNext;
17162 + listNext->prev = newEntry;
17163 +
17164 +}
17165 +
17166 +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
17167 + struct ylist_head *list)
17168 +{
17169 + struct ylist_head *listPrev = list->prev;
17170 +
17171 + list->prev = newEntry;
17172 + newEntry->next = list;
17173 + newEntry->prev = listPrev;
17174 + listPrev->next = newEntry;
17175 +
17176 +}
17177 +
17178 +
17179 +/* Take an element out of its current list, with or without
17180 + * reinitialising the links.of the entry*/
17181 +static Y_INLINE void ylist_del(struct ylist_head *entry)
17182 +{
17183 + struct ylist_head *listNext = entry->next;
17184 + struct ylist_head *listPrev = entry->prev;
17185 +
17186 + listNext->prev = listPrev;
17187 + listPrev->next = listNext;
17188 +
17189 +}
17190 +
17191 +static Y_INLINE void ylist_del_init(struct ylist_head *entry)
17192 +{
17193 + ylist_del(entry);
17194 + entry->next = entry->prev = entry;
17195 +}
17196 +
17197 +
17198 +/* Test if the list is empty */
17199 +static Y_INLINE int ylist_empty(struct ylist_head *entry)
17200 +{
17201 + return (entry->next == entry);
17202 +}
17203 +
17204 +
17205 +/* ylist_entry takes a pointer to a list entry and offsets it to that
17206 + * we can find a pointer to the object it is embedded in.
17207 + */
17208 +
17209 +
17210 +#define ylist_entry(entry, type, member) \
17211 + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
17212 +
17213 +
17214 +/* ylist_for_each and list_for_each_safe iterate over lists.
17215 + * ylist_for_each_safe uses temporary storage to make the list delete safe
17216 + */
17217 +
17218 +#define ylist_for_each(itervar, list) \
17219 + for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
17220 +
17221 +#define ylist_for_each_safe(itervar, saveVar, list) \
17222 + for (itervar = (list)->next, saveVar = (list)->next->next; \
17223 + itervar != (list); itervar = saveVar, saveVar = saveVar->next)
17224 +
17225 +
17226 +#endif
17227 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.c
17228 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.c 2010-10-20 13:17:58.956000294 +0300
17229 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.c 2010-10-20 13:28:16.028000294 +0300
17230 @@ -2,7 +2,7 @@
17231 * YAFFS: Yet another FFS. A NAND-flash specific file system.
17232 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
17233 *
17234 - * Copyright (C) 2002 Aleph One Ltd.
17235 + * Copyright (C) 2002-2010 Aleph One Ltd.
17236 * for Toby Churchill Ltd and Brightstar Engineering
17237 *
17238 * This program is free software; you can redistribute it and/or modify
17239 @@ -18,15 +18,17 @@
17240 *
17241 * These functions are invoked via function pointers in yaffs_nand.c.
17242 * This replaces functionality provided by functions in yaffs_mtdif.c
17243 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
17244 + * and the yaffs_tags_tCompatability functions in yaffs_tagscompat.c that are
17245 * called in yaffs_mtdif.c when the function pointers are NULL.
17246 - * We assume the MTD layer is performing ECC (useNANDECC is true).
17247 + * We assume the MTD layer is performing ECC (use_nand_ecc is true).
17248 */
17249
17250 #include "yportenv.h"
17251 +#include "yaffs_trace.h"
17252 #include "yaffs_guts.h"
17253 #include "yaffs_packedtags1.h"
17254 -#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
17255 +#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
17256 +#include "yaffs_linux.h"
17257
17258 #include "linux/kernel.h"
17259 #include "linux/version.h"
17260 @@ -36,8 +38,6 @@
17261 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
17262 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
17263
17264 -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
17265 -
17266 #ifndef CONFIG_YAFFS_9BYTE_TAGS
17267 # define YTAG1_SIZE 8
17268 #else
17269 @@ -51,12 +51,12 @@ const char *yaffs_mtdif1_c_version = "$I
17270 * adjust 'oobfree' to match your existing Yaffs data.
17271 *
17272 * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
17273 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
17274 + * page_status byte (at NAND spare offset 4) scattered/gathered from/to
17275 * the 9th byte.
17276 *
17277 * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
17278 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
17279 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
17280 + * We have/need PackedTags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
17281 + * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
17282 * byte and B is the small-page bad-block indicator byte.
17283 */
17284 static struct nand_ecclayout nand_oob_16 = {
17285 @@ -88,42 +88,40 @@ static struct nand_ecclayout nand_oob_16
17286 * Any underlying MTD error results in YAFFS_FAIL.
17287 * Returns YAFFS_OK or YAFFS_FAIL.
17288 */
17289 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
17290 - int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
17291 +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev,
17292 + int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
17293 {
17294 - struct mtd_info *mtd = dev->genericDevice;
17295 - int chunkBytes = dev->nDataBytesPerChunk;
17296 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17297 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17298 + int chunkBytes = dev->data_bytes_per_chunk;
17299 + loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
17300 struct mtd_oob_ops ops;
17301 yaffs_PackedTags1 pt1;
17302 int retval;
17303
17304 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
17305 + /* we assume that PackedTags1 and yaffs_tags_t are compatible */
17306 compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
17307 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
17308 -
17309 - dev->nPageWrites++;
17310 + compile_time_assertion(sizeof(yaffs_tags_t) == 8);
17311
17312 yaffs_PackTags1(&pt1, etags);
17313 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
17314 + yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1);
17315
17316 /* When deleting a chunk, the upper layer provides only skeletal
17317 - * etags, one with chunkDeleted set. However, we need to update the
17318 + * etags, one with is_deleted set. However, we need to update the
17319 * tags, not erase them completely. So we use the NAND write property
17320 * that only zeroed-bits stick and set tag bytes to all-ones and
17321 * zero just the (not) deleted bit.
17322 */
17323 #ifndef CONFIG_YAFFS_9BYTE_TAGS
17324 - if (etags->chunkDeleted) {
17325 + if (etags->is_deleted) {
17326 memset(&pt1, 0xff, 8);
17327 /* clear delete status bit to indicate deleted */
17328 pt1.deleted = 0;
17329 }
17330 #else
17331 ((__u8 *)&pt1)[8] = 0xff;
17332 - if (etags->chunkDeleted) {
17333 + if (etags->is_deleted) {
17334 memset(&pt1, 0xff, 8);
17335 - /* zero pageStatus byte to indicate deleted */
17336 + /* zero page_status byte to indicate deleted */
17337 ((__u8 *)&pt1)[8] = 0;
17338 }
17339 #endif
17340 @@ -137,20 +135,20 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
17341
17342 retval = mtd->write_oob(mtd, addr, &ops);
17343 if (retval) {
17344 - yaffs_trace(YAFFS_TRACE_MTD,
17345 - "write_oob failed, chunk %d, mtd error %d\n",
17346 - chunkInNAND, retval);
17347 + T(YAFFS_TRACE_MTD,
17348 + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
17349 + nand_chunk, retval));
17350 }
17351 return retval ? YAFFS_FAIL : YAFFS_OK;
17352 }
17353
17354 -/* Return with empty ExtendedTags but add eccResult.
17355 +/* Return with empty ExtendedTags but add ecc_result.
17356 */
17357 -static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
17358 +static int rettags(yaffs_ext_tags *etags, int ecc_result, int retval)
17359 {
17360 if (etags) {
17361 memset(etags, 0, sizeof(*etags));
17362 - etags->eccResult = eccResult;
17363 + etags->ecc_result = ecc_result;
17364 }
17365 return retval;
17366 }
17367 @@ -158,30 +156,28 @@ static int rettags(yaffs_ExtendedTags *e
17368 /* Read a chunk (page) from NAND.
17369 *
17370 * Caller expects ExtendedTags data to be usable even on error; that is,
17371 - * all members except eccResult and blockBad are zeroed.
17372 + * all members except ecc_result and block_bad are zeroed.
17373 *
17374 * - Check ECC results for data (if applicable)
17375 * - Check for blank/erased block (return empty ExtendedTags if blank)
17376 * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
17377 * - Convert PackedTags1 to ExtendedTags
17378 - * - Update eccResult and blockBad members to refect state.
17379 + * - Update ecc_result and block_bad members to refect state.
17380 *
17381 * Returns YAFFS_OK or YAFFS_FAIL.
17382 */
17383 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
17384 - int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
17385 +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev,
17386 + int nand_chunk, __u8 *data, yaffs_ext_tags *etags)
17387 {
17388 - struct mtd_info *mtd = dev->genericDevice;
17389 - int chunkBytes = dev->nDataBytesPerChunk;
17390 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17391 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17392 + int chunkBytes = dev->data_bytes_per_chunk;
17393 + loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
17394 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
17395 struct mtd_oob_ops ops;
17396 yaffs_PackedTags1 pt1;
17397 int retval;
17398 int deleted;
17399
17400 - dev->nPageReads++;
17401 -
17402 memset(&ops, 0, sizeof(ops));
17403 ops.mode = MTD_OOB_AUTO;
17404 ops.len = (data) ? chunkBytes : 0;
17405 @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17406 */
17407 retval = mtd->read_oob(mtd, addr, &ops);
17408 if (retval) {
17409 - yaffs_trace(YAFFS_TRACE_MTD,
17410 - "read_oob failed, chunk %d, mtd error %d\n",
17411 - chunkInNAND, retval);
17412 + T(YAFFS_TRACE_MTD,
17413 + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
17414 + nand_chunk, retval));
17415 }
17416
17417 switch (retval) {
17418 @@ -213,23 +209,23 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17419 case -EUCLEAN:
17420 /* MTD's ECC fixed the data */
17421 eccres = YAFFS_ECC_RESULT_FIXED;
17422 - dev->eccFixed++;
17423 + dev->n_ecc_fixed++;
17424 break;
17425
17426 case -EBADMSG:
17427 /* MTD's ECC could not fix the data */
17428 - dev->eccUnfixed++;
17429 + dev->n_ecc_unfixed++;
17430 /* fall into... */
17431 default:
17432 rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
17433 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
17434 + etags->block_bad = (mtd->block_isbad)(mtd, addr);
17435 return YAFFS_FAIL;
17436 }
17437
17438 /* Check for a blank/erased chunk.
17439 */
17440 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
17441 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
17442 + if (yaffs_check_ff((__u8 *)&pt1, 8)) {
17443 + /* when blank, upper layers want ecc_result to be <= NO_ERROR */
17444 return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
17445 }
17446
17447 @@ -241,37 +237,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17448 deleted = !pt1.deleted;
17449 pt1.deleted = 1;
17450 #else
17451 - deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
17452 + deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7);
17453 #endif
17454
17455 /* Check the packed tags mini-ECC and correct if necessary/possible.
17456 */
17457 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
17458 + retval = yaffs_check_tags_ecc((yaffs_tags_t *)&pt1);
17459 switch (retval) {
17460 case 0:
17461 /* no tags error, use MTD result */
17462 break;
17463 case 1:
17464 /* recovered tags-ECC error */
17465 - dev->tagsEccFixed++;
17466 + dev->n_tags_ecc_fixed++;
17467 if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
17468 eccres = YAFFS_ECC_RESULT_FIXED;
17469 break;
17470 default:
17471 /* unrecovered tags-ECC error */
17472 - dev->tagsEccUnfixed++;
17473 + dev->n_tags_ecc_unfixed++;
17474 return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
17475 }
17476
17477 /* Unpack the tags to extended form and set ECC result.
17478 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
17479 + * [set shouldBeFF just to keep yaffs_unpack_tags1 happy]
17480 */
17481 pt1.shouldBeFF = 0xFFFFFFFF;
17482 - yaffs_UnpackTags1(etags, &pt1);
17483 - etags->eccResult = eccres;
17484 + yaffs_unpack_tags1(etags, &pt1);
17485 + etags->ecc_result = eccres;
17486
17487 /* Set deleted state */
17488 - etags->chunkDeleted = deleted;
17489 + etags->is_deleted = deleted;
17490 return YAFFS_OK;
17491 }
17492
17493 @@ -282,15 +278,15 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
17494 *
17495 * Returns YAFFS_OK or YAFFS_FAIL.
17496 */
17497 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
17498 +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
17499 {
17500 - struct mtd_info *mtd = dev->genericDevice;
17501 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
17502 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17503 + int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
17504 int retval;
17505
17506 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
17507 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
17508
17509 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
17510 + retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
17511 return (retval) ? YAFFS_FAIL : YAFFS_OK;
17512 }
17513
17514 @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru
17515 int oobavail = mtd->ecclayout->oobavail;
17516
17517 if (oobavail < YTAG1_SIZE) {
17518 - yaffs_trace(YAFFS_TRACE_ERROR,
17519 - "mtd device has only %d bytes for tags, need %d\n",
17520 - oobavail, YTAG1_SIZE);
17521 + T(YAFFS_TRACE_ERROR,
17522 + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
17523 + oobavail, YTAG1_SIZE));
17524 return YAFFS_FAIL;
17525 }
17526 return YAFFS_OK;
17527 @@ -322,13 +318,13 @@ static int nandmtd1_TestPrerequists(stru
17528 *
17529 * Always returns YAFFS_OK.
17530 */
17531 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
17532 - yaffs_BlockState *pState, __u32 *pSequenceNumber)
17533 +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
17534 + yaffs_block_state_t *pState, __u32 *pSequenceNumber)
17535 {
17536 - struct mtd_info *mtd = dev->genericDevice;
17537 - int chunkNo = blockNo * dev->nChunksPerBlock;
17538 - loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
17539 - yaffs_ExtendedTags etags;
17540 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
17541 + int chunkNo = block_no * dev->param.chunks_per_block;
17542 + loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk;
17543 + yaffs_ext_tags etags;
17544 int state = YAFFS_BLOCK_STATE_DEAD;
17545 int seqnum = 0;
17546 int retval;
17547 @@ -340,17 +336,17 @@ int nandmtd1_QueryNANDBlock(struct yaffs
17548 return YAFFS_FAIL;
17549
17550 retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
17551 - etags.blockBad = (mtd->block_isbad)(mtd, addr);
17552 - if (etags.blockBad) {
17553 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
17554 - "block %d is marked bad\n", blockNo);
17555 + etags.block_bad = (mtd->block_isbad)(mtd, addr);
17556 + if (etags.block_bad) {
17557 + T(YAFFS_TRACE_BAD_BLOCKS,
17558 + (TSTR("block %d is marked bad"TENDSTR), block_no));
17559 state = YAFFS_BLOCK_STATE_DEAD;
17560 - } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
17561 + } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
17562 /* bad tags, need to look more closely */
17563 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17564 - } else if (etags.chunkUsed) {
17565 + } else if (etags.chunk_used) {
17566 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17567 - seqnum = etags.sequenceNumber;
17568 + seqnum = etags.seq_number;
17569 } else {
17570 state = YAFFS_BLOCK_STATE_EMPTY;
17571 }
17572 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1-compat.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1-compat.c
17573 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1-compat.c 2010-10-20 13:17:58.956000294 +0300
17574 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1-compat.c 1970-01-01 02:00:00.000000000 +0200
17575 @@ -1,434 +0,0 @@
17576 -From ian@brightstareng.com Fri May 18 15:06:49 2007
17577 -From ian@brightstareng.com Fri May 18 15:08:21 2007
17578 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
17579 - by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
17580 - (envelope-from <ian@brightstareng.com>)
17581 - id 1Hp380-00011e-T6
17582 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
17583 -Received: from localhost (localhost.localdomain [127.0.0.1])
17584 - by zebra.brightstareng.com (Postfix) with ESMTP
17585 - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
17586 -Received: from zebra.brightstareng.com ([127.0.0.1])
17587 - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
17588 - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
17589 -Received: from pippin (unknown [192.168.1.25])
17590 - by zebra.brightstareng.com (Postfix) with ESMTP
17591 - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
17592 -From: Ian McDonnell <ian@brightstareng.com>
17593 -To: David Goodenough <david.goodenough@linkchoose.co.uk>
17594 -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
17595 -Date: Fri, 18 May 2007 10:06:49 -0400
17596 -User-Agent: KMail/1.9.1
17597 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
17598 -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
17599 -Cc: Andrea Conti <alyf@alyf.net>,
17600 - Charles Manning <manningc2@actrix.gen.nz>
17601 -MIME-Version: 1.0
17602 -Content-Type: Multipart/Mixed;
17603 - boundary="Boundary-00=_5LbTGmt62YoutxM"
17604 -Message-Id: <200705181006.49860.ian@brightstareng.com>
17605 -X-Virus-Scanned: by amavisd-new at brightstareng.com
17606 -Status: R
17607 -X-Status: NT
17608 -X-KMail-EncryptionState:
17609 -X-KMail-SignatureState:
17610 -X-KMail-MDN-Sent:
17611 -
17612 ---Boundary-00=_5LbTGmt62YoutxM
17613 -Content-Type: text/plain;
17614 - charset="iso-8859-15"
17615 -Content-Transfer-Encoding: 7bit
17616 -Content-Disposition: inline
17617 -
17618 -David, Andrea,
17619 -
17620 -On Friday 18 May 2007 08:34, you wrote:
17621 -> Yea team. With this fix in place (I put it in the wrong place
17622 -> at first) I can now mount and ls the Yaffs partition without
17623 -> an error messages!
17624 -
17625 -Good news!
17626 -
17627 -Attached is a newer yaffs_mtdif1.c with a bandaid to help the
17628 -2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
17629 -See the LINUX_VERSION_CODE conditional in
17630 -nandmtd1_ReadChunkWithTagsFromNAND.
17631 -
17632 --imcd
17633 -
17634 ---Boundary-00=_5LbTGmt62YoutxM
17635 -Content-Type: text/x-csrc;
17636 - charset="iso-8859-15";
17637 - name="yaffs_mtdif1.c"
17638 -Content-Transfer-Encoding: 7bit
17639 -Content-Disposition: attachment;
17640 - filename="yaffs_mtdif1.c"
17641 -
17642 -/*
17643 - * YAFFS: Yet another FFS. A NAND-flash specific file system.
17644 - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
17645 - *
17646 - * Copyright (C) 2002 Aleph One Ltd.
17647 - * for Toby Churchill Ltd and Brightstar Engineering
17648 - *
17649 - * This program is free software; you can redistribute it and/or modify
17650 - * it under the terms of the GNU General Public License version 2 as
17651 - * published by the Free Software Foundation.
17652 - */
17653 -
17654 -/*
17655 - * This module provides the interface between yaffs_nand.c and the
17656 - * MTD API. This version is used when the MTD interface supports the
17657 - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
17658 - * and we have small-page NAND device.
17659 - *
17660 - * These functions are invoked via function pointers in yaffs_nand.c.
17661 - * This replaces functionality provided by functions in yaffs_mtdif.c
17662 - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
17663 - * called in yaffs_mtdif.c when the function pointers are NULL.
17664 - * We assume the MTD layer is performing ECC (useNANDECC is true).
17665 - */
17666 -
17667 -#include "yportenv.h"
17668 -#include "yaffs_guts.h"
17669 -#include "yaffs_packedtags1.h"
17670 -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
17671 -
17672 -#include "linux/kernel.h"
17673 -#include "linux/version.h"
17674 -#include "linux/types.h"
17675 -#include "linux/mtd/mtd.h"
17676 -
17677 -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
17678 -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
17679 -
17680 -const char *yaffs_mtdif1_c_version = "$Id$";
17681 -
17682 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17683 -# define YTAG1_SIZE 8
17684 -#else
17685 -# define YTAG1_SIZE 9
17686 -#endif
17687 -
17688 -#if 0
17689 -/* Use the following nand_ecclayout with MTD when using
17690 - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
17691 - * If you have existing Yaffs images and the byte order differs from this,
17692 - * adjust 'oobfree' to match your existing Yaffs data.
17693 - *
17694 - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
17695 - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
17696 - * the 9th byte.
17697 - *
17698 - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
17699 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
17700 - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
17701 - * byte and B is the small-page bad-block indicator byte.
17702 - */
17703 -static struct nand_ecclayout nand_oob_16 = {
17704 - .eccbytes = 6,
17705 - .eccpos = { 8, 9, 10, 13, 14, 15 },
17706 - .oobavail = 9,
17707 - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
17708 -};
17709 -#endif
17710 -
17711 -/* Write a chunk (page) of data to NAND.
17712 - *
17713 - * Caller always provides ExtendedTags data which are converted to a more
17714 - * compact (packed) form for storage in NAND. A mini-ECC runs over the
17715 - * contents of the tags meta-data; used to valid the tags when read.
17716 - *
17717 - * - Pack ExtendedTags to PackedTags1 form
17718 - * - Compute mini-ECC for PackedTags1
17719 - * - Write data and packed tags to NAND.
17720 - *
17721 - * Note: Due to the use of the PackedTags1 meta-data which does not include
17722 - * a full sequence number (as found in the larger PackedTags2 form) it is
17723 - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
17724 - * discarded and dirty. This is not ideal: newer NAND parts are supposed
17725 - * to be written just once. When Yaffs performs this operation, this
17726 - * function is called with a NULL data pointer -- calling MTD write_oob
17727 - * without data is valid usage (2.6.17).
17728 - *
17729 - * Any underlying MTD error results in YAFFS_FAIL.
17730 - * Returns YAFFS_OK or YAFFS_FAIL.
17731 - */
17732 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
17733 - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
17734 -{
17735 - struct mtd_info * mtd = dev->genericDevice;
17736 - int chunkBytes = dev->nDataBytesPerChunk;
17737 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17738 - struct mtd_oob_ops ops;
17739 - yaffs_PackedTags1 pt1;
17740 - int retval;
17741 -
17742 - /* we assume that PackedTags1 and yaffs_Tags are compatible */
17743 - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
17744 - compile_time_assertion(sizeof(yaffs_Tags) == 8);
17745 -
17746 - yaffs_PackTags1(&pt1, etags);
17747 - yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
17748 -
17749 - /* When deleting a chunk, the upper layer provides only skeletal
17750 - * etags, one with chunkDeleted set. However, we need to update the
17751 - * tags, not erase them completely. So we use the NAND write property
17752 - * that only zeroed-bits stick and set tag bytes to all-ones and
17753 - * zero just the (not) deleted bit.
17754 - */
17755 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17756 - if (etags->chunkDeleted) {
17757 - memset(&pt1, 0xff, 8);
17758 - /* clear delete status bit to indicate deleted */
17759 - pt1.deleted = 0;
17760 - }
17761 -#else
17762 - ((__u8 *)&pt1)[8] = 0xff;
17763 - if (etags->chunkDeleted) {
17764 - memset(&pt1, 0xff, 8);
17765 - /* zero pageStatus byte to indicate deleted */
17766 - ((__u8 *)&pt1)[8] = 0;
17767 - }
17768 -#endif
17769 -
17770 - memset(&ops, 0, sizeof(ops));
17771 - ops.mode = MTD_OOB_AUTO;
17772 - ops.len = (data) ? chunkBytes : 0;
17773 - ops.ooblen = YTAG1_SIZE;
17774 - ops.datbuf = (__u8 *)data;
17775 - ops.oobbuf = (__u8 *)&pt1;
17776 -
17777 - retval = mtd->write_oob(mtd, addr, &ops);
17778 - if (retval) {
17779 - yaffs_trace(YAFFS_TRACE_MTD,
17780 - "write_oob failed, chunk %d, mtd error %d\n",
17781 - chunkInNAND, retval);
17782 - }
17783 - return retval ? YAFFS_FAIL : YAFFS_OK;
17784 -}
17785 -
17786 -/* Return with empty ExtendedTags but add eccResult.
17787 - */
17788 -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
17789 -{
17790 - if (etags) {
17791 - memset(etags, 0, sizeof(*etags));
17792 - etags->eccResult = eccResult;
17793 - }
17794 - return retval;
17795 -}
17796 -
17797 -/* Read a chunk (page) from NAND.
17798 - *
17799 - * Caller expects ExtendedTags data to be usable even on error; that is,
17800 - * all members except eccResult and blockBad are zeroed.
17801 - *
17802 - * - Check ECC results for data (if applicable)
17803 - * - Check for blank/erased block (return empty ExtendedTags if blank)
17804 - * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
17805 - * - Convert PackedTags1 to ExtendedTags
17806 - * - Update eccResult and blockBad members to refect state.
17807 - *
17808 - * Returns YAFFS_OK or YAFFS_FAIL.
17809 - */
17810 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
17811 - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
17812 -{
17813 - struct mtd_info * mtd = dev->genericDevice;
17814 - int chunkBytes = dev->nDataBytesPerChunk;
17815 - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
17816 - int eccres = YAFFS_ECC_RESULT_NO_ERROR;
17817 - struct mtd_oob_ops ops;
17818 - yaffs_PackedTags1 pt1;
17819 - int retval;
17820 - int deleted;
17821 -
17822 - memset(&ops, 0, sizeof(ops));
17823 - ops.mode = MTD_OOB_AUTO;
17824 - ops.len = (data) ? chunkBytes : 0;
17825 - ops.ooblen = YTAG1_SIZE;
17826 - ops.datbuf = data;
17827 - ops.oobbuf = (__u8 *)&pt1;
17828 -
17829 -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
17830 - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
17831 - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
17832 - */
17833 - ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
17834 -#endif
17835 - /* Read page and oob using MTD.
17836 - * Check status and determine ECC result.
17837 - */
17838 - retval = mtd->read_oob(mtd, addr, &ops);
17839 - if (retval) {
17840 - yaffs_trace(YAFFS_TRACE_MTD,
17841 - "read_oob failed, chunk %d, mtd error %d\n",
17842 - chunkInNAND, retval);
17843 - }
17844 -
17845 - switch (retval) {
17846 - case 0:
17847 - /* no error */
17848 - break;
17849 -
17850 - case -EUCLEAN:
17851 - /* MTD's ECC fixed the data */
17852 - eccres = YAFFS_ECC_RESULT_FIXED;
17853 - dev->eccFixed++;
17854 - break;
17855 -
17856 - case -EBADMSG:
17857 - /* MTD's ECC could not fix the data */
17858 - dev->eccUnfixed++;
17859 - /* fall into... */
17860 - default:
17861 - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
17862 - etags->blockBad = (mtd->block_isbad)(mtd, addr);
17863 - return YAFFS_FAIL;
17864 - }
17865 -
17866 - /* Check for a blank/erased chunk.
17867 - */
17868 - if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
17869 - /* when blank, upper layers want eccResult to be <= NO_ERROR */
17870 - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
17871 - }
17872 -
17873 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17874 - /* Read deleted status (bit) then return it to it's non-deleted
17875 - * state before performing tags mini-ECC check. pt1.deleted is
17876 - * inverted.
17877 - */
17878 - deleted = !pt1.deleted;
17879 - pt1.deleted = 1;
17880 -#else
17881 - (void) deleted; /* not used */
17882 -#endif
17883 -
17884 - /* Check the packed tags mini-ECC and correct if necessary/possible.
17885 - */
17886 - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
17887 - switch (retval) {
17888 - case 0:
17889 - /* no tags error, use MTD result */
17890 - break;
17891 - case 1:
17892 - /* recovered tags-ECC error */
17893 - dev->tagsEccFixed++;
17894 - eccres = YAFFS_ECC_RESULT_FIXED;
17895 - break;
17896 - default:
17897 - /* unrecovered tags-ECC error */
17898 - dev->tagsEccUnfixed++;
17899 - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
17900 - }
17901 -
17902 - /* Unpack the tags to extended form and set ECC result.
17903 - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
17904 - */
17905 - pt1.shouldBeFF = 0xFFFFFFFF;
17906 - yaffs_UnpackTags1(etags, &pt1);
17907 - etags->eccResult = eccres;
17908 -
17909 - /* Set deleted state.
17910 - */
17911 -#ifndef CONFIG_YAFFS_9BYTE_TAGS
17912 - etags->chunkDeleted = deleted;
17913 -#else
17914 - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
17915 -#endif
17916 - return YAFFS_OK;
17917 -}
17918 -
17919 -/* Mark a block bad.
17920 - *
17921 - * This is a persistant state.
17922 - * Use of this function should be rare.
17923 - *
17924 - * Returns YAFFS_OK or YAFFS_FAIL.
17925 - */
17926 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
17927 -{
17928 - struct mtd_info * mtd = dev->genericDevice;
17929 - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
17930 - int retval;
17931 -
17932 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
17933 -
17934 - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
17935 - return (retval) ? YAFFS_FAIL : YAFFS_OK;
17936 -}
17937 -
17938 -/* Check any MTD prerequists.
17939 - *
17940 - * Returns YAFFS_OK or YAFFS_FAIL.
17941 - */
17942 -static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
17943 -{
17944 - /* 2.6.18 has mtd->ecclayout->oobavail */
17945 - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
17946 - int oobavail = mtd->ecclayout->oobavail;
17947 -
17948 - if (oobavail < YTAG1_SIZE) {
17949 - yaffs_trace(YAFFS_TRACE_ERROR,
17950 - "mtd device has only %d bytes for tags, need %d",
17951 - oobavail, YTAG1_SIZE);
17952 - return YAFFS_FAIL;
17953 - }
17954 - return YAFFS_OK;
17955 -}
17956 -
17957 -/* Query for the current state of a specific block.
17958 - *
17959 - * Examine the tags of the first chunk of the block and return the state:
17960 - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
17961 - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
17962 - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
17963 - *
17964 - * Always returns YAFFS_OK.
17965 - */
17966 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
17967 - yaffs_BlockState * pState, int *pSequenceNumber)
17968 -{
17969 - struct mtd_info * mtd = dev->genericDevice;
17970 - int chunkNo = blockNo * dev->nChunksPerBlock;
17971 - yaffs_ExtendedTags etags;
17972 - int state = YAFFS_BLOCK_STATE_DEAD;
17973 - int seqnum = 0;
17974 - int retval;
17975 -
17976 - /* We don't yet have a good place to test for MTD config prerequists.
17977 - * Do it here as we are called during the initial scan.
17978 - */
17979 - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
17980 - return YAFFS_FAIL;
17981 - }
17982 -
17983 - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
17984 - if (etags.blockBad) {
17985 - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
17986 - "block %d is marked bad", blockNo);
17987 - state = YAFFS_BLOCK_STATE_DEAD;
17988 - }
17989 - else if (etags.chunkUsed) {
17990 - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
17991 - seqnum = etags.sequenceNumber;
17992 - }
17993 - else {
17994 - state = YAFFS_BLOCK_STATE_EMPTY;
17995 - }
17996 -
17997 - *pState = state;
17998 - *pSequenceNumber = seqnum;
17999 -
18000 - /* query always succeeds */
18001 - return YAFFS_OK;
18002 -}
18003 -
18004 -#endif /*KERNEL_VERSION*/
18005 -
18006 ---Boundary-00=_5LbTGmt62YoutxM--
18007 -
18008 -
18009 -
18010 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.h
18011 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif1.h 2010-10-20 13:17:58.957000294 +0300
18012 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif1.h 2010-10-20 13:28:16.062000294 +0300
18013 @@ -1,7 +1,7 @@
18014 /*
18015 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
18016 *
18017 - * Copyright (C) 2002-2007 Aleph One Ltd.
18018 + * Copyright (C) 2002-2010 Aleph One Ltd.
18019 * for Toby Churchill Ltd and Brightstar Engineering
18020 *
18021 * This program is free software; you can redistribute it and/or modify
18022 @@ -14,15 +14,15 @@
18023 #ifndef __YAFFS_MTDIF1_H__
18024 #define __YAFFS_MTDIF1_H__
18025
18026 -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18027 - const __u8 *data, const yaffs_ExtendedTags *tags);
18028 +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18029 + const __u8 *data, const yaffs_ext_tags *tags);
18030
18031 -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18032 - __u8 *data, yaffs_ExtendedTags *tags);
18033 +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18034 + __u8 *data, yaffs_ext_tags *tags);
18035
18036 -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
18037 +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
18038
18039 -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18040 - yaffs_BlockState *state, __u32 *sequenceNumber);
18041 +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18042 + yaffs_block_state_t *state, __u32 *seq_number);
18043
18044 #endif
18045 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.c
18046 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.c 2010-10-20 13:17:58.957000294 +0300
18047 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.c 2010-10-20 13:28:16.028000294 +0300
18048 @@ -1,7 +1,7 @@
18049 /*
18050 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18051 *
18052 - * Copyright (C) 2002-2007 Aleph One Ltd.
18053 + * Copyright (C) 2002-2010 Aleph One Ltd.
18054 * for Toby Churchill Ltd and Brightstar Engineering
18055 *
18056 * Created by Charles Manning <charles@aleph1.co.uk>
18057 @@ -13,11 +13,8 @@
18058
18059 /* mtd interface for YAFFS2 */
18060
18061 -const char *yaffs_mtdif2_c_version =
18062 - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
18063 -
18064 #include "yportenv.h"
18065 -
18066 +#include "yaffs_trace.h"
18067
18068 #include "yaffs_mtdif2.h"
18069
18070 @@ -27,15 +24,17 @@ const char *yaffs_mtdif2_c_version =
18071
18072 #include "yaffs_packedtags2.h"
18073
18074 +#include "yaffs_linux.h"
18075 +
18076 /* NB For use with inband tags....
18077 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
18078 * use it to load the tags.
18079 */
18080 -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18081 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18082 const __u8 *data,
18083 - const yaffs_ExtendedTags *tags)
18084 + const yaffs_ext_tags *tags)
18085 {
18086 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18087 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18088 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18089 struct mtd_oob_ops ops;
18090 #else
18091 @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18092
18093 yaffs_PackedTags2 pt;
18094
18095 + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
18096 + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t : (void *)&pt;
18097 +
18098 T(YAFFS_TRACE_MTD,
18099 (TSTR
18100 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
18101 - TENDSTR), chunkInNAND, data, tags));
18102 + TENDSTR), nand_chunk, data, tags));
18103
18104
18105 - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
18106 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
18107
18108 /* For yaffs2 writing there must be both data and tags.
18109 * If we're using inband tags, then the tags are stuffed into
18110 @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18111 */
18112 if (!data || !tags)
18113 BUG();
18114 - else if (dev->inbandTags) {
18115 + else if (dev->param.inband_tags) {
18116 yaffs_PackedTags2TagsPart *pt2tp;
18117 - pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
18118 + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk);
18119 yaffs_PackTags2TagsPart(pt2tp, tags);
18120 } else
18121 - yaffs_PackTags2(&pt, tags);
18122 + yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
18123
18124 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18125 ops.mode = MTD_OOB_AUTO;
18126 - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
18127 - ops.len = dev->totalBytesPerChunk;
18128 + ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
18129 + ops.len = dev->param.total_bytes_per_chunk;
18130 ops.ooboffs = 0;
18131 ops.datbuf = (__u8 *)data;
18132 - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
18133 + ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
18134 retval = mtd->write_oob(mtd, addr, &ops);
18135
18136 #else
18137 - if (!dev->inbandTags) {
18138 + if (!dev->param.inband_tags) {
18139 retval =
18140 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18141 - &dummy, data, (__u8 *) &pt, NULL);
18142 + mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
18143 + &dummy, data, (__u8 *) packed_tags_ptr, NULL);
18144 } else {
18145 retval =
18146 - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
18147 + mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy,
18148 data);
18149 }
18150 #endif
18151 @@ -95,10 +97,10 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
18152 return YAFFS_FAIL;
18153 }
18154
18155 -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18156 - __u8 *data, yaffs_ExtendedTags *tags)
18157 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18158 + __u8 *data, yaffs_ext_tags *tags)
18159 {
18160 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18161 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18162 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18163 struct mtd_oob_ops ops;
18164 #endif
18165 @@ -106,20 +108,23 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18166 int retval = 0;
18167 int localData = 0;
18168
18169 - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
18170 + loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
18171
18172 yaffs_PackedTags2 pt;
18173
18174 + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
18175 + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t: (void *)&pt;
18176 +
18177 T(YAFFS_TRACE_MTD,
18178 (TSTR
18179 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
18180 - TENDSTR), chunkInNAND, data, tags));
18181 + TENDSTR), nand_chunk, data, tags));
18182
18183 - if (dev->inbandTags) {
18184 + if (dev->param.inband_tags) {
18185
18186 if (!data) {
18187 localData = 1;
18188 - data = yaffs_GetTempBuffer(dev, __LINE__);
18189 + data = yaffs_get_temp_buffer(dev, __LINE__);
18190 }
18191
18192
18193 @@ -127,30 +132,30 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18194
18195
18196 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
18197 - if (dev->inbandTags || (data && !tags))
18198 - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
18199 + if (dev->param.inband_tags || (data && !tags))
18200 + retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
18201 &dummy, data);
18202 else if (tags) {
18203 ops.mode = MTD_OOB_AUTO;
18204 - ops.ooblen = sizeof(pt);
18205 - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
18206 + ops.ooblen = packed_tags_size;
18207 + ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
18208 ops.ooboffs = 0;
18209 ops.datbuf = data;
18210 - ops.oobbuf = dev->spareBuffer;
18211 + ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
18212 retval = mtd->read_oob(mtd, addr, &ops);
18213 }
18214 #else
18215 - if (!dev->inbandTags && data && tags) {
18216 + if (!dev->param.inband_tags && data && tags) {
18217
18218 - retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18219 + retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
18220 &dummy, data, dev->spareBuffer,
18221 NULL);
18222 } else {
18223 if (data)
18224 retval =
18225 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18226 + mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
18227 data);
18228 - if (!dev->inbandTags && tags)
18229 + if (!dev->param.inband_tags && tags)
18230 retval =
18231 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
18232 dev->spareBuffer);
18233 @@ -158,41 +163,47 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
18234 #endif
18235
18236
18237 - if (dev->inbandTags) {
18238 + if (dev->param.inband_tags) {
18239 if (tags) {
18240 yaffs_PackedTags2TagsPart *pt2tp;
18241 - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
18242 - yaffs_UnpackTags2TagsPart(tags, pt2tp);
18243 + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk];
18244 + yaffs_unpack_tags2tags_part(tags, pt2tp);
18245 }
18246 } else {
18247 if (tags) {
18248 - memcpy(&pt, dev->spareBuffer, sizeof(pt));
18249 - yaffs_UnpackTags2(tags, &pt);
18250 + memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size);
18251 + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
18252 }
18253 }
18254
18255 if (localData)
18256 - yaffs_ReleaseTempBuffer(dev, data, __LINE__);
18257 + yaffs_release_temp_buffer(dev, data, __LINE__);
18258
18259 - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
18260 - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
18261 + if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
18262 + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
18263 + dev->n_ecc_unfixed++;
18264 + }
18265 + if(tags && retval == -EUCLEAN && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
18266 + tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
18267 + dev->n_ecc_fixed++;
18268 + }
18269 if (retval == 0)
18270 return YAFFS_OK;
18271 else
18272 return YAFFS_FAIL;
18273 }
18274
18275 -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
18276 +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
18277 {
18278 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18279 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18280 int retval;
18281 T(YAFFS_TRACE_MTD,
18282 - (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
18283 + (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
18284
18285 retval =
18286 mtd->block_markbad(mtd,
18287 - blockNo * dev->nChunksPerBlock *
18288 - dev->totalBytesPerChunk);
18289 + block_no * dev->param.chunks_per_block *
18290 + dev->param.total_bytes_per_chunk);
18291
18292 if (retval == 0)
18293 return YAFFS_OK;
18294 @@ -201,41 +212,41 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
18295
18296 }
18297
18298 -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18299 - yaffs_BlockState *state, __u32 *sequenceNumber)
18300 +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18301 + yaffs_block_state_t *state, __u32 *seq_number)
18302 {
18303 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18304 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18305 int retval;
18306
18307 T(YAFFS_TRACE_MTD,
18308 - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
18309 + (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
18310 retval =
18311 mtd->block_isbad(mtd,
18312 - blockNo * dev->nChunksPerBlock *
18313 - dev->totalBytesPerChunk);
18314 + block_no * dev->param.chunks_per_block *
18315 + dev->param.total_bytes_per_chunk);
18316
18317 if (retval) {
18318 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
18319
18320 *state = YAFFS_BLOCK_STATE_DEAD;
18321 - *sequenceNumber = 0;
18322 + *seq_number = 0;
18323 } else {
18324 - yaffs_ExtendedTags t;
18325 + yaffs_ext_tags t;
18326 nandmtd2_ReadChunkWithTagsFromNAND(dev,
18327 - blockNo *
18328 - dev->nChunksPerBlock, NULL,
18329 + block_no *
18330 + dev->param.chunks_per_block, NULL,
18331 &t);
18332
18333 - if (t.chunkUsed) {
18334 - *sequenceNumber = t.sequenceNumber;
18335 + if (t.chunk_used) {
18336 + *seq_number = t.seq_number;
18337 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
18338 } else {
18339 - *sequenceNumber = 0;
18340 + *seq_number = 0;
18341 *state = YAFFS_BLOCK_STATE_EMPTY;
18342 }
18343 }
18344 T(YAFFS_TRACE_MTD,
18345 - (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
18346 + (TSTR("block is bad seq %d state %d" TENDSTR), *seq_number,
18347 *state));
18348
18349 if (retval == 0)
18350 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.h
18351 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif2.h 2010-10-20 13:17:58.957000294 +0300
18352 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif2.h 2010-10-20 13:28:16.062000294 +0300
18353 @@ -1,7 +1,7 @@
18354 /*
18355 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18356 *
18357 - * Copyright (C) 2002-2007 Aleph One Ltd.
18358 + * Copyright (C) 2002-2010 Aleph One Ltd.
18359 * for Toby Churchill Ltd and Brightstar Engineering
18360 *
18361 * Created by Charles Manning <charles@aleph1.co.uk>
18362 @@ -17,13 +17,13 @@
18363 #define __YAFFS_MTDIF2_H__
18364
18365 #include "yaffs_guts.h"
18366 -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
18367 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
18368 const __u8 *data,
18369 - const yaffs_ExtendedTags *tags);
18370 -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18371 - __u8 *data, yaffs_ExtendedTags *tags);
18372 -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
18373 -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
18374 - yaffs_BlockState *state, __u32 *sequenceNumber);
18375 + const yaffs_ext_tags *tags);
18376 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
18377 + __u8 *data, yaffs_ext_tags *tags);
18378 +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
18379 +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
18380 + yaffs_block_state_t *state, __u32 *seq_number);
18381
18382 #endif
18383 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.c
18384 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.c 2010-10-20 13:17:58.958000294 +0300
18385 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.c 2010-10-20 13:28:16.029000294 +0300
18386 @@ -1,7 +1,7 @@
18387 /*
18388 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18389 *
18390 - * Copyright (C) 2002-2007 Aleph One Ltd.
18391 + * Copyright (C) 2002-2010 Aleph One Ltd.
18392 * for Toby Churchill Ltd and Brightstar Engineering
18393 *
18394 * Created by Charles Manning <charles@aleph1.co.uk>
18395 @@ -11,9 +11,6 @@
18396 * published by the Free Software Foundation.
18397 */
18398
18399 -const char *yaffs_mtdif_c_version =
18400 - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
18401 -
18402 #include "yportenv.h"
18403
18404
18405 @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
18406 #include "linux/time.h"
18407 #include "linux/mtd/nand.h"
18408
18409 -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
18410 -static struct nand_oobinfo yaffs_oobinfo = {
18411 - .useecc = 1,
18412 - .eccbytes = 6,
18413 - .eccpos = {8, 9, 10, 13, 14, 15}
18414 -};
18415 -
18416 -static struct nand_oobinfo yaffs_noeccinfo = {
18417 - .useecc = 0,
18418 -};
18419 -#endif
18420 -
18421 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18422 -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
18423 -{
18424 - oob[0] = spare->tagByte0;
18425 - oob[1] = spare->tagByte1;
18426 - oob[2] = spare->tagByte2;
18427 - oob[3] = spare->tagByte3;
18428 - oob[4] = spare->tagByte4;
18429 - oob[5] = spare->tagByte5 & 0x3f;
18430 - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
18431 - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
18432 - oob[6] = spare->tagByte6;
18433 - oob[7] = spare->tagByte7;
18434 -}
18435 -
18436 -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
18437 -{
18438 - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
18439 - spare->tagByte0 = oob[0];
18440 - spare->tagByte1 = oob[1];
18441 - spare->tagByte2 = oob[2];
18442 - spare->tagByte3 = oob[3];
18443 - spare->tagByte4 = oob[4];
18444 - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
18445 - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
18446 - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
18447 - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
18448 - spare->tagByte6 = oob[6];
18449 - spare->tagByte7 = oob[7];
18450 - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
18451 -
18452 - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
18453 -}
18454 -#endif
18455 -
18456 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
18457 - const __u8 *data, const yaffs_Spare *spare)
18458 -{
18459 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18460 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18461 - struct mtd_oob_ops ops;
18462 -#endif
18463 - size_t dummy;
18464 - int retval = 0;
18465 -
18466 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
18467 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18468 - __u8 spareAsBytes[8]; /* OOB */
18469 -
18470 - if (data && !spare)
18471 - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
18472 - &dummy, data);
18473 - else if (spare) {
18474 - if (dev->useNANDECC) {
18475 - translate_spare2oob(spare, spareAsBytes);
18476 - ops.mode = MTD_OOB_AUTO;
18477 - ops.ooblen = 8; /* temp hack */
18478 - } else {
18479 - ops.mode = MTD_OOB_RAW;
18480 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
18481 - }
18482 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
18483 - ops.datbuf = (u8 *)data;
18484 - ops.ooboffs = 0;
18485 - ops.oobbuf = spareAsBytes;
18486 - retval = mtd->write_oob(mtd, addr, &ops);
18487 - }
18488 -#else
18489 - __u8 *spareAsBytes = (__u8 *) spare;
18490 -
18491 - if (data && spare) {
18492 - if (dev->useNANDECC)
18493 - retval =
18494 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18495 - &dummy, data, spareAsBytes,
18496 - &yaffs_oobinfo);
18497 - else
18498 - retval =
18499 - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
18500 - &dummy, data, spareAsBytes,
18501 - &yaffs_noeccinfo);
18502 - } else {
18503 - if (data)
18504 - retval =
18505 - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18506 - data);
18507 - if (spare)
18508 - retval =
18509 - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
18510 - &dummy, spareAsBytes);
18511 - }
18512 -#endif
18513 -
18514 - if (retval == 0)
18515 - return YAFFS_OK;
18516 - else
18517 - return YAFFS_FAIL;
18518 -}
18519 -
18520 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
18521 - yaffs_Spare *spare)
18522 -{
18523 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18524 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18525 - struct mtd_oob_ops ops;
18526 -#endif
18527 - size_t dummy;
18528 - int retval = 0;
18529 +#include "yaffs_linux.h"
18530
18531 - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
18532 -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
18533 - __u8 spareAsBytes[8]; /* OOB */
18534 -
18535 - if (data && !spare)
18536 - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
18537 - &dummy, data);
18538 - else if (spare) {
18539 - if (dev->useNANDECC) {
18540 - ops.mode = MTD_OOB_AUTO;
18541 - ops.ooblen = 8; /* temp hack */
18542 - } else {
18543 - ops.mode = MTD_OOB_RAW;
18544 - ops.ooblen = YAFFS_BYTES_PER_SPARE;
18545 - }
18546 - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
18547 - ops.datbuf = data;
18548 - ops.ooboffs = 0;
18549 - ops.oobbuf = spareAsBytes;
18550 - retval = mtd->read_oob(mtd, addr, &ops);
18551 - if (dev->useNANDECC)
18552 - translate_oob2spare(spare, spareAsBytes);
18553 - }
18554 -#else
18555 - __u8 *spareAsBytes = (__u8 *) spare;
18556 -
18557 - if (data && spare) {
18558 - if (dev->useNANDECC) {
18559 - /* Careful, this call adds 2 ints */
18560 - /* to the end of the spare data. Calling function */
18561 - /* should allocate enough memory for spare, */
18562 - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
18563 - retval =
18564 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18565 - &dummy, data, spareAsBytes,
18566 - &yaffs_oobinfo);
18567 - } else {
18568 - retval =
18569 - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
18570 - &dummy, data, spareAsBytes,
18571 - &yaffs_noeccinfo);
18572 - }
18573 - } else {
18574 - if (data)
18575 - retval =
18576 - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
18577 - data);
18578 - if (spare)
18579 - retval =
18580 - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
18581 - &dummy, spareAsBytes);
18582 - }
18583 -#endif
18584 -
18585 - if (retval == 0)
18586 - return YAFFS_OK;
18587 - else
18588 - return YAFFS_FAIL;
18589 -}
18590 -
18591 -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
18592 +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
18593 {
18594 - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
18595 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
18596 __u32 addr =
18597 - ((loff_t) blockNumber) * dev->nDataBytesPerChunk
18598 - * dev->nChunksPerBlock;
18599 + ((loff_t) blockNumber) * dev->param.total_bytes_per_chunk
18600 + * dev->param.chunks_per_block;
18601 struct erase_info ei;
18602 +
18603 int retval = 0;
18604
18605 ei.mtd = mtd;
18606 ei.addr = addr;
18607 - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
18608 + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
18609 ei.time = 1000;
18610 ei.retries = 2;
18611 ei.callback = NULL;
18612 ei.priv = (u_long) dev;
18613
18614 - /* Todo finish off the ei if required */
18615 -
18616 - sema_init(&dev->sem, 0);
18617 -
18618 retval = mtd->erase(mtd, &ei);
18619
18620 if (retval == 0)
18621 @@ -234,7 +49,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Devic
18622 return YAFFS_FAIL;
18623 }
18624
18625 -int nandmtd_InitialiseNAND(yaffs_Device *dev)
18626 +int nandmtd_InitialiseNAND(yaffs_dev_t *dev)
18627 {
18628 return YAFFS_OK;
18629 }
18630 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.h
18631 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_mtdif.h 2010-10-20 13:17:58.958000294 +0300
18632 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_mtdif.h 2010-10-20 13:28:16.062000294 +0300
18633 @@ -1,7 +1,7 @@
18634 /*
18635 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18636 *
18637 - * Copyright (C) 2002-2007 Aleph One Ltd.
18638 + * Copyright (C) 2002-2010 Aleph One Ltd.
18639 * for Toby Churchill Ltd and Brightstar Engineering
18640 *
18641 * Created by Charles Manning <charles@aleph1.co.uk>
18642 @@ -22,11 +22,6 @@
18643 extern struct nand_oobinfo yaffs_oobinfo;
18644 extern struct nand_oobinfo yaffs_noeccinfo;
18645 #endif
18646 -
18647 -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
18648 - const __u8 *data, const yaffs_Spare *spare);
18649 -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
18650 - yaffs_Spare *spare);
18651 -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
18652 -int nandmtd_InitialiseNAND(yaffs_Device *dev);
18653 +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
18654 +int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
18655 #endif
18656 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.c
18657 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.c 1970-01-01 02:00:00.000000000 +0200
18658 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.c 2010-10-20 13:28:16.029000294 +0300
18659 @@ -0,0 +1,197 @@
18660 +/*
18661 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18662 + *
18663 + * Copyright (C) 2002-2010 Aleph One Ltd.
18664 + * for Toby Churchill Ltd and Brightstar Engineering
18665 + *
18666 + * Created by Charles Manning <charles@aleph1.co.uk>
18667 + *
18668 + * This program is free software; you can redistribute it and/or modify
18669 + * it under the terms of the GNU General Public License version 2 as
18670 + * published by the Free Software Foundation.
18671 + */
18672 +
18673 +/*
18674 + * This simple implementation of a name-value store assumes a small number of values and fits
18675 + * into a small finite buffer.
18676 + *
18677 + * Each attribute is stored as a record:
18678 + * sizeof(int) bytes record size.
18679 + * strnlen+1 bytes name null terminated.
18680 + * nbytes value.
18681 + * ----------
18682 + * total size stored in record size
18683 + *
18684 + * This code has not been tested with unicode yet.
18685 + */
18686 +
18687 +
18688 +#include "yaffs_nameval.h"
18689 +
18690 +#include "yportenv.h"
18691 +
18692 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
18693 + int *exist_size)
18694 +{
18695 + int pos=0;
18696 + int size;
18697 +
18698 + memcpy(&size,xb,sizeof(int));
18699 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
18700 + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
18701 + if(exist_size)
18702 + *exist_size = size;
18703 + return pos;
18704 + }
18705 + pos += size;
18706 + if(pos < xb_size -sizeof(int))
18707 + memcpy(&size,xb + pos,sizeof(int));
18708 + else
18709 + size = 0;
18710 + }
18711 + if(exist_size)
18712 + *exist_size = 0;
18713 + return -1;
18714 +}
18715 +
18716 +static int nval_used(const char *xb, int xb_size)
18717 +{
18718 + int pos=0;
18719 + int size;
18720 +
18721 + memcpy(&size,xb + pos,sizeof(int));
18722 + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
18723 + pos += size;
18724 + if(pos < xb_size -sizeof(int))
18725 + memcpy(&size,xb + pos,sizeof(int));
18726 + else
18727 + size = 0;
18728 + }
18729 + return pos;
18730 +}
18731 +
18732 +int nval_del(char *xb, int xb_size, const YCHAR *name)
18733 +{
18734 + int pos = nval_find(xb, xb_size, name, NULL);
18735 + int size;
18736 +
18737 + if(pos >= 0 && pos < xb_size){
18738 + /* Find size, shift rest over this record, then zero out the rest of buffer */
18739 + memcpy(&size,xb+pos,sizeof(int));
18740 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
18741 + memset(xb + (xb_size - size),0,size);
18742 + return 0;
18743 + } else
18744 + return -ENODATA;
18745 +}
18746 +
18747 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
18748 +{
18749 + int pos;
18750 + int namelen = yaffs_strnlen(name,xb_size);
18751 + int reclen;
18752 + int size_exist = 0;
18753 + int space;
18754 + int start;
18755 +
18756 + pos = nval_find(xb,xb_size,name, &size_exist);
18757 +
18758 + if(flags & XATTR_CREATE && pos >= 0)
18759 + return -EEXIST;
18760 + if(flags & XATTR_REPLACE && pos < 0)
18761 + return -ENODATA;
18762 +
18763 + start = nval_used(xb,xb_size);
18764 + space = xb_size - start + size_exist;
18765 +
18766 + reclen = (sizeof(int) + namelen + 1 + bsize);
18767 +
18768 + if(reclen > space)
18769 + return -ENOSPC;
18770 +
18771 + if(pos >= 0){
18772 + nval_del(xb,xb_size,name);
18773 + start = nval_used(xb, xb_size);
18774 + }
18775 +
18776 + pos = start;
18777 +
18778 + memcpy(xb + pos,&reclen,sizeof(int));
18779 + pos +=sizeof(int);
18780 + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
18781 + pos+= (namelen+1);
18782 + memcpy(xb + pos,buf,bsize);
18783 + return 0;
18784 +}
18785 +
18786 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
18787 +{
18788 + int pos = nval_find(xb,xb_size,name,NULL);
18789 + int size;
18790 +
18791 + if(pos >= 0 && pos< xb_size){
18792 +
18793 + memcpy(&size,xb +pos,sizeof(int));
18794 + pos+=sizeof(int); /* advance past record length */
18795 + size -= sizeof(int);
18796 +
18797 + /* Advance over name string */
18798 + while(xb[pos] && size > 0 && pos < xb_size){
18799 + pos++;
18800 + size--;
18801 + }
18802 + /*Advance over NUL */
18803 + pos++;
18804 + size--;
18805 +
18806 + if(size <= bsize){
18807 + memcpy(buf,xb + pos,size);
18808 + return size;
18809 + }
18810 +
18811 + }
18812 + if(pos >= 0)
18813 + return -ERANGE;
18814 + else
18815 + return -ENODATA;
18816 +}
18817 +
18818 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
18819 +{
18820 + int pos = 0;
18821 + int size;
18822 + int name_len;
18823 + int ncopied = 0;
18824 + int filled = 0;
18825 +
18826 + memcpy(&size,xb + pos,sizeof(int));
18827 + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
18828 + pos+= sizeof(int);
18829 + size-=sizeof(int);
18830 + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
18831 + if(ncopied + name_len + 1 < bsize){
18832 + memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
18833 + buf+= name_len;
18834 + *buf = '\0';
18835 + buf++;
18836 + if(sizeof(YCHAR) > 1){
18837 + *buf = '\0';
18838 + buf++;
18839 + }
18840 + ncopied += (name_len+1);
18841 + } else
18842 + filled = 1;
18843 + pos+=size;
18844 + if(pos < xb_size -sizeof(int))
18845 + memcpy(&size,xb + pos,sizeof(int));
18846 + else
18847 + size = 0;
18848 + }
18849 + return ncopied;
18850 +}
18851 +
18852 +
18853 +int nval_hasvalues(const char *xb, int xb_size)
18854 +{
18855 + return nval_used(xb, xb_size) > 0;
18856 +}
18857 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.h
18858 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nameval.h 1970-01-01 02:00:00.000000000 +0200
18859 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nameval.h 2010-10-20 13:28:16.062000294 +0300
18860 @@ -0,0 +1,25 @@
18861 +/*
18862 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
18863 + *
18864 + * Copyright (C) 2002-2010 Aleph One Ltd.
18865 + * for Toby Churchill Ltd and Brightstar Engineering
18866 + *
18867 + * Created by Charles Manning <charles@aleph1.co.uk>
18868 + *
18869 + * This program is free software; you can redistribute it and/or modify
18870 + * it under the terms of the GNU Lesser General Public License version 2.1 as
18871 + * published by the Free Software Foundation.
18872 + *
18873 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
18874 + */
18875 +#ifndef __NAMEVAL_H__
18876 +#define __NAMEVAL_H__
18877 +
18878 +#include "yportenv.h"
18879 +
18880 +int nval_del(char *xb, int xb_size, const YCHAR *name);
18881 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
18882 +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
18883 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
18884 +int nval_hasvalues(const char *xb, int xb_size);
18885 +#endif
18886 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.c
18887 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.c 2010-10-20 13:17:58.959000294 +0300
18888 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.c 2010-10-20 13:28:16.029000294 +0300
18889 @@ -1,7 +1,7 @@
18890 /*
18891 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
18892 *
18893 - * Copyright (C) 2002-2007 Aleph One Ltd.
18894 + * Copyright (C) 2002-2010 Aleph One Ltd.
18895 * for Toby Churchill Ltd and Brightstar Engineering
18896 *
18897 * Created by Charles Manning <charles@aleph1.co.uk>
18898 @@ -11,124 +11,129 @@
18899 * published by the Free Software Foundation.
18900 */
18901
18902 -const char *yaffs_nand_c_version =
18903 - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
18904 -
18905 #include "yaffs_nand.h"
18906 #include "yaffs_tagscompat.h"
18907 #include "yaffs_tagsvalidity.h"
18908
18909 #include "yaffs_getblockinfo.h"
18910
18911 -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
18912 +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
18913 __u8 *buffer,
18914 - yaffs_ExtendedTags *tags)
18915 + yaffs_ext_tags *tags)
18916 {
18917 int result;
18918 - yaffs_ExtendedTags localTags;
18919 + yaffs_ext_tags localTags;
18920 +
18921 + int realignedChunkInNAND = nand_chunk - dev->chunk_offset;
18922
18923 - int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
18924 + dev->n_page_reads++;
18925
18926 /* If there are no tags provided, use local tags to get prioritised gc working */
18927 if (!tags)
18928 tags = &localTags;
18929
18930 - if (dev->readChunkWithTagsFromNAND)
18931 - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
18932 + if (dev->param.read_chunk_tags_fn)
18933 + result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer,
18934 tags);
18935 else
18936 - result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
18937 + result = yaffs_tags_compat_rd(dev,
18938 realignedChunkInNAND,
18939 buffer,
18940 tags);
18941 if (tags &&
18942 - tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
18943 + tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
18944
18945 - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
18946 - yaffs_HandleChunkError(dev, bi);
18947 + yaffs_block_info_t *bi;
18948 + bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block);
18949 + yaffs_handle_chunk_error(dev, bi);
18950 }
18951
18952 return result;
18953 }
18954
18955 -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
18956 - int chunkInNAND,
18957 +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
18958 + int nand_chunk,
18959 const __u8 *buffer,
18960 - yaffs_ExtendedTags *tags)
18961 + yaffs_ext_tags *tags)
18962 {
18963 - chunkInNAND -= dev->chunkOffset;
18964 +
18965 + dev->n_page_writes++;
18966 +
18967 + nand_chunk -= dev->chunk_offset;
18968
18969
18970 if (tags) {
18971 - tags->sequenceNumber = dev->sequenceNumber;
18972 - tags->chunkUsed = 1;
18973 - if (!yaffs_ValidateTags(tags)) {
18974 + tags->seq_number = dev->seq_number;
18975 + tags->chunk_used = 1;
18976 + if (!yaffs_validate_tags(tags)) {
18977 T(YAFFS_TRACE_ERROR,
18978 (TSTR("Writing uninitialised tags" TENDSTR)));
18979 YBUG();
18980 }
18981 T(YAFFS_TRACE_WRITE,
18982 - (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
18983 - tags->objectId, tags->chunkId));
18984 + (TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
18985 + tags->obj_id, tags->chunk_id));
18986 } else {
18987 T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
18988 YBUG();
18989 }
18990
18991 - if (dev->writeChunkWithTagsToNAND)
18992 - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
18993 + if (dev->param.write_chunk_tags_fn)
18994 + return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
18995 tags);
18996 else
18997 - return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
18998 - chunkInNAND,
18999 + return yaffs_tags_compat_wr(dev,
19000 + nand_chunk,
19001 buffer,
19002 tags);
19003 }
19004
19005 -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
19006 +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no)
19007 {
19008 - blockNo -= dev->blockOffset;
19009 + block_no -= dev->block_offset;
19010 +
19011
19012 -;
19013 - if (dev->markNANDBlockBad)
19014 - return dev->markNANDBlockBad(dev, blockNo);
19015 + if (dev->param.bad_block_fn)
19016 + return dev->param.bad_block_fn(dev, block_no);
19017 else
19018 - return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
19019 + return yaffs_tags_compat_mark_bad(dev, block_no);
19020 }
19021
19022 -int yaffs_QueryInitialBlockState(yaffs_Device *dev,
19023 - int blockNo,
19024 - yaffs_BlockState *state,
19025 - __u32 *sequenceNumber)
19026 +int yaffs_query_init_block_state(yaffs_dev_t *dev,
19027 + int block_no,
19028 + yaffs_block_state_t *state,
19029 + __u32 *seq_number)
19030 {
19031 - blockNo -= dev->blockOffset;
19032 + block_no -= dev->block_offset;
19033
19034 - if (dev->queryNANDBlock)
19035 - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
19036 + if (dev->param.query_block_fn)
19037 + return dev->param.query_block_fn(dev, block_no, state, seq_number);
19038 else
19039 - return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
19040 + return yaffs_tags_compat_query_block(dev, block_no,
19041 state,
19042 - sequenceNumber);
19043 + seq_number);
19044 }
19045
19046
19047 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19048 - int blockInNAND)
19049 +int yaffs_erase_block(struct yaffs_dev_s *dev,
19050 + int flash_block)
19051 {
19052 int result;
19053
19054 - blockInNAND -= dev->blockOffset;
19055 + flash_block -= dev->block_offset;
19056
19057 + dev->n_erasures++;
19058
19059 - dev->nBlockErasures++;
19060 - result = dev->eraseBlockInNAND(dev, blockInNAND);
19061 + result = dev->param.erase_fn(dev, flash_block);
19062
19063 return result;
19064 }
19065
19066 -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
19067 +int yaffs_init_nand(struct yaffs_dev_s *dev)
19068 {
19069 - return dev->initialiseNAND(dev);
19070 + if(dev->param.initialise_flash_fn)
19071 + return dev->param.initialise_flash_fn(dev);
19072 + return YAFFS_OK;
19073 }
19074
19075
19076 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nandemul2k.h
19077 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nandemul2k.h 2010-10-20 13:17:58.959000294 +0300
19078 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nandemul2k.h 2010-10-20 13:28:16.063000294 +0300
19079 @@ -1,7 +1,7 @@
19080 /*
19081 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19082 *
19083 - * Copyright (C) 2002-2007 Aleph One Ltd.
19084 + * Copyright (C) 2002-2010 Aleph One Ltd.
19085 * for Toby Churchill Ltd and Brightstar Engineering
19086 *
19087 * Created by Charles Manning <charles@aleph1.co.uk>
19088 @@ -20,18 +20,18 @@
19089
19090 #include "yaffs_guts.h"
19091
19092 -int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
19093 - int chunkInNAND, const __u8 *data,
19094 - const yaffs_ExtendedTags *tags);
19095 -int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
19096 - int chunkInNAND, __u8 *data,
19097 - yaffs_ExtendedTags *tags);
19098 -int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
19099 -int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
19100 - yaffs_BlockState *state, __u32 *sequenceNumber);
19101 -int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19102 - int blockInNAND);
19103 -int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
19104 +int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev,
19105 + int nand_chunk, const __u8 *data,
19106 + const yaffs_ext_tags *tags);
19107 +int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev,
19108 + int nand_chunk, __u8 *data,
19109 + yaffs_ext_tags *tags);
19110 +int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
19111 +int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
19112 + yaffs_block_state_t *state, __u32 *seq_number);
19113 +int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev,
19114 + int flash_block);
19115 +int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev);
19116 int nandemul2k_GetBytesPerChunk(void);
19117 int nandemul2k_GetChunksPerBlock(void);
19118 int nandemul2k_GetNumberOfBlocks(void);
19119 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.h
19120 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_nand.h 2010-10-20 13:17:58.959000294 +0300
19121 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_nand.h 2010-10-20 13:28:16.063000294 +0300
19122 @@ -1,7 +1,7 @@
19123 /*
19124 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19125 *
19126 - * Copyright (C) 2002-2007 Aleph One Ltd.
19127 + * Copyright (C) 2002-2010 Aleph One Ltd.
19128 * for Toby Churchill Ltd and Brightstar Engineering
19129 *
19130 * Created by Charles Manning <charles@aleph1.co.uk>
19131 @@ -19,26 +19,26 @@
19132
19133
19134
19135 -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
19136 +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
19137 __u8 *buffer,
19138 - yaffs_ExtendedTags *tags);
19139 + yaffs_ext_tags *tags);
19140
19141 -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
19142 - int chunkInNAND,
19143 +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
19144 + int nand_chunk,
19145 const __u8 *buffer,
19146 - yaffs_ExtendedTags *tags);
19147 + yaffs_ext_tags *tags);
19148
19149 -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
19150 +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no);
19151
19152 -int yaffs_QueryInitialBlockState(yaffs_Device *dev,
19153 - int blockNo,
19154 - yaffs_BlockState *state,
19155 - unsigned *sequenceNumber);
19156 +int yaffs_query_init_block_state(yaffs_dev_t *dev,
19157 + int block_no,
19158 + yaffs_block_state_t *state,
19159 + unsigned *seq_number);
19160
19161 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
19162 - int blockInNAND);
19163 +int yaffs_erase_block(struct yaffs_dev_s *dev,
19164 + int flash_block);
19165
19166 -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
19167 +int yaffs_init_nand(struct yaffs_dev_s *dev);
19168
19169 #endif
19170
19171 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.c
19172 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.c 2010-10-20 13:17:58.959000294 +0300
19173 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.c 2010-10-20 13:28:16.029000294 +0300
19174 @@ -1,7 +1,7 @@
19175 /*
19176 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19177 *
19178 - * Copyright (C) 2002-2007 Aleph One Ltd.
19179 + * Copyright (C) 2002-2010 Aleph One Ltd.
19180 * for Toby Churchill Ltd and Brightstar Engineering
19181 *
19182 * Created by Charles Manning <charles@aleph1.co.uk>
19183 @@ -14,37 +14,37 @@
19184 #include "yaffs_packedtags1.h"
19185 #include "yportenv.h"
19186
19187 -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
19188 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t)
19189 {
19190 - pt->chunkId = t->chunkId;
19191 - pt->serialNumber = t->serialNumber;
19192 - pt->byteCount = t->byteCount;
19193 - pt->objectId = t->objectId;
19194 + pt->chunk_id = t->chunk_id;
19195 + pt->serial_number = t->serial_number;
19196 + pt->n_bytes = t->n_bytes;
19197 + pt->obj_id = t->obj_id;
19198 pt->ecc = 0;
19199 - pt->deleted = (t->chunkDeleted) ? 0 : 1;
19200 + pt->deleted = (t->is_deleted) ? 0 : 1;
19201 pt->unusedStuff = 0;
19202 pt->shouldBeFF = 0xFFFFFFFF;
19203
19204 }
19205
19206 -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
19207 +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt)
19208 {
19209 static const __u8 allFF[] =
19210 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
19211 0xff };
19212
19213 if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
19214 - t->blockBad = 0;
19215 + t->block_bad = 0;
19216 if (pt->shouldBeFF != 0xFFFFFFFF)
19217 - t->blockBad = 1;
19218 - t->chunkUsed = 1;
19219 - t->objectId = pt->objectId;
19220 - t->chunkId = pt->chunkId;
19221 - t->byteCount = pt->byteCount;
19222 - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19223 - t->chunkDeleted = (pt->deleted) ? 0 : 1;
19224 - t->serialNumber = pt->serialNumber;
19225 + t->block_bad = 1;
19226 + t->chunk_used = 1;
19227 + t->obj_id = pt->obj_id;
19228 + t->chunk_id = pt->chunk_id;
19229 + t->n_bytes = pt->n_bytes;
19230 + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19231 + t->is_deleted = (pt->deleted) ? 0 : 1;
19232 + t->serial_number = pt->serial_number;
19233 } else {
19234 - memset(t, 0, sizeof(yaffs_ExtendedTags));
19235 + memset(t, 0, sizeof(yaffs_ext_tags));
19236 }
19237 }
19238 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.h
19239 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags1.h 2010-10-20 13:17:58.960000294 +0300
19240 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags1.h 2010-10-20 13:28:16.063000294 +0300
19241 @@ -1,7 +1,7 @@
19242 /*
19243 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19244 *
19245 - * Copyright (C) 2002-2007 Aleph One Ltd.
19246 + * Copyright (C) 2002-2010 Aleph One Ltd.
19247 * for Toby Churchill Ltd and Brightstar Engineering
19248 *
19249 * Created by Charles Manning <charles@aleph1.co.uk>
19250 @@ -21,10 +21,10 @@
19251 #include "yaffs_guts.h"
19252
19253 typedef struct {
19254 - unsigned chunkId:20;
19255 - unsigned serialNumber:2;
19256 - unsigned byteCount:10;
19257 - unsigned objectId:18;
19258 + unsigned chunk_id:20;
19259 + unsigned serial_number:2;
19260 + unsigned n_bytes:10;
19261 + unsigned obj_id:18;
19262 unsigned ecc:12;
19263 unsigned deleted:1;
19264 unsigned unusedStuff:1;
19265 @@ -32,6 +32,6 @@ typedef struct {
19266
19267 } yaffs_PackedTags1;
19268
19269 -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
19270 -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
19271 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t);
19272 +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt);
19273 #endif
19274 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.c
19275 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.c 2010-10-20 13:17:58.960000294 +0300
19276 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.c 2010-10-20 13:28:16.029000294 +0300
19277 @@ -1,7 +1,7 @@
19278 /*
19279 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19280 *
19281 - * Copyright (C) 2002-2007 Aleph One Ltd.
19282 + * Copyright (C) 2002-2010 Aleph One Ltd.
19283 * for Toby Churchill Ltd and Brightstar Engineering
19284 *
19285 * Created by Charles Manning <charles@aleph1.co.uk>
19286 @@ -13,6 +13,7 @@
19287
19288 #include "yaffs_packedtags2.h"
19289 #include "yportenv.h"
19290 +#include "yaffs_trace.h"
19291 #include "yaffs_tagsvalidity.h"
19292
19293 /* This code packs a set of extended tags into a binary structure for
19294 @@ -24,7 +25,7 @@
19295 * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
19296 */
19297
19298 -/* Extra flags applied to chunkId */
19299 +/* Extra flags applied to chunk_id */
19300
19301 #define EXTRA_HEADER_INFO_FLAG 0x80000000
19302 #define EXTRA_SHRINK_FLAG 0x40000000
19303 @@ -42,53 +43,53 @@ static void yaffs_DumpPackedTags2TagsPar
19304 {
19305 T(YAFFS_TRACE_MTD,
19306 (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
19307 - ptt->objectId, ptt->chunkId, ptt->byteCount,
19308 - ptt->sequenceNumber));
19309 + ptt->obj_id, ptt->chunk_id, ptt->n_bytes,
19310 + ptt->seq_number));
19311 }
19312 static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
19313 {
19314 yaffs_DumpPackedTags2TagsPart(&pt->t);
19315 }
19316
19317 -static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
19318 +static void yaffs_DumpTags2(const yaffs_ext_tags *t)
19319 {
19320 T(YAFFS_TRACE_MTD,
19321 (TSTR
19322 ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
19323 - TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
19324 - t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
19325 - t->sequenceNumber));
19326 + TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
19327 + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
19328 + t->seq_number));
19329
19330 }
19331
19332 void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
19333 - const yaffs_ExtendedTags *t)
19334 + const yaffs_ext_tags *t)
19335 {
19336 - ptt->chunkId = t->chunkId;
19337 - ptt->sequenceNumber = t->sequenceNumber;
19338 - ptt->byteCount = t->byteCount;
19339 - ptt->objectId = t->objectId;
19340 + ptt->chunk_id = t->chunk_id;
19341 + ptt->seq_number = t->seq_number;
19342 + ptt->n_bytes = t->n_bytes;
19343 + ptt->obj_id = t->obj_id;
19344
19345 - if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
19346 + if (t->chunk_id == 0 && t->extra_available) {
19347 /* Store the extra header info instead */
19348 - /* We save the parent object in the chunkId */
19349 - ptt->chunkId = EXTRA_HEADER_INFO_FLAG
19350 - | t->extraParentObjectId;
19351 - if (t->extraIsShrinkHeader)
19352 - ptt->chunkId |= EXTRA_SHRINK_FLAG;
19353 - if (t->extraShadows)
19354 - ptt->chunkId |= EXTRA_SHADOWS_FLAG;
19355 -
19356 - ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
19357 - ptt->objectId |=
19358 - (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
19359 -
19360 - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
19361 - ptt->byteCount = t->extraEquivalentObjectId;
19362 - else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
19363 - ptt->byteCount = t->extraFileLength;
19364 + /* We save the parent object in the chunk_id */
19365 + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG
19366 + | t->extra_parent_id;
19367 + if (t->extra_is_shrink)
19368 + ptt->chunk_id |= EXTRA_SHRINK_FLAG;
19369 + if (t->extra_shadows)
19370 + ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
19371 +
19372 + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
19373 + ptt->obj_id |=
19374 + (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
19375 +
19376 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
19377 + ptt->n_bytes = t->extra_equiv_id;
19378 + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
19379 + ptt->n_bytes = t->extra_length;
19380 else
19381 - ptt->byteCount = 0;
19382 + ptt->n_bytes = 0;
19383 }
19384
19385 yaffs_DumpPackedTags2TagsPart(ptt);
19386 @@ -96,59 +97,56 @@ void yaffs_PackTags2TagsPart(yaffs_Packe
19387 }
19388
19389
19390 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
19391 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC)
19392 {
19393 yaffs_PackTags2TagsPart(&pt->t, t);
19394
19395 -#ifndef YAFFS_IGNORE_TAGS_ECC
19396 - {
19397 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
19398 + if(tagsECC)
19399 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
19400 sizeof(yaffs_PackedTags2TagsPart),
19401 &pt->ecc);
19402 - }
19403 -#endif
19404 }
19405
19406
19407 -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
19408 +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t,
19409 yaffs_PackedTags2TagsPart *ptt)
19410 {
19411
19412 - memset(t, 0, sizeof(yaffs_ExtendedTags));
19413 + memset(t, 0, sizeof(yaffs_ext_tags));
19414
19415 - yaffs_InitialiseTags(t);
19416 + yaffs_init_tags(t);
19417
19418 - if (ptt->sequenceNumber != 0xFFFFFFFF) {
19419 - t->blockBad = 0;
19420 - t->chunkUsed = 1;
19421 - t->objectId = ptt->objectId;
19422 - t->chunkId = ptt->chunkId;
19423 - t->byteCount = ptt->byteCount;
19424 - t->chunkDeleted = 0;
19425 - t->serialNumber = 0;
19426 - t->sequenceNumber = ptt->sequenceNumber;
19427 + if (ptt->seq_number != 0xFFFFFFFF) {
19428 + t->block_bad = 0;
19429 + t->chunk_used = 1;
19430 + t->obj_id = ptt->obj_id;
19431 + t->chunk_id = ptt->chunk_id;
19432 + t->n_bytes = ptt->n_bytes;
19433 + t->is_deleted = 0;
19434 + t->serial_number = 0;
19435 + t->seq_number = ptt->seq_number;
19436
19437 /* Do extra header info stuff */
19438
19439 - if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
19440 - t->chunkId = 0;
19441 - t->byteCount = 0;
19442 -
19443 - t->extraHeaderInfoAvailable = 1;
19444 - t->extraParentObjectId =
19445 - ptt->chunkId & (~(ALL_EXTRA_FLAGS));
19446 - t->extraIsShrinkHeader =
19447 - (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
19448 - t->extraShadows =
19449 - (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
19450 - t->extraObjectType =
19451 - ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
19452 - t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
19453 + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
19454 + t->chunk_id = 0;
19455 + t->n_bytes = 0;
19456 +
19457 + t->extra_available = 1;
19458 + t->extra_parent_id =
19459 + ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
19460 + t->extra_is_shrink =
19461 + (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
19462 + t->extra_shadows =
19463 + (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
19464 + t->extra_obj_type =
19465 + ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
19466 + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
19467
19468 - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
19469 - t->extraEquivalentObjectId = ptt->byteCount;
19470 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
19471 + t->extra_equiv_id = ptt->n_bytes;
19472 else
19473 - t->extraFileLength = ptt->byteCount;
19474 + t->extra_length = ptt->n_bytes;
19475 }
19476 }
19477
19478 @@ -158,49 +156,43 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext
19479 }
19480
19481
19482 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
19483 +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC)
19484 {
19485
19486 - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19487 + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19488
19489 - if (pt->t.sequenceNumber != 0xFFFFFFFF) {
19490 - /* Page is in use */
19491 -#ifndef YAFFS_IGNORE_TAGS_ECC
19492 - {
19493 - yaffs_ECCOther ecc;
19494 - int result;
19495 - yaffs_ECCCalculateOther((unsigned char *)&pt->t,
19496 - sizeof
19497 - (yaffs_PackedTags2TagsPart),
19498 - &ecc);
19499 - result =
19500 - yaffs_ECCCorrectOther((unsigned char *)&pt->t,
19501 - sizeof
19502 - (yaffs_PackedTags2TagsPart),
19503 - &pt->ecc, &ecc);
19504 - switch (result) {
19505 + if (pt->t.seq_number != 0xFFFFFFFF &&
19506 + tagsECC){
19507 + /* Chunk is in use and we need to do ECC */
19508 +
19509 + yaffs_ECCOther ecc;
19510 + int result;
19511 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
19512 + sizeof(yaffs_PackedTags2TagsPart),
19513 + &ecc);
19514 + result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
19515 + sizeof(yaffs_PackedTags2TagsPart),
19516 + &pt->ecc, &ecc);
19517 + switch (result) {
19518 case 0:
19519 - eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19520 + ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19521 break;
19522 case 1:
19523 - eccResult = YAFFS_ECC_RESULT_FIXED;
19524 + ecc_result = YAFFS_ECC_RESULT_FIXED;
19525 break;
19526 case -1:
19527 - eccResult = YAFFS_ECC_RESULT_UNFIXED;
19528 + ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19529 break;
19530 default:
19531 - eccResult = YAFFS_ECC_RESULT_UNKNOWN;
19532 - }
19533 + ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
19534 }
19535 -#endif
19536 }
19537
19538 - yaffs_UnpackTags2TagsPart(t, &pt->t);
19539 + yaffs_unpack_tags2tags_part(t, &pt->t);
19540
19541 - t->eccResult = eccResult;
19542 + t->ecc_result = ecc_result;
19543
19544 yaffs_DumpPackedTags2(pt);
19545 yaffs_DumpTags2(t);
19546 -
19547 }
19548
19549 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.h
19550 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_packedtags2.h 2010-10-20 13:17:58.960000294 +0300
19551 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_packedtags2.h 2010-10-20 13:28:16.063000294 +0300
19552 @@ -1,7 +1,7 @@
19553 /*
19554 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19555 *
19556 - * Copyright (C) 2002-2007 Aleph One Ltd.
19557 + * Copyright (C) 2002-2010 Aleph One Ltd.
19558 * for Toby Churchill Ltd and Brightstar Engineering
19559 *
19560 * Created by Charles Manning <charles@aleph1.co.uk>
19561 @@ -22,10 +22,10 @@
19562 #include "yaffs_ecc.h"
19563
19564 typedef struct {
19565 - unsigned sequenceNumber;
19566 - unsigned objectId;
19567 - unsigned chunkId;
19568 - unsigned byteCount;
19569 + unsigned seq_number;
19570 + unsigned obj_id;
19571 + unsigned chunk_id;
19572 + unsigned n_bytes;
19573 } yaffs_PackedTags2TagsPart;
19574
19575 typedef struct {
19576 @@ -34,10 +34,10 @@ typedef struct {
19577 } yaffs_PackedTags2;
19578
19579 /* Full packed tags with ECC, used for oob tags */
19580 -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
19581 -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
19582 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC);
19583 +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC);
19584
19585 /* Only the tags part (no ECC for use with inband tags */
19586 -void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
19587 -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
19588 +void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t);
19589 +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt);
19590 #endif
19591 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_qsort.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_qsort.h
19592 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_qsort.h 2010-10-20 13:17:58.961000294 +0300
19593 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_qsort.h 2010-10-20 13:28:16.063000294 +0300
19594 @@ -1,7 +1,7 @@
19595 /*
19596 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
19597 *
19598 - * Copyright (C) 2002-2007 Aleph One Ltd.
19599 + * Copyright (C) 2002-2010 Aleph One Ltd.
19600 * for Toby Churchill Ltd and Brightstar Engineering
19601 *
19602 * Created by Charles Manning <charles@aleph1.co.uk>
19603 @@ -17,7 +17,18 @@
19604 #ifndef __YAFFS_QSORT_H__
19605 #define __YAFFS_QSORT_H__
19606
19607 +#ifdef __KERNEL__
19608 +#include <linux/sort.h>
19609 +
19610 +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
19611 + int (*cmp)(const void *, const void *)){
19612 + sort(base, total_elems, size, cmp, NULL);
19613 +}
19614 +
19615 +#else
19616 +
19617 extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
19618 int (*cmp)(const void *, const void *));
19619
19620 #endif
19621 +#endif
19622 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.c
19623 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.c 2010-10-20 13:17:58.961000294 +0300
19624 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.c 2010-10-20 13:28:16.030000294 +0300
19625 @@ -1,7 +1,7 @@
19626 /*
19627 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
19628 *
19629 - * Copyright (C) 2002-2007 Aleph One Ltd.
19630 + * Copyright (C) 2002-2010 Aleph One Ltd.
19631 * for Toby Churchill Ltd and Brightstar Engineering
19632 *
19633 * Created by Charles Manning <charles@aleph1.co.uk>
19634 @@ -15,19 +15,20 @@
19635 #include "yaffs_tagscompat.h"
19636 #include "yaffs_ecc.h"
19637 #include "yaffs_getblockinfo.h"
19638 +#include "yaffs_trace.h"
19639
19640 -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
19641 +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk);
19642 #ifdef NOTYET
19643 -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
19644 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
19645 +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk);
19646 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
19647 const __u8 *data,
19648 - const yaffs_Spare *spare);
19649 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
19650 - const yaffs_Spare *spare);
19651 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
19652 + const yaffs_spare *spare);
19653 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
19654 + const yaffs_spare *spare);
19655 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk);
19656 #endif
19657
19658 -static const char yaffs_countBitsTable[256] = {
19659 +static const char yaffs_count_bits_table[256] = {
19660 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
19661 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
19662 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
19663 @@ -46,26 +47,26 @@ static const char yaffs_countBitsTable[2
19664 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
19665 };
19666
19667 -int yaffs_CountBits(__u8 x)
19668 +int yaffs_count_bits(__u8 x)
19669 {
19670 int retVal;
19671 - retVal = yaffs_countBitsTable[x];
19672 + retVal = yaffs_count_bits_table[x];
19673 return retVal;
19674 }
19675
19676 /********** Tags ECC calculations *********/
19677
19678 -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
19679 +void yaffs_calc_ecc(const __u8 *data, yaffs_spare *spare)
19680 {
19681 - yaffs_ECCCalculate(data, spare->ecc1);
19682 - yaffs_ECCCalculate(&data[256], spare->ecc2);
19683 + yaffs_ecc_cacl(data, spare->ecc1);
19684 + yaffs_ecc_cacl(&data[256], spare->ecc2);
19685 }
19686
19687 -void yaffs_CalcTagsECC(yaffs_Tags *tags)
19688 +void yaffs_calc_tags_ecc(yaffs_tags_t *tags)
19689 {
19690 /* Calculate an ecc */
19691
19692 - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
19693 + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
19694 unsigned i, j;
19695 unsigned ecc = 0;
19696 unsigned bit = 0;
19697 @@ -84,24 +85,24 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
19698
19699 }
19700
19701 -int yaffs_CheckECCOnTags(yaffs_Tags *tags)
19702 +int yaffs_check_tags_ecc(yaffs_tags_t *tags)
19703 {
19704 unsigned ecc = tags->ecc;
19705
19706 - yaffs_CalcTagsECC(tags);
19707 + yaffs_calc_tags_ecc(tags);
19708
19709 ecc ^= tags->ecc;
19710
19711 if (ecc && ecc <= 64) {
19712 /* TODO: Handle the failure better. Retire? */
19713 - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
19714 + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
19715
19716 ecc--;
19717
19718 b[ecc / 8] ^= (1 << (ecc & 7));
19719
19720 /* Now recvalc the ecc */
19721 - yaffs_CalcTagsECC(tags);
19722 + yaffs_calc_tags_ecc(tags);
19723
19724 return 1; /* recovered error */
19725 } else if (ecc) {
19726 @@ -115,76 +116,73 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tag
19727
19728 /********** Tags **********/
19729
19730 -static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
19731 - yaffs_Tags *tagsPtr)
19732 +static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr,
19733 + yaffs_tags_t *tagsPtr)
19734 {
19735 - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
19736 + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
19737
19738 - yaffs_CalcTagsECC(tagsPtr);
19739 + yaffs_calc_tags_ecc(tagsPtr);
19740
19741 - sparePtr->tagByte0 = tu->asBytes[0];
19742 - sparePtr->tagByte1 = tu->asBytes[1];
19743 - sparePtr->tagByte2 = tu->asBytes[2];
19744 - sparePtr->tagByte3 = tu->asBytes[3];
19745 - sparePtr->tagByte4 = tu->asBytes[4];
19746 - sparePtr->tagByte5 = tu->asBytes[5];
19747 - sparePtr->tagByte6 = tu->asBytes[6];
19748 - sparePtr->tagByte7 = tu->asBytes[7];
19749 + sparePtr->tb0 = tu->as_bytes[0];
19750 + sparePtr->tb1 = tu->as_bytes[1];
19751 + sparePtr->tb2 = tu->as_bytes[2];
19752 + sparePtr->tb3 = tu->as_bytes[3];
19753 + sparePtr->tb4 = tu->as_bytes[4];
19754 + sparePtr->tb5 = tu->as_bytes[5];
19755 + sparePtr->tb6 = tu->as_bytes[6];
19756 + sparePtr->tb7 = tu->as_bytes[7];
19757 }
19758
19759 -static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
19760 - yaffs_Tags *tagsPtr)
19761 +static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr,
19762 + yaffs_tags_t *tagsPtr)
19763 {
19764 - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
19765 + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
19766 int result;
19767
19768 - tu->asBytes[0] = sparePtr->tagByte0;
19769 - tu->asBytes[1] = sparePtr->tagByte1;
19770 - tu->asBytes[2] = sparePtr->tagByte2;
19771 - tu->asBytes[3] = sparePtr->tagByte3;
19772 - tu->asBytes[4] = sparePtr->tagByte4;
19773 - tu->asBytes[5] = sparePtr->tagByte5;
19774 - tu->asBytes[6] = sparePtr->tagByte6;
19775 - tu->asBytes[7] = sparePtr->tagByte7;
19776 + tu->as_bytes[0] = sparePtr->tb0;
19777 + tu->as_bytes[1] = sparePtr->tb1;
19778 + tu->as_bytes[2] = sparePtr->tb2;
19779 + tu->as_bytes[3] = sparePtr->tb3;
19780 + tu->as_bytes[4] = sparePtr->tb4;
19781 + tu->as_bytes[5] = sparePtr->tb5;
19782 + tu->as_bytes[6] = sparePtr->tb6;
19783 + tu->as_bytes[7] = sparePtr->tb7;
19784
19785 - result = yaffs_CheckECCOnTags(tagsPtr);
19786 + result = yaffs_check_tags_ecc(tagsPtr);
19787 if (result > 0)
19788 - dev->tagsEccFixed++;
19789 + dev->n_tags_ecc_fixed++;
19790 else if (result < 0)
19791 - dev->tagsEccUnfixed++;
19792 + dev->n_tags_ecc_unfixed++;
19793 }
19794
19795 -static void yaffs_SpareInitialise(yaffs_Spare *spare)
19796 +static void yaffs_spare_init(yaffs_spare *spare)
19797 {
19798 - memset(spare, 0xFF, sizeof(yaffs_Spare));
19799 + memset(spare, 0xFF, sizeof(yaffs_spare));
19800 }
19801
19802 -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
19803 - int chunkInNAND, const __u8 *data,
19804 - yaffs_Spare *spare)
19805 +static int yaffs_wr_nand(struct yaffs_dev_s *dev,
19806 + int nand_chunk, const __u8 *data,
19807 + yaffs_spare *spare)
19808 {
19809 - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
19810 + if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
19811 T(YAFFS_TRACE_ERROR,
19812 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
19813 - chunkInNAND));
19814 + nand_chunk));
19815 return YAFFS_FAIL;
19816 }
19817
19818 - dev->nPageWrites++;
19819 - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
19820 + return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
19821 }
19822
19823 -static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
19824 - int chunkInNAND,
19825 +static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev,
19826 + int nand_chunk,
19827 __u8 *data,
19828 - yaffs_Spare *spare,
19829 - yaffs_ECCResult *eccResult,
19830 + yaffs_spare *spare,
19831 + yaffs_ecc_result *ecc_result,
19832 int doErrorCorrection)
19833 {
19834 int retVal;
19835 - yaffs_Spare localSpare;
19836 -
19837 - dev->nPageReads++;
19838 + yaffs_spare localSpare;
19839
19840 if (!spare && data) {
19841 /* If we don't have a real spare, then we use a local one. */
19842 @@ -192,107 +190,107 @@ static int yaffs_ReadChunkFromNAND(struc
19843 spare = &localSpare;
19844 }
19845
19846 - if (!dev->useNANDECC) {
19847 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
19848 + if (!dev->param.use_nand_ecc) {
19849 + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
19850 if (data && doErrorCorrection) {
19851 /* Do ECC correction */
19852 /* Todo handle any errors */
19853 - int eccResult1, eccResult2;
19854 + int ecc_result1, ecc_result2;
19855 __u8 calcEcc[3];
19856
19857 - yaffs_ECCCalculate(data, calcEcc);
19858 - eccResult1 =
19859 - yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
19860 - yaffs_ECCCalculate(&data[256], calcEcc);
19861 - eccResult2 =
19862 - yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
19863 + yaffs_ecc_cacl(data, calcEcc);
19864 + ecc_result1 =
19865 + yaffs_ecc_correct(data, spare->ecc1, calcEcc);
19866 + yaffs_ecc_cacl(&data[256], calcEcc);
19867 + ecc_result2 =
19868 + yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc);
19869
19870 - if (eccResult1 > 0) {
19871 + if (ecc_result1 > 0) {
19872 T(YAFFS_TRACE_ERROR,
19873 (TSTR
19874 ("**>>yaffs ecc error fix performed on chunk %d:0"
19875 - TENDSTR), chunkInNAND));
19876 - dev->eccFixed++;
19877 - } else if (eccResult1 < 0) {
19878 + TENDSTR), nand_chunk));
19879 + dev->n_ecc_fixed++;
19880 + } else if (ecc_result1 < 0) {
19881 T(YAFFS_TRACE_ERROR,
19882 (TSTR
19883 ("**>>yaffs ecc error unfixed on chunk %d:0"
19884 - TENDSTR), chunkInNAND));
19885 - dev->eccUnfixed++;
19886 + TENDSTR), nand_chunk));
19887 + dev->n_ecc_unfixed++;
19888 }
19889
19890 - if (eccResult2 > 0) {
19891 + if (ecc_result2 > 0) {
19892 T(YAFFS_TRACE_ERROR,
19893 (TSTR
19894 ("**>>yaffs ecc error fix performed on chunk %d:1"
19895 - TENDSTR), chunkInNAND));
19896 - dev->eccFixed++;
19897 - } else if (eccResult2 < 0) {
19898 + TENDSTR), nand_chunk));
19899 + dev->n_ecc_fixed++;
19900 + } else if (ecc_result2 < 0) {
19901 T(YAFFS_TRACE_ERROR,
19902 (TSTR
19903 ("**>>yaffs ecc error unfixed on chunk %d:1"
19904 - TENDSTR), chunkInNAND));
19905 - dev->eccUnfixed++;
19906 + TENDSTR), nand_chunk));
19907 + dev->n_ecc_unfixed++;
19908 }
19909
19910 - if (eccResult1 || eccResult2) {
19911 + if (ecc_result1 || ecc_result2) {
19912 /* We had a data problem on this page */
19913 - yaffs_HandleReadDataError(dev, chunkInNAND);
19914 + yaffs_handle_rd_data_error(dev, nand_chunk);
19915 }
19916
19917 - if (eccResult1 < 0 || eccResult2 < 0)
19918 - *eccResult = YAFFS_ECC_RESULT_UNFIXED;
19919 - else if (eccResult1 > 0 || eccResult2 > 0)
19920 - *eccResult = YAFFS_ECC_RESULT_FIXED;
19921 + if (ecc_result1 < 0 || ecc_result2 < 0)
19922 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19923 + else if (ecc_result1 > 0 || ecc_result2 > 0)
19924 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
19925 else
19926 - *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19927 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19928 }
19929 } else {
19930 /* Must allocate enough memory for spare+2*sizeof(int) */
19931 /* for ecc results from device. */
19932 - struct yaffs_NANDSpare nspare;
19933 + struct yaffs_nand_spare nspare;
19934
19935 memset(&nspare, 0, sizeof(nspare));
19936
19937 - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
19938 - (yaffs_Spare *) &nspare);
19939 - memcpy(spare, &nspare, sizeof(yaffs_Spare));
19940 + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data,
19941 + (yaffs_spare *) &nspare);
19942 + memcpy(spare, &nspare, sizeof(yaffs_spare));
19943 if (data && doErrorCorrection) {
19944 if (nspare.eccres1 > 0) {
19945 T(YAFFS_TRACE_ERROR,
19946 (TSTR
19947 ("**>>mtd ecc error fix performed on chunk %d:0"
19948 - TENDSTR), chunkInNAND));
19949 + TENDSTR), nand_chunk));
19950 } else if (nspare.eccres1 < 0) {
19951 T(YAFFS_TRACE_ERROR,
19952 (TSTR
19953 ("**>>mtd ecc error unfixed on chunk %d:0"
19954 - TENDSTR), chunkInNAND));
19955 + TENDSTR), nand_chunk));
19956 }
19957
19958 if (nspare.eccres2 > 0) {
19959 T(YAFFS_TRACE_ERROR,
19960 (TSTR
19961 ("**>>mtd ecc error fix performed on chunk %d:1"
19962 - TENDSTR), chunkInNAND));
19963 + TENDSTR), nand_chunk));
19964 } else if (nspare.eccres2 < 0) {
19965 T(YAFFS_TRACE_ERROR,
19966 (TSTR
19967 ("**>>mtd ecc error unfixed on chunk %d:1"
19968 - TENDSTR), chunkInNAND));
19969 + TENDSTR), nand_chunk));
19970 }
19971
19972 if (nspare.eccres1 || nspare.eccres2) {
19973 /* We had a data problem on this page */
19974 - yaffs_HandleReadDataError(dev, chunkInNAND);
19975 + yaffs_handle_rd_data_error(dev, nand_chunk);
19976 }
19977
19978 if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
19979 - *eccResult = YAFFS_ECC_RESULT_UNFIXED;
19980 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
19981 else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
19982 - *eccResult = YAFFS_ECC_RESULT_FIXED;
19983 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
19984 else
19985 - *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
19986 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
19987
19988 }
19989 }
19990 @@ -300,17 +298,17 @@ static int yaffs_ReadChunkFromNAND(struc
19991 }
19992
19993 #ifdef NOTYET
19994 -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
19995 - int chunkInNAND)
19996 +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
19997 + int nand_chunk)
19998 {
19999 static int init;
20000 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
20001 static __u8 data[YAFFS_BYTES_PER_CHUNK];
20002 /* Might as well always allocate the larger size for */
20003 - /* dev->useNANDECC == true; */
20004 - static __u8 spare[sizeof(struct yaffs_NANDSpare)];
20005 + /* dev->param.use_nand_ecc == true; */
20006 + static __u8 spare[sizeof(struct yaffs_nand_spare)];
20007
20008 - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
20009 + dev->param.read_chunk_fn(dev, nand_chunk, data, (yaffs_spare *) spare);
20010
20011 if (!init) {
20012 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
20013 @@ -331,14 +329,14 @@ static int yaffs_CheckChunkErased(struct
20014 * Functions for robustisizing
20015 */
20016
20017 -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
20018 +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk)
20019 {
20020 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
20021 + int flash_block = nand_chunk / dev->param.chunks_per_block;
20022
20023 /* Mark the block for retirement */
20024 - yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
20025 + yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1;
20026 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
20027 - (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
20028 + (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
20029
20030 /* TODO:
20031 * Just do a garbage collection on the affected block
20032 @@ -348,44 +346,44 @@ static void yaffs_HandleReadDataError(ya
20033 }
20034
20035 #ifdef NOTYET
20036 -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
20037 +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk)
20038 {
20039 }
20040
20041 -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
20042 +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
20043 const __u8 *data,
20044 - const yaffs_Spare *spare)
20045 + const yaffs_spare *spare)
20046 {
20047 }
20048
20049 -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
20050 - const yaffs_Spare *spare)
20051 +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
20052 + const yaffs_spare *spare)
20053 {
20054 }
20055
20056 -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
20057 +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk)
20058 {
20059 - int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
20060 + int flash_block = nand_chunk / dev->param.chunks_per_block;
20061
20062 /* Mark the block for retirement */
20063 - yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
20064 + yaffs_get_block_info(dev, flash_block)->needs_retiring = 1;
20065 /* Delete the chunk */
20066 - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
20067 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
20068 }
20069
20070 -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
20071 - const yaffs_Spare *s0, const yaffs_Spare *s1)
20072 +static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1,
20073 + const yaffs_spare *s0, const yaffs_spare *s1)
20074 {
20075
20076 if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
20077 - s0->tagByte0 != s1->tagByte0 ||
20078 - s0->tagByte1 != s1->tagByte1 ||
20079 - s0->tagByte2 != s1->tagByte2 ||
20080 - s0->tagByte3 != s1->tagByte3 ||
20081 - s0->tagByte4 != s1->tagByte4 ||
20082 - s0->tagByte5 != s1->tagByte5 ||
20083 - s0->tagByte6 != s1->tagByte6 ||
20084 - s0->tagByte7 != s1->tagByte7 ||
20085 + s0->tb0 != s1->tb0 ||
20086 + s0->tb1 != s1->tb1 ||
20087 + s0->tb2 != s1->tb2 ||
20088 + s0->tb3 != s1->tb3 ||
20089 + s0->tb4 != s1->tb4 ||
20090 + s0->tb5 != s1->tb5 ||
20091 + s0->tb6 != s1->tb6 ||
20092 + s0->tb7 != s1->tb7 ||
20093 s0->ecc1[0] != s1->ecc1[0] ||
20094 s0->ecc1[1] != s1->ecc1[1] ||
20095 s0->ecc1[2] != s1->ecc1[2] ||
20096 @@ -398,53 +396,53 @@ static int yaffs_VerifyCompare(const __u
20097 }
20098 #endif /* NOTYET */
20099
20100 -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
20101 - int chunkInNAND,
20102 +int yaffs_tags_compat_wr(yaffs_dev_t *dev,
20103 + int nand_chunk,
20104 const __u8 *data,
20105 - const yaffs_ExtendedTags *eTags)
20106 + const yaffs_ext_tags *eTags)
20107 {
20108 - yaffs_Spare spare;
20109 - yaffs_Tags tags;
20110 + yaffs_spare spare;
20111 + yaffs_tags_t tags;
20112
20113 - yaffs_SpareInitialise(&spare);
20114 + yaffs_spare_init(&spare);
20115
20116 - if (eTags->chunkDeleted)
20117 - spare.pageStatus = 0;
20118 + if (eTags->is_deleted)
20119 + spare.page_status = 0;
20120 else {
20121 - tags.objectId = eTags->objectId;
20122 - tags.chunkId = eTags->chunkId;
20123 + tags.obj_id = eTags->obj_id;
20124 + tags.chunk_id = eTags->chunk_id;
20125
20126 - tags.byteCountLSB = eTags->byteCount & 0x3ff;
20127 + tags.n_bytes_lsb = eTags->n_bytes & 0x3ff;
20128
20129 - if (dev->nDataBytesPerChunk >= 1024)
20130 - tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
20131 + if (dev->data_bytes_per_chunk >= 1024)
20132 + tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3;
20133 else
20134 - tags.byteCountMSB = 3;
20135 + tags.n_bytes_msb = 3;
20136
20137
20138 - tags.serialNumber = eTags->serialNumber;
20139 + tags.serial_number = eTags->serial_number;
20140
20141 - if (!dev->useNANDECC && data)
20142 - yaffs_CalcECC(data, &spare);
20143 + if (!dev->param.use_nand_ecc && data)
20144 + yaffs_calc_ecc(data, &spare);
20145
20146 - yaffs_LoadTagsIntoSpare(&spare, &tags);
20147 + yaffs_load_tags_to_spare(&spare, &tags);
20148
20149 }
20150
20151 - return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
20152 + return yaffs_wr_nand(dev, nand_chunk, data, &spare);
20153 }
20154
20155 -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
20156 - int chunkInNAND,
20157 +int yaffs_tags_compat_rd(yaffs_dev_t *dev,
20158 + int nand_chunk,
20159 __u8 *data,
20160 - yaffs_ExtendedTags *eTags)
20161 + yaffs_ext_tags *eTags)
20162 {
20163
20164 - yaffs_Spare spare;
20165 - yaffs_Tags tags;
20166 - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
20167 + yaffs_spare spare;
20168 + yaffs_tags_t tags;
20169 + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
20170
20171 - static yaffs_Spare spareFF;
20172 + static yaffs_spare spareFF;
20173 static int init;
20174
20175 if (!init) {
20176 @@ -452,33 +450,33 @@ int yaffs_TagsCompatabilityReadChunkWith
20177 init = 1;
20178 }
20179
20180 - if (yaffs_ReadChunkFromNAND
20181 - (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
20182 + if (yaffs_rd_chunk_nand
20183 + (dev, nand_chunk, data, &spare, &ecc_result, 1)) {
20184 /* eTags may be NULL */
20185 if (eTags) {
20186
20187 int deleted =
20188 - (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
20189 + (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
20190
20191 - eTags->chunkDeleted = deleted;
20192 - eTags->eccResult = eccResult;
20193 - eTags->blockBad = 0; /* We're reading it */
20194 + eTags->is_deleted = deleted;
20195 + eTags->ecc_result = ecc_result;
20196 + eTags->block_bad = 0; /* We're reading it */
20197 /* therefore it is not a bad block */
20198 - eTags->chunkUsed =
20199 + eTags->chunk_used =
20200 (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
20201 0) ? 1 : 0;
20202
20203 - if (eTags->chunkUsed) {
20204 - yaffs_GetTagsFromSpare(dev, &spare, &tags);
20205 + if (eTags->chunk_used) {
20206 + yaffs_get_tags_from_spare(dev, &spare, &tags);
20207
20208 - eTags->objectId = tags.objectId;
20209 - eTags->chunkId = tags.chunkId;
20210 - eTags->byteCount = tags.byteCountLSB;
20211 + eTags->obj_id = tags.obj_id;
20212 + eTags->chunk_id = tags.chunk_id;
20213 + eTags->n_bytes = tags.n_bytes_lsb;
20214
20215 - if (dev->nDataBytesPerChunk >= 1024)
20216 - eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
20217 + if (dev->data_bytes_per_chunk >= 1024)
20218 + eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10);
20219
20220 - eTags->serialNumber = tags.serialNumber;
20221 + eTags->serial_number = tags.serial_number;
20222 }
20223 }
20224
20225 @@ -488,49 +486,49 @@ int yaffs_TagsCompatabilityReadChunkWith
20226 }
20227 }
20228
20229 -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
20230 - int blockInNAND)
20231 +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
20232 + int flash_block)
20233 {
20234
20235 - yaffs_Spare spare;
20236 + yaffs_spare spare;
20237
20238 - memset(&spare, 0xff, sizeof(yaffs_Spare));
20239 + memset(&spare, 0xff, sizeof(yaffs_spare));
20240
20241 - spare.blockStatus = 'Y';
20242 + spare.block_status = 'Y';
20243
20244 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
20245 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
20246 &spare);
20247 - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
20248 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
20249 NULL, &spare);
20250
20251 return YAFFS_OK;
20252
20253 }
20254
20255 -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
20256 - int blockNo,
20257 - yaffs_BlockState *state,
20258 - __u32 *sequenceNumber)
20259 +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
20260 + int block_no,
20261 + yaffs_block_state_t *state,
20262 + __u32 *seq_number)
20263 {
20264
20265 - yaffs_Spare spare0, spare1;
20266 - static yaffs_Spare spareFF;
20267 + yaffs_spare spare0, spare1;
20268 + static yaffs_spare spareFF;
20269 static int init;
20270 - yaffs_ECCResult dummy;
20271 + yaffs_ecc_result dummy;
20272
20273 if (!init) {
20274 memset(&spareFF, 0xFF, sizeof(spareFF));
20275 init = 1;
20276 }
20277
20278 - *sequenceNumber = 0;
20279 + *seq_number = 0;
20280
20281 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
20282 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
20283 &spare0, &dummy, 1);
20284 - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
20285 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL,
20286 &spare1, &dummy, 1);
20287
20288 - if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
20289 + if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7)
20290 *state = YAFFS_BLOCK_STATE_DEAD;
20291 else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
20292 *state = YAFFS_BLOCK_STATE_EMPTY;
20293 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.h
20294 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagscompat.h 2010-10-20 13:17:58.961000294 +0300
20295 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagscompat.h 2010-10-20 13:28:16.064000294 +0300
20296 @@ -1,7 +1,7 @@
20297 /*
20298 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20299 *
20300 - * Copyright (C) 2002-2007 Aleph One Ltd.
20301 + * Copyright (C) 2002-2010 Aleph One Ltd.
20302 * for Toby Churchill Ltd and Brightstar Engineering
20303 *
20304 * Created by Charles Manning <charles@aleph1.co.uk>
20305 @@ -17,23 +17,23 @@
20306 #define __YAFFS_TAGSCOMPAT_H__
20307
20308 #include "yaffs_guts.h"
20309 -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
20310 - int chunkInNAND,
20311 +int yaffs_tags_compat_wr(yaffs_dev_t *dev,
20312 + int nand_chunk,
20313 const __u8 *data,
20314 - const yaffs_ExtendedTags *tags);
20315 -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
20316 - int chunkInNAND,
20317 + const yaffs_ext_tags *tags);
20318 +int yaffs_tags_compat_rd(yaffs_dev_t *dev,
20319 + int nand_chunk,
20320 __u8 *data,
20321 - yaffs_ExtendedTags *tags);
20322 -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
20323 - int blockNo);
20324 -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
20325 - int blockNo,
20326 - yaffs_BlockState *state,
20327 - __u32 *sequenceNumber);
20328 + yaffs_ext_tags *tags);
20329 +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
20330 + int block_no);
20331 +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
20332 + int block_no,
20333 + yaffs_block_state_t *state,
20334 + __u32 *seq_number);
20335
20336 -void yaffs_CalcTagsECC(yaffs_Tags *tags);
20337 -int yaffs_CheckECCOnTags(yaffs_Tags *tags);
20338 -int yaffs_CountBits(__u8 byte);
20339 +void yaffs_calc_tags_ecc(yaffs_tags_t *tags);
20340 +int yaffs_check_tags_ecc(yaffs_tags_t *tags);
20341 +int yaffs_count_bits(__u8 byte);
20342
20343 #endif
20344 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.c
20345 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-20 13:17:58.962000294 +0300
20346 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.c 2010-10-20 13:28:16.030000294 +0300
20347 @@ -1,7 +1,7 @@
20348 /*
20349 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
20350 *
20351 - * Copyright (C) 2002-2007 Aleph One Ltd.
20352 + * Copyright (C) 2002-2010 Aleph One Ltd.
20353 * for Toby Churchill Ltd and Brightstar Engineering
20354 *
20355 * Created by Charles Manning <charles@aleph1.co.uk>
20356 @@ -13,16 +13,16 @@
20357
20358 #include "yaffs_tagsvalidity.h"
20359
20360 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
20361 +void yaffs_init_tags(yaffs_ext_tags *tags)
20362 {
20363 - memset(tags, 0, sizeof(yaffs_ExtendedTags));
20364 - tags->validMarker0 = 0xAAAAAAAA;
20365 - tags->validMarker1 = 0x55555555;
20366 + memset(tags, 0, sizeof(yaffs_ext_tags));
20367 + tags->validity1 = 0xAAAAAAAA;
20368 + tags->validty1 = 0x55555555;
20369 }
20370
20371 -int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
20372 +int yaffs_validate_tags(yaffs_ext_tags *tags)
20373 {
20374 - return (tags->validMarker0 == 0xAAAAAAAA &&
20375 - tags->validMarker1 == 0x55555555);
20376 + return (tags->validity1 == 0xAAAAAAAA &&
20377 + tags->validty1 == 0x55555555);
20378
20379 }
20380 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.h
20381 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-20 13:17:58.962000294 +0300
20382 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_tagsvalidity.h 2010-10-20 13:28:16.064000294 +0300
20383 @@ -1,7 +1,7 @@
20384 /*
20385 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20386 *
20387 - * Copyright (C) 2002-2007 Aleph One Ltd.
20388 + * Copyright (C) 2002-2010 Aleph One Ltd.
20389 * for Toby Churchill Ltd and Brightstar Engineering
20390 *
20391 * Created by Charles Manning <charles@aleph1.co.uk>
20392 @@ -19,6 +19,6 @@
20393
20394 #include "yaffs_guts.h"
20395
20396 -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
20397 -int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
20398 +void yaffs_init_tags(yaffs_ext_tags *tags);
20399 +int yaffs_validate_tags(yaffs_ext_tags *tags);
20400 #endif
20401 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_trace.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_trace.h
20402 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_trace.h 1970-01-01 02:00:00.000000000 +0200
20403 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_trace.h 2010-10-20 13:28:16.064000294 +0300
20404 @@ -0,0 +1,60 @@
20405 +/*
20406 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
20407 + *
20408 + * Copyright (C) 2002-2010 Aleph One Ltd.
20409 + * for Toby Churchill Ltd and Brightstar Engineering
20410 + *
20411 + * Created by Charles Manning <charles@aleph1.co.uk>
20412 + *
20413 + * This program is free software; you can redistribute it and/or modify
20414 + * it under the terms of the GNU Lesser General Public License version 2.1 as
20415 + * published by the Free Software Foundation.
20416 + *
20417 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
20418 + */
20419 +
20420 +
20421 +#ifndef __YTRACE_H__
20422 +#define __YTRACE_H__
20423 +
20424 +extern unsigned int yaffs_trace_mask;
20425 +extern unsigned int yaffs_wr_attempts;
20426 +
20427 +/*
20428 + * Tracing flags.
20429 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
20430 + */
20431 +
20432 +#define YAFFS_TRACE_OS 0x00000002
20433 +#define YAFFS_TRACE_ALLOCATE 0x00000004
20434 +#define YAFFS_TRACE_SCAN 0x00000008
20435 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
20436 +#define YAFFS_TRACE_ERASE 0x00000020
20437 +#define YAFFS_TRACE_GC 0x00000040
20438 +#define YAFFS_TRACE_WRITE 0x00000080
20439 +#define YAFFS_TRACE_TRACING 0x00000100
20440 +#define YAFFS_TRACE_DELETION 0x00000200
20441 +#define YAFFS_TRACE_BUFFERS 0x00000400
20442 +#define YAFFS_TRACE_NANDACCESS 0x00000800
20443 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
20444 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
20445 +#define YAFFS_TRACE_MTD 0x00004000
20446 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
20447 +
20448 +#define YAFFS_TRACE_VERIFY 0x00010000
20449 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
20450 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
20451 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
20452 +
20453 +#define YAFFS_TRACE_SYNC 0x00100000
20454 +#define YAFFS_TRACE_BACKGROUND 0x00200000
20455 +#define YAFFS_TRACE_LOCK 0x00400000
20456 +
20457 +#define YAFFS_TRACE_ERROR 0x40000000
20458 +#define YAFFS_TRACE_BUG 0x80000000
20459 +#define YAFFS_TRACE_ALWAYS 0xF0000000
20460 +
20461 +
20462 +#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
20463 +
20464 +#endif
20465 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.c
20466 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.c 1970-01-01 02:00:00.000000000 +0200
20467 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.c 2010-10-20 13:28:16.031000294 +0300
20468 @@ -0,0 +1,626 @@
20469 +/*
20470 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
20471 + *
20472 + * Copyright (C) 2002-2010 Aleph One Ltd.
20473 + * for Toby Churchill Ltd and Brightstar Engineering
20474 + *
20475 + * Created by Charles Manning <charles@aleph1.co.uk>
20476 + *
20477 + * This program is free software; you can redistribute it and/or modify
20478 + * it under the terms of the GNU General Public License version 2 as
20479 + * published by the Free Software Foundation.
20480 + */
20481 +
20482 +
20483 +#include "yaffs_verify.h"
20484 +#include "yaffs_trace.h"
20485 +#include "yaffs_bitmap.h"
20486 +#include "yaffs_getblockinfo.h"
20487 +#include "yaffs_nand.h"
20488 +
20489 +int yaffs_skip_verification(yaffs_dev_t *dev)
20490 +{
20491 + dev=dev;
20492 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
20493 +}
20494 +
20495 +static int yaffs_skip_full_verification(yaffs_dev_t *dev)
20496 +{
20497 + dev=dev;
20498 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
20499 +}
20500 +
20501 +static int yaffs_skip_nand_verification(yaffs_dev_t *dev)
20502 +{
20503 + dev=dev;
20504 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
20505 +}
20506 +
20507 +
20508 +static const char *block_stateName[] = {
20509 +"Unknown",
20510 +"Needs scanning",
20511 +"Scanning",
20512 +"Empty",
20513 +"Allocating",
20514 +"Full",
20515 +"Dirty",
20516 +"Checkpoint",
20517 +"Collecting",
20518 +"Dead"
20519 +};
20520 +
20521 +
20522 +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
20523 +{
20524 + int actuallyUsed;
20525 + int inUse;
20526 +
20527 + if (yaffs_skip_verification(dev))
20528 + return;
20529 +
20530 + /* Report illegal runtime states */
20531 + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
20532 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state));
20533 +
20534 + switch (bi->block_state) {
20535 + case YAFFS_BLOCK_STATE_UNKNOWN:
20536 + case YAFFS_BLOCK_STATE_SCANNING:
20537 + case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
20538 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
20539 + n, block_stateName[bi->block_state]));
20540 + }
20541 +
20542 + /* Check pages in use and soft deletions are legal */
20543 +
20544 + actuallyUsed = bi->pages_in_use - bi->soft_del_pages;
20545 +
20546 + if (bi->pages_in_use < 0 || bi->pages_in_use > dev->param.chunks_per_block ||
20547 + bi->soft_del_pages < 0 || bi->soft_del_pages > dev->param.chunks_per_block ||
20548 + actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block)
20549 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR),
20550 + n, bi->pages_in_use, bi->soft_del_pages));
20551 +
20552 +
20553 + /* Check chunk bitmap legal */
20554 + inUse = yaffs_count_chunk_bits(dev, n);
20555 + if (inUse != bi->pages_in_use)
20556 + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR),
20557 + n, bi->pages_in_use, inUse));
20558 +
20559 +}
20560 +
20561 +
20562 +
20563 +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
20564 +{
20565 + yaffs_verify_blk(dev, bi, n);
20566 +
20567 + /* After collection the block should be in the erased state */
20568 +
20569 + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
20570 + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
20571 + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
20572 + n, bi->block_state));
20573 + }
20574 +}
20575 +
20576 +void yaffs_verify_blocks(yaffs_dev_t *dev)
20577 +{
20578 + int i;
20579 + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
20580 + int nIllegalBlockStates = 0;
20581 +
20582 + if (yaffs_skip_verification(dev))
20583 + return;
20584 +
20585 + memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
20586 +
20587 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
20588 + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
20589 + yaffs_verify_blk(dev, bi, i);
20590 +
20591 + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
20592 + nBlocksPerState[bi->block_state]++;
20593 + else
20594 + nIllegalBlockStates++;
20595 + }
20596 +
20597 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
20598 + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
20599 +
20600 + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
20601 + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
20602 + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
20603 +
20604 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
20605 + T(YAFFS_TRACE_VERIFY,
20606 + (TSTR("%s %d blocks"TENDSTR),
20607 + block_stateName[i], nBlocksPerState[i]));
20608 +
20609 + if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
20610 + T(YAFFS_TRACE_VERIFY,
20611 + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
20612 + dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
20613 +
20614 + if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
20615 + T(YAFFS_TRACE_VERIFY,
20616 + (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
20617 + dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
20618 +
20619 + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
20620 + T(YAFFS_TRACE_VERIFY,
20621 + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
20622 + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
20623 +
20624 + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
20625 +
20626 +}
20627 +
20628 +/*
20629 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which
20630 + * case those tests will not be performed.
20631 + */
20632 +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck)
20633 +{
20634 + if (obj && yaffs_skip_verification(obj->my_dev))
20635 + return;
20636 +
20637 + if (!(tags && obj && oh)) {
20638 + T(YAFFS_TRACE_VERIFY,
20639 + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
20640 + tags, obj, oh));
20641 + return;
20642 + }
20643 +
20644 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
20645 + oh->type > YAFFS_OBJECT_TYPE_MAX)
20646 + T(YAFFS_TRACE_VERIFY,
20647 + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
20648 + tags->obj_id, oh->type));
20649 +
20650 + if (tags->obj_id != obj->obj_id)
20651 + T(YAFFS_TRACE_VERIFY,
20652 + (TSTR("Obj %d header mismatch obj_id %d"TENDSTR),
20653 + tags->obj_id, obj->obj_id));
20654 +
20655 +
20656 + /*
20657 + * Check that the object's parent ids match if parentCheck requested.
20658 + *
20659 + * Tests do not apply to the root object.
20660 + */
20661 +
20662 + if (parentCheck && tags->obj_id > 1 && !obj->parent)
20663 + T(YAFFS_TRACE_VERIFY,
20664 + (TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR),
20665 + tags->obj_id, oh->parent_obj_id));
20666 +
20667 + if (parentCheck && obj->parent &&
20668 + oh->parent_obj_id != obj->parent->obj_id &&
20669 + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
20670 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
20671 + T(YAFFS_TRACE_VERIFY,
20672 + (TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR),
20673 + tags->obj_id, oh->parent_obj_id, obj->parent->obj_id));
20674 +
20675 + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
20676 + T(YAFFS_TRACE_VERIFY,
20677 + (TSTR("Obj %d header name is NULL"TENDSTR),
20678 + obj->obj_id));
20679 +
20680 + if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
20681 + T(YAFFS_TRACE_VERIFY,
20682 + (TSTR("Obj %d header name is 0xFF"TENDSTR),
20683 + obj->obj_id));
20684 +}
20685 +
20686 +
20687 +#if 0
20688 +/* Not being used, but don't want to throw away yet */
20689 +int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn,
20690 + __u32 level, int chunk_offset)
20691 +{
20692 + int i;
20693 + yaffs_dev_t *dev = obj->my_dev;
20694 + int ok = 1;
20695 +
20696 + if (tn) {
20697 + if (level > 0) {
20698 +
20699 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
20700 + if (tn->internal[i]) {
20701 + ok = yaffs_verify_tnode_worker(obj,
20702 + tn->internal[i],
20703 + level - 1,
20704 + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
20705 + }
20706 + }
20707 + } else if (level == 0) {
20708 + yaffs_ext_tags tags;
20709 + __u32 obj_id = obj->obj_id;
20710 +
20711 + chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS;
20712 +
20713 + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
20714 + __u32 theChunk = yaffs_get_group_base(dev, tn, i);
20715 +
20716 + if (theChunk > 0) {
20717 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */
20718 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
20719 + if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) {
20720 + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
20721 + obj_id, chunk_offset, theChunk,
20722 + tags.obj_id, tags.chunk_id));
20723 + }
20724 + }
20725 + chunk_offset++;
20726 + }
20727 + }
20728 + }
20729 +
20730 + return ok;
20731 +
20732 +}
20733 +
20734 +#endif
20735 +
20736 +void yaffs_verify_file(yaffs_obj_t *obj)
20737 +{
20738 + int requiredTallness;
20739 + int actualTallness;
20740 + __u32 lastChunk;
20741 + __u32 x;
20742 + __u32 i;
20743 + yaffs_dev_t *dev;
20744 + yaffs_ext_tags tags;
20745 + yaffs_tnode_t *tn;
20746 + __u32 obj_id;
20747 +
20748 + if (!obj)
20749 + return;
20750 +
20751 + if (yaffs_skip_verification(obj->my_dev))
20752 + return;
20753 +
20754 + dev = obj->my_dev;
20755 + obj_id = obj->obj_id;
20756 +
20757 + /* Check file size is consistent with tnode depth */
20758 + lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
20759 + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
20760 + requiredTallness = 0;
20761 + while (x > 0) {
20762 + x >>= YAFFS_TNODES_INTERNAL_BITS;
20763 + requiredTallness++;
20764 + }
20765 +
20766 + actualTallness = obj->variant.file_variant.top_level;
20767 +
20768 + /* Check that the chunks in the tnode tree are all correct.
20769 + * We do this by scanning through the tnode tree and
20770 + * checking the tags for every chunk match.
20771 + */
20772 +
20773 + if (yaffs_skip_nand_verification(dev))
20774 + return;
20775 +
20776 + for (i = 1; i <= lastChunk; i++) {
20777 + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
20778 +
20779 + if (tn) {
20780 + __u32 theChunk = yaffs_get_group_base(dev, tn, i);
20781 + if (theChunk > 0) {
20782 + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */
20783 + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
20784 + if (tags.obj_id != obj_id || tags.chunk_id != i) {
20785 + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
20786 + obj_id, i, theChunk,
20787 + tags.obj_id, tags.chunk_id));
20788 + }
20789 + }
20790 + }
20791 + }
20792 +}
20793 +
20794 +
20795 +void yaffs_verify_link(yaffs_obj_t *obj)
20796 +{
20797 + if (obj && yaffs_skip_verification(obj->my_dev))
20798 + return;
20799 +
20800 + /* Verify sane equivalent object */
20801 +}
20802 +
20803 +void yaffs_verify_symlink(yaffs_obj_t *obj)
20804 +{
20805 + if (obj && yaffs_skip_verification(obj->my_dev))
20806 + return;
20807 +
20808 + /* Verify symlink string */
20809 +}
20810 +
20811 +void yaffs_verify_special(yaffs_obj_t *obj)
20812 +{
20813 + if (obj && yaffs_skip_verification(obj->my_dev))
20814 + return;
20815 +}
20816 +
20817 +void yaffs_verify_obj(yaffs_obj_t *obj)
20818 +{
20819 + yaffs_dev_t *dev;
20820 +
20821 + __u32 chunkMin;
20822 + __u32 chunkMax;
20823 +
20824 + __u32 chunk_idOk;
20825 + __u32 chunkInRange;
20826 + __u32 chunkShouldNotBeDeleted;
20827 + __u32 chunkValid;
20828 +
20829 + if (!obj)
20830 + return;
20831 +
20832 + if (obj->being_created)
20833 + return;
20834 +
20835 + dev = obj->my_dev;
20836 +
20837 + if (yaffs_skip_verification(dev))
20838 + return;
20839 +
20840 + /* Check sane object header chunk */
20841 +
20842 + chunkMin = dev->internal_start_block * dev->param.chunks_per_block;
20843 + chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1;
20844 +
20845 + chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax);
20846 + chunk_idOk = chunkInRange || (obj->hdr_chunk == 0);
20847 + chunkValid = chunkInRange &&
20848 + yaffs_check_chunk_bit(dev,
20849 + obj->hdr_chunk / dev->param.chunks_per_block,
20850 + obj->hdr_chunk % dev->param.chunks_per_block);
20851 + chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
20852 +
20853 + if (!obj->fake &&
20854 + (!chunk_idOk || chunkShouldNotBeDeleted)) {
20855 + T(YAFFS_TRACE_VERIFY,
20856 + (TSTR("Obj %d has chunk_id %d %s %s"TENDSTR),
20857 + obj->obj_id, obj->hdr_chunk,
20858 + chunk_idOk ? "" : ",out of range",
20859 + chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
20860 + }
20861 +
20862 + if (chunkValid && !yaffs_skip_nand_verification(dev)) {
20863 + yaffs_ext_tags tags;
20864 + yaffs_obj_header *oh;
20865 + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
20866 +
20867 + oh = (yaffs_obj_header *)buffer;
20868 +
20869 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer,
20870 + &tags);
20871 +
20872 + yaffs_verify_oh(obj, oh, &tags, 1);
20873 +
20874 + yaffs_release_temp_buffer(dev, buffer, __LINE__);
20875 + }
20876 +
20877 + /* Verify it has a parent */
20878 + if (obj && !obj->fake &&
20879 + (!obj->parent || obj->parent->my_dev != dev)) {
20880 + T(YAFFS_TRACE_VERIFY,
20881 + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
20882 + obj->obj_id, obj->parent));
20883 + }
20884 +
20885 + /* Verify parent is a directory */
20886 + if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20887 + T(YAFFS_TRACE_VERIFY,
20888 + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
20889 + obj->obj_id, obj->parent->variant_type));
20890 + }
20891 +
20892 + switch (obj->variant_type) {
20893 + case YAFFS_OBJECT_TYPE_FILE:
20894 + yaffs_verify_file(obj);
20895 + break;
20896 + case YAFFS_OBJECT_TYPE_SYMLINK:
20897 + yaffs_verify_symlink(obj);
20898 + break;
20899 + case YAFFS_OBJECT_TYPE_DIRECTORY:
20900 + yaffs_verify_dir(obj);
20901 + break;
20902 + case YAFFS_OBJECT_TYPE_HARDLINK:
20903 + yaffs_verify_link(obj);
20904 + break;
20905 + case YAFFS_OBJECT_TYPE_SPECIAL:
20906 + yaffs_verify_special(obj);
20907 + break;
20908 + case YAFFS_OBJECT_TYPE_UNKNOWN:
20909 + default:
20910 + T(YAFFS_TRACE_VERIFY,
20911 + (TSTR("Obj %d has illegaltype %d"TENDSTR),
20912 + obj->obj_id, obj->variant_type));
20913 + break;
20914 + }
20915 +}
20916 +
20917 +void yaffs_verify_objects(yaffs_dev_t *dev)
20918 +{
20919 + yaffs_obj_t *obj;
20920 + int i;
20921 + struct ylist_head *lh;
20922 +
20923 + if (yaffs_skip_verification(dev))
20924 + return;
20925 +
20926 + /* Iterate through the objects in each hash entry */
20927 +
20928 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
20929 + ylist_for_each(lh, &dev->obj_bucket[i].list) {
20930 + if (lh) {
20931 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
20932 + yaffs_verify_obj(obj);
20933 + }
20934 + }
20935 + }
20936 +}
20937 +
20938 +
20939 +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
20940 +{
20941 + struct ylist_head *lh;
20942 + yaffs_obj_t *listObj;
20943 +
20944 + int count = 0;
20945 +
20946 + if (!obj) {
20947 + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
20948 + YBUG();
20949 + return;
20950 + }
20951 +
20952 + if (yaffs_skip_verification(obj->my_dev))
20953 + return;
20954 +
20955 + if (!obj->parent) {
20956 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
20957 + YBUG();
20958 + return;
20959 + }
20960 +
20961 + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20962 + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
20963 + YBUG();
20964 + }
20965 +
20966 + /* Iterate through the objects in each hash entry */
20967 +
20968 + ylist_for_each(lh, &obj->parent->variant.dir_variant.children) {
20969 + if (lh) {
20970 + listObj = ylist_entry(lh, yaffs_obj_t, siblings);
20971 + yaffs_verify_obj(listObj);
20972 + if (obj == listObj)
20973 + count++;
20974 + }
20975 + }
20976 +
20977 + if (count != 1) {
20978 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
20979 + YBUG();
20980 + }
20981 +}
20982 +
20983 +void yaffs_verify_dir(yaffs_obj_t *directory)
20984 +{
20985 + struct ylist_head *lh;
20986 + yaffs_obj_t *listObj;
20987 +
20988 + if (!directory) {
20989 + YBUG();
20990 + return;
20991 + }
20992 +
20993 + if (yaffs_skip_full_verification(directory->my_dev))
20994 + return;
20995 +
20996 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
20997 + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type));
20998 + YBUG();
20999 + }
21000 +
21001 + /* Iterate through the objects in each hash entry */
21002 +
21003 + ylist_for_each(lh, &directory->variant.dir_variant.children) {
21004 + if (lh) {
21005 + listObj = ylist_entry(lh, yaffs_obj_t, siblings);
21006 + if (listObj->parent != directory) {
21007 + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
21008 + YBUG();
21009 + }
21010 + yaffs_verify_obj_in_dir(listObj);
21011 + }
21012 + }
21013 +}
21014 +
21015 +static int yaffs_free_verification_failures;
21016 +
21017 +void yaffs_verify_free_chunks(yaffs_dev_t *dev)
21018 +{
21019 + int counted;
21020 + int difference;
21021 +
21022 + if (yaffs_skip_verification(dev))
21023 + return;
21024 +
21025 + counted = yaffs_count_free_chunks(dev);
21026 +
21027 + difference = dev->n_free_chunks - counted;
21028 +
21029 + if (difference) {
21030 + T(YAFFS_TRACE_ALWAYS,
21031 + (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
21032 + dev->n_free_chunks, counted, difference));
21033 + yaffs_free_verification_failures++;
21034 + }
21035 +}
21036 +
21037 +int yaffs_verify_file_sane(yaffs_obj_t *in)
21038 +{
21039 +#if 0
21040 + int chunk;
21041 + int n_chunks;
21042 + int fSize;
21043 + int failed = 0;
21044 + int obj_id;
21045 + yaffs_tnode_t *tn;
21046 + yaffs_tags_t localTags;
21047 + yaffs_tags_t *tags = &localTags;
21048 + int theChunk;
21049 + int is_deleted;
21050 +
21051 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
21052 + return YAFFS_FAIL;
21053 +
21054 + obj_id = in->obj_id;
21055 + fSize = in->variant.file_variant.file_size;
21056 + n_chunks =
21057 + (fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk;
21058 +
21059 + for (chunk = 1; chunk <= n_chunks; chunk++) {
21060 + tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant,
21061 + chunk);
21062 +
21063 + if (tn) {
21064 +
21065 + theChunk = yaffs_get_group_base(dev, tn, chunk);
21066 +
21067 + if (yaffs_check_chunk_bits
21068 + (dev, theChunk / dev->param.chunks_per_block,
21069 + theChunk % dev->param.chunks_per_block)) {
21070 +
21071 + yaffs_rd_chunk_tags_nand(in->my_dev, theChunk,
21072 + tags,
21073 + &is_deleted);
21074 + if (yaffs_tags_match
21075 + (tags, in->obj_id, chunk, is_deleted)) {
21076 + /* found it; */
21077 +
21078 + }
21079 + } else {
21080 +
21081 + failed = 1;
21082 + }
21083 +
21084 + } else {
21085 + /* T(("No level 0 found for %d\n", chunk)); */
21086 + }
21087 + }
21088 +
21089 + return failed ? YAFFS_FAIL : YAFFS_OK;
21090 +#else
21091 + in=in;
21092 + return YAFFS_OK;
21093 +#endif
21094 +}
21095 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.h
21096 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_verify.h 1970-01-01 02:00:00.000000000 +0200
21097 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_verify.h 2010-10-20 13:28:16.064000294 +0300
21098 @@ -0,0 +1,39 @@
21099 +/*
21100 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21101 + *
21102 + * Copyright (C) 2002-2010 Aleph One Ltd.
21103 + * for Toby Churchill Ltd and Brightstar Engineering
21104 + *
21105 + * Created by Charles Manning <charles@aleph1.co.uk>
21106 + *
21107 + * This program is free software; you can redistribute it and/or modify
21108 + * it under the terms of the GNU General Public License version 2 as
21109 + * published by the Free Software Foundation.
21110 + */
21111 +
21112 +#ifndef __YAFFS_VERIFY_H__
21113 +#define __YAFFS_VERIFY_H__
21114 +
21115 +#include "yaffs_guts.h"
21116 +
21117 +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
21118 +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
21119 +void yaffs_verify_blocks(yaffs_dev_t *dev);
21120 +
21121 +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck);
21122 +void yaffs_verify_file(yaffs_obj_t *obj);
21123 +void yaffs_verify_link(yaffs_obj_t *obj);
21124 +void yaffs_verify_symlink(yaffs_obj_t *obj);
21125 +void yaffs_verify_special(yaffs_obj_t *obj);
21126 +void yaffs_verify_obj(yaffs_obj_t *obj);
21127 +void yaffs_verify_objects(yaffs_dev_t *dev);
21128 +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj);
21129 +void yaffs_verify_dir(yaffs_obj_t *directory);
21130 +void yaffs_verify_free_chunks(yaffs_dev_t *dev);
21131 +
21132 +int yaffs_verify_file_sane(yaffs_obj_t *obj);
21133 +
21134 +int yaffs_skip_verification(yaffs_dev_t *dev);
21135 +
21136 +#endif
21137 +
21138 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_vfs_glue.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_vfs_glue.c
21139 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_vfs_glue.c 1970-01-01 02:00:00.000000000 +0200
21140 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_vfs_glue.c 2010-10-20 13:28:16.069000294 +0300
21141 @@ -0,0 +1,3576 @@
21142 +/*
21143 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
21144 + *
21145 + * Copyright (C) 2002-2010 Aleph One Ltd.
21146 + * for Toby Churchill Ltd and Brightstar Engineering
21147 + *
21148 + * Created by Charles Manning <charles@aleph1.co.uk>
21149 + * Acknowledgements:
21150 + * Luc van OostenRyck for numerous patches.
21151 + * Nick Bane for numerous patches.
21152 + * Nick Bane for 2.5/2.6 integration.
21153 + * Andras Toth for mknod rdev issue.
21154 + * Michael Fischer for finding the problem with inode inconsistency.
21155 + * Some code bodily lifted from JFFS
21156 + *
21157 + * This program is free software; you can redistribute it and/or modify
21158 + * it under the terms of the GNU General Public License version 2 as
21159 + * published by the Free Software Foundation.
21160 + */
21161 +
21162 +/*
21163 + *
21164 + * This is the file system front-end to YAFFS that hooks it up to
21165 + * the VFS.
21166 + *
21167 + * Special notes:
21168 + * >> 2.4: sb->u.generic_sbp points to the yaffs_dev_t associated with
21169 + * this superblock
21170 + * >> 2.6: sb->s_fs_info points to the yaffs_dev_t associated with this
21171 + * superblock
21172 + * >> inode->u.generic_ip points to the associated yaffs_obj_t.
21173 + */
21174 +
21175 +/*
21176 + * There are two variants of the VFS glue code. This variant should compile
21177 + * for any version of Linux.
21178 + */
21179 +#include <linux/version.h>
21180 +
21181 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
21182 +#define YAFFS_COMPILE_BACKGROUND
21183 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
21184 +#define YAFFS_COMPILE_FREEZER
21185 +#endif
21186 +#endif
21187 +
21188 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
21189 +#define YAFFS_COMPILE_EXPORTFS
21190 +#endif
21191 +
21192 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
21193 +#define YAFFS_USE_SETATTR_COPY
21194 +#define YAFFS_USE_TRUNCATE_SETSIZE
21195 +#endif
21196 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
21197 +#define YAFFS_HAS_EVICT_INODE
21198 +#endif
21199 +
21200 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
21201 +#define YAFFS_NEW_FOLLOW_LINK 1
21202 +#else
21203 +#define YAFFS_NEW_FOLLOW_LINK 0
21204 +#endif
21205 +
21206 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
21207 +#include <linux/config.h>
21208 +#endif
21209 +
21210 +#include <linux/kernel.h>
21211 +#include <linux/module.h>
21212 +#include <linux/slab.h>
21213 +#include <linux/init.h>
21214 +#include <linux/fs.h>
21215 +#include <linux/proc_fs.h>
21216 +#include <linux/smp_lock.h>
21217 +#include <linux/pagemap.h>
21218 +#include <linux/mtd/mtd.h>
21219 +#include <linux/interrupt.h>
21220 +#include <linux/string.h>
21221 +#include <linux/ctype.h>
21222 +
21223 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21224 +#include <linux/namei.h>
21225 +#endif
21226 +
21227 +#ifdef YAFFS_COMPILE_EXPORTFS
21228 +#include <linux/exportfs.h>
21229 +#endif
21230 +
21231 +#ifdef YAFFS_COMPILE_BACKGROUND
21232 +#include <linux/kthread.h>
21233 +#include <linux/delay.h>
21234 +#endif
21235 +#ifdef YAFFS_COMPILE_FREEZER
21236 +#include <linux/freezer.h>
21237 +#endif
21238 +
21239 +#include <asm/div64.h>
21240 +
21241 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21242 +
21243 +#include <linux/statfs.h>
21244 +
21245 +#define UnlockPage(p) unlock_page(p)
21246 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
21247 +
21248 +/* FIXME: use sb->s_id instead ? */
21249 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
21250 +
21251 +#else
21252 +
21253 +#include <linux/locks.h>
21254 +#define BDEVNAME_SIZE 0
21255 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
21256 +
21257 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
21258 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
21259 +#define __user
21260 +#endif
21261 +
21262 +#endif
21263 +
21264 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
21265 +#define YPROC_ROOT (&proc_root)
21266 +#else
21267 +#define YPROC_ROOT NULL
21268 +#endif
21269 +
21270 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
21271 +#define Y_INIT_TIMER(a) init_timer(a)
21272 +#else
21273 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
21274 +#endif
21275 +
21276 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21277 +#define WRITE_SIZE_STR "writesize"
21278 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
21279 +#else
21280 +#define WRITE_SIZE_STR "oobblock"
21281 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
21282 +#endif
21283 +
21284 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
21285 +#define YAFFS_USE_WRITE_BEGIN_END 1
21286 +#else
21287 +#define YAFFS_USE_WRITE_BEGIN_END 0
21288 +#endif
21289 +
21290 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
21291 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
21292 +{
21293 + uint64_t result = partition_size;
21294 + do_div(result, block_size);
21295 + return (uint32_t)result;
21296 +}
21297 +#else
21298 +#define YCALCBLOCKS(s, b) ((s)/(b))
21299 +#endif
21300 +
21301 +#include <linux/uaccess.h>
21302 +#include <linux/mtd/mtd.h>
21303 +
21304 +#include "yportenv.h"
21305 +#include "yaffs_trace.h"
21306 +#include "yaffs_guts.h"
21307 +
21308 +#include "yaffs_linux.h"
21309 +
21310 +#include "yaffs_mtdif.h"
21311 +#include "yaffs_mtdif1.h"
21312 +#include "yaffs_mtdif2.h"
21313 +
21314 +unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
21315 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
21316 +unsigned int yaffs_auto_checkpoint = 1;
21317 +unsigned int yaffs_gc_control = 1;
21318 +unsigned int yaffs_bg_enable = 1;
21319 +
21320 +/* Module Parameters */
21321 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21322 +module_param(yaffs_trace_mask, uint, 0644);
21323 +module_param(yaffs_wr_attempts, uint, 0644);
21324 +module_param(yaffs_auto_checkpoint, uint, 0644);
21325 +module_param(yaffs_gc_control, uint, 0644);
21326 +module_param(yaffs_bg_enable, uint, 0644);
21327 +#else
21328 +MODULE_PARM(yaffs_trace_mask, "i");
21329 +MODULE_PARM(yaffs_wr_attempts, "i");
21330 +MODULE_PARM(yaffs_auto_checkpoint, "i");
21331 +MODULE_PARM(yaffs_gc_control, "i");
21332 +#endif
21333 +
21334 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
21335 +/* use iget and read_inode */
21336 +#define Y_IGET(sb, inum) iget((sb), (inum))
21337 +static void yaffs_read_inode(struct inode *inode);
21338 +
21339 +#else
21340 +/* Call local equivalent */
21341 +#define YAFFS_USE_OWN_IGET
21342 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
21343 +
21344 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
21345 +#endif
21346 +
21347 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
21348 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
21349 +#else
21350 +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
21351 +#endif
21352 +
21353 +#define yaffs_InodeToObject(iptr) ((yaffs_obj_t *)(yaffs_InodeToObjectLV(iptr)))
21354 +#define yaffs_dentry_to_obj(dptr) yaffs_InodeToObject((dptr)->d_inode)
21355 +
21356 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21357 +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->s_fs_info)
21358 +#else
21359 +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
21360 +#endif
21361 +
21362 +
21363 +#define update_dir_time(dir) do {\
21364 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
21365 + } while(0)
21366 +
21367 +static void yaffs_put_super(struct super_block *sb);
21368 +
21369 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
21370 + loff_t *pos);
21371 +static ssize_t yaffs_hold_space(struct file *f);
21372 +static void yaffs_release_space(struct file *f);
21373 +
21374 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21375 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
21376 +#else
21377 +static int yaffs_file_flush(struct file *file);
21378 +#endif
21379 +
21380 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
21381 +static int yaffs_sync_object(struct file *file, int datasync);
21382 +#else
21383 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
21384 + int datasync);
21385 +#endif
21386 +
21387 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
21388 +
21389 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21390 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
21391 + struct nameidata *n);
21392 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
21393 + struct nameidata *n);
21394 +#else
21395 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
21396 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
21397 +#endif
21398 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
21399 + struct dentry *dentry);
21400 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
21401 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
21402 + const char *symname);
21403 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
21404 +
21405 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21406 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
21407 + dev_t dev);
21408 +#else
21409 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
21410 + int dev);
21411 +#endif
21412 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
21413 + struct inode *new_dir, struct dentry *new_dentry);
21414 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
21415 +
21416 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21417 +static int yaffs_sync_fs(struct super_block *sb, int wait);
21418 +static void yaffs_write_super(struct super_block *sb);
21419 +#else
21420 +static int yaffs_sync_fs(struct super_block *sb);
21421 +static int yaffs_write_super(struct super_block *sb);
21422 +#endif
21423 +
21424 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
21425 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
21426 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21427 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
21428 +#else
21429 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
21430 +#endif
21431 +
21432 +#ifdef YAFFS_HAS_PUT_INODE
21433 +static void yaffs_put_inode(struct inode *inode);
21434 +#endif
21435 +
21436 +#ifdef YAFFS_HAS_EVICT_INODE
21437 +static void yaffs_evict_inode(struct inode *);
21438 +#else
21439 +static void yaffs_delete_inode(struct inode *);
21440 +static void yaffs_clear_inode(struct inode *);
21441 +#endif
21442 +
21443 +static int yaffs_readpage(struct file *file, struct page *page);
21444 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21445 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
21446 +#else
21447 +static int yaffs_writepage(struct page *page);
21448 +#endif
21449 +
21450 +#ifdef CONFIG_YAFFS_XATTR
21451 +int yaffs_setxattr(struct dentry *dentry, const char *name,
21452 + const void *value, size_t size, int flags);
21453 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
21454 + size_t size);
21455 +int yaffs_removexattr(struct dentry *dentry, const char *name);
21456 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
21457 +#endif
21458 +
21459 +
21460 +#if (YAFFS_USE_WRITE_BEGIN_END != 0)
21461 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
21462 + loff_t pos, unsigned len, unsigned flags,
21463 + struct page **pagep, void **fsdata);
21464 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
21465 + loff_t pos, unsigned len, unsigned copied,
21466 + struct page *pg, void *fsdadata);
21467 +#else
21468 +static int yaffs_prepare_write(struct file *f, struct page *pg,
21469 + unsigned offset, unsigned to);
21470 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
21471 + unsigned to);
21472 +
21473 +#endif
21474 +
21475 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
21476 + int buflen);
21477 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21478 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
21479 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
21480 +#else
21481 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
21482 +#endif
21483 +
21484 +static void yaffs_touch_super(yaffs_dev_t *dev);
21485 +
21486 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
21487 +
21488 +static int yaffs_vfs_setattr(struct inode *, struct iattr *);
21489 +
21490 +
21491 +static struct address_space_operations yaffs_file_address_operations = {
21492 + .readpage = yaffs_readpage,
21493 + .writepage = yaffs_writepage,
21494 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
21495 + .write_begin = yaffs_write_begin,
21496 + .write_end = yaffs_write_end,
21497 +#else
21498 + .prepare_write = yaffs_prepare_write,
21499 + .commit_write = yaffs_commit_write,
21500 +#endif
21501 +};
21502 +
21503 +
21504 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
21505 +static const struct file_operations yaffs_file_operations = {
21506 + .read = do_sync_read,
21507 + .write = do_sync_write,
21508 + .aio_read = generic_file_aio_read,
21509 + .aio_write = generic_file_aio_write,
21510 + .mmap = generic_file_mmap,
21511 + .flush = yaffs_file_flush,
21512 + .fsync = yaffs_sync_object,
21513 + .splice_read = generic_file_splice_read,
21514 + .splice_write = generic_file_splice_write,
21515 + .llseek = generic_file_llseek,
21516 +};
21517 +
21518 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
21519 +
21520 +static const struct file_operations yaffs_file_operations = {
21521 + .read = do_sync_read,
21522 + .write = do_sync_write,
21523 + .aio_read = generic_file_aio_read,
21524 + .aio_write = generic_file_aio_write,
21525 + .mmap = generic_file_mmap,
21526 + .flush = yaffs_file_flush,
21527 + .fsync = yaffs_sync_object,
21528 + .sendfile = generic_file_sendfile,
21529 +};
21530 +
21531 +#else
21532 +
21533 +static const struct file_operations yaffs_file_operations = {
21534 + .read = generic_file_read,
21535 + .write = generic_file_write,
21536 + .mmap = generic_file_mmap,
21537 + .flush = yaffs_file_flush,
21538 + .fsync = yaffs_sync_object,
21539 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21540 + .sendfile = generic_file_sendfile,
21541 +#endif
21542 +};
21543 +#endif
21544 +
21545 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
21546 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
21547 +{
21548 + void * kaddr = kmap_atomic(page, KM_USER0);
21549 + memset(kaddr + start, 0, end - start);
21550 + kunmap_atomic(kaddr, KM_USER0);
21551 + flush_dcache_page(page);
21552 +}
21553 +#endif
21554 +
21555 +
21556 +static const struct inode_operations yaffs_file_inode_operations = {
21557 + .setattr = yaffs_setattr,
21558 +#ifdef CONFIG_YAFFS_XATTR
21559 + .setxattr = yaffs_setxattr,
21560 + .getxattr = yaffs_getxattr,
21561 + .listxattr = yaffs_listxattr,
21562 + .removexattr = yaffs_removexattr,
21563 +#endif
21564 +};
21565 +
21566 +static const struct inode_operations yaffs_symlink_inode_operations = {
21567 + .readlink = yaffs_readlink,
21568 + .follow_link = yaffs_follow_link,
21569 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21570 + .put_link = yaffs_put_link,
21571 +#endif
21572 + .setattr = yaffs_setattr,
21573 +#ifdef CONFIG_YAFFS_XATTR
21574 + .setxattr = yaffs_setxattr,
21575 + .getxattr = yaffs_getxattr,
21576 + .listxattr = yaffs_listxattr,
21577 + .removexattr = yaffs_removexattr,
21578 +#endif
21579 +};
21580 +
21581 +static const struct inode_operations yaffs_dir_inode_operations = {
21582 + .create = yaffs_create,
21583 + .lookup = yaffs_lookup,
21584 + .link = yaffs_link,
21585 + .unlink = yaffs_unlink,
21586 + .symlink = yaffs_symlink,
21587 + .mkdir = yaffs_mkdir,
21588 + .rmdir = yaffs_unlink,
21589 + .mknod = yaffs_mknod,
21590 + .rename = yaffs_rename,
21591 + .setattr = yaffs_setattr,
21592 +#ifdef CONFIG_YAFFS_XATTR
21593 + .setxattr = yaffs_setxattr,
21594 + .getxattr = yaffs_getxattr,
21595 + .listxattr = yaffs_listxattr,
21596 + .removexattr = yaffs_removexattr,
21597 +#endif
21598 +};
21599 +
21600 +static const struct file_operations yaffs_dir_operations = {
21601 + .read = generic_read_dir,
21602 + .readdir = yaffs_readdir,
21603 + .fsync = yaffs_sync_object,
21604 + .llseek = yaffs_dir_llseek,
21605 +};
21606 +
21607 +static const struct super_operations yaffs_super_ops = {
21608 + .statfs = yaffs_statfs,
21609 +
21610 +#ifndef YAFFS_USE_OWN_IGET
21611 + .read_inode = yaffs_read_inode,
21612 +#endif
21613 +#ifdef YAFFS_HAS_PUT_INODE
21614 + .put_inode = yaffs_put_inode,
21615 +#endif
21616 + .put_super = yaffs_put_super,
21617 +#ifdef YAFFS_HAS_EVICT_INODE
21618 + .evict_inode = yaffs_evict_inode,
21619 +#else
21620 + .delete_inode = yaffs_delete_inode,
21621 + .clear_inode = yaffs_clear_inode,
21622 +#endif
21623 + .sync_fs = yaffs_sync_fs,
21624 + .write_super = yaffs_write_super,
21625 +};
21626 +
21627 +
21628 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
21629 +{
21630 +#ifdef YAFFS_USE_SETATTR_COPY
21631 + setattr_copy(inode,attr);
21632 + return 0;
21633 +#else
21634 + return inode_setattr(inode, attr);
21635 +#endif
21636 +
21637 +}
21638 +
21639 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
21640 +{
21641 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
21642 + truncate_setsize(inode,newsize);
21643 + return 0;
21644 +#else
21645 + truncate_inode_pages(&inode->i_data,newsize);
21646 + return 0;
21647 +#endif
21648 +
21649 +}
21650 +
21651 +static unsigned yaffs_gc_control_callback(yaffs_dev_t *dev)
21652 +{
21653 + return yaffs_gc_control;
21654 +}
21655 +
21656 +static void yaffs_gross_lock(yaffs_dev_t *dev)
21657 +{
21658 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
21659 + down(&(yaffs_dev_to_lc(dev)->grossLock));
21660 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
21661 +}
21662 +
21663 +static void yaffs_gross_unlock(yaffs_dev_t *dev)
21664 +{
21665 + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
21666 + up(&(yaffs_dev_to_lc(dev)->grossLock));
21667 +}
21668 +
21669 +#ifdef YAFFS_COMPILE_EXPORTFS
21670 +
21671 +static struct inode *
21672 +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
21673 +{
21674 + return Y_IGET(sb, ino);
21675 +}
21676 +
21677 +static struct dentry *
21678 +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
21679 +{
21680 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
21681 +}
21682 +
21683 +static struct dentry *
21684 + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
21685 +{
21686 + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
21687 +}
21688 +
21689 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
21690 +{
21691 +
21692 + struct super_block *sb = dentry->d_inode->i_sb;
21693 + struct dentry *parent = ERR_PTR(-ENOENT);
21694 + struct inode *inode;
21695 + unsigned long parent_ino;
21696 + yaffs_obj_t *d_obj;
21697 + yaffs_obj_t *parent_obj;
21698 +
21699 + d_obj = yaffs_InodeToObject(dentry->d_inode);
21700 +
21701 + if (d_obj) {
21702 + parent_obj = d_obj->parent;
21703 + if (parent_obj) {
21704 + parent_ino = yaffs_get_obj_inode(parent_obj);
21705 + inode = Y_IGET(sb, parent_ino);
21706 +
21707 + if (IS_ERR(inode)) {
21708 + parent = ERR_CAST(inode);
21709 + } else {
21710 + parent = d_obtain_alias(inode);
21711 + if (!IS_ERR(parent)) {
21712 + parent = ERR_PTR(-ENOMEM);
21713 + iput(inode);
21714 + }
21715 + }
21716 + }
21717 + }
21718 +
21719 + return parent;
21720 +}
21721 +
21722 +/* Just declare a zero structure as a NULL value implies
21723 + * using the default functions of exportfs.
21724 + */
21725 +
21726 +static struct export_operations yaffs_export_ops =
21727 +{
21728 + .fh_to_dentry = yaffs2_fh_to_dentry,
21729 + .fh_to_parent = yaffs2_fh_to_parent,
21730 + .get_parent = yaffs2_get_parent,
21731 +} ;
21732 +
21733 +#endif
21734 +
21735 +/*-----------------------------------------------------------------*/
21736 +/* Directory search context allows us to unlock access to yaffs during
21737 + * filldir without causing problems with the directory being modified.
21738 + * This is similar to the tried and tested mechanism used in yaffs direct.
21739 + *
21740 + * A search context iterates along a doubly linked list of siblings in the
21741 + * directory. If the iterating object is deleted then this would corrupt
21742 + * the list iteration, likely causing a crash. The search context avoids
21743 + * this by using the remove_obj_fn to move the search context to the
21744 + * next object before the object is deleted.
21745 + *
21746 + * Many readdirs (and thus seach conexts) may be alive simulateously so
21747 + * each yaffs_dev_t has a list of these.
21748 + *
21749 + * A seach context lives for the duration of a readdir.
21750 + *
21751 + * All these functions must be called while yaffs is locked.
21752 + */
21753 +
21754 +struct yaffs_SearchContext {
21755 + yaffs_dev_t *dev;
21756 + yaffs_obj_t *dirObj;
21757 + yaffs_obj_t *nextReturn;
21758 + struct ylist_head others;
21759 +};
21760 +
21761 +/*
21762 + * yaffs_NewSearch() creates a new search context, initialises it and
21763 + * adds it to the device's search context list.
21764 + *
21765 + * Called at start of readdir.
21766 + */
21767 +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_obj_t *dir)
21768 +{
21769 + yaffs_dev_t *dev = dir->my_dev;
21770 + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
21771 + if(sc){
21772 + sc->dirObj = dir;
21773 + sc->dev = dev;
21774 + if( ylist_empty(&sc->dirObj->variant.dir_variant.children))
21775 + sc->nextReturn = NULL;
21776 + else
21777 + sc->nextReturn = ylist_entry(
21778 + dir->variant.dir_variant.children.next,
21779 + yaffs_obj_t,siblings);
21780 + YINIT_LIST_HEAD(&sc->others);
21781 + ylist_add(&sc->others,&(yaffs_dev_to_lc(dev)->searchContexts));
21782 + }
21783 + return sc;
21784 +}
21785 +
21786 +/*
21787 + * yaffs_search_end() disposes of a search context and cleans up.
21788 + */
21789 +static void yaffs_search_end(struct yaffs_SearchContext * sc)
21790 +{
21791 + if(sc){
21792 + ylist_del(&sc->others);
21793 + YFREE(sc);
21794 + }
21795 +}
21796 +
21797 +/*
21798 + * yaffs_search_advance() moves a search context to the next object.
21799 + * Called when the search iterates or when an object removal causes
21800 + * the search context to be moved to the next object.
21801 + */
21802 +static void yaffs_search_advance(struct yaffs_SearchContext *sc)
21803 +{
21804 + if(!sc)
21805 + return;
21806 +
21807 + if( sc->nextReturn == NULL ||
21808 + ylist_empty(&sc->dirObj->variant.dir_variant.children))
21809 + sc->nextReturn = NULL;
21810 + else {
21811 + struct ylist_head *next = sc->nextReturn->siblings.next;
21812 +
21813 + if( next == &sc->dirObj->variant.dir_variant.children)
21814 + sc->nextReturn = NULL; /* end of list */
21815 + else
21816 + sc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
21817 + }
21818 +}
21819 +
21820 +/*
21821 + * yaffs_remove_obj_callback() is called when an object is unlinked.
21822 + * We check open search contexts and advance any which are currently
21823 + * on the object being iterated.
21824 + */
21825 +static void yaffs_remove_obj_callback(yaffs_obj_t *obj)
21826 +{
21827 +
21828 + struct ylist_head *i;
21829 + struct yaffs_SearchContext *sc;
21830 + struct ylist_head *search_contexts = &(yaffs_dev_to_lc(obj->my_dev)->searchContexts);
21831 +
21832 +
21833 + /* Iterate through the directory search contexts.
21834 + * If any are currently on the object being removed, then advance
21835 + * the search context to the next object to prevent a hanging pointer.
21836 + */
21837 + ylist_for_each(i, search_contexts) {
21838 + if (i) {
21839 + sc = ylist_entry(i, struct yaffs_SearchContext,others);
21840 + if(sc->nextReturn == obj)
21841 + yaffs_search_advance(sc);
21842 + }
21843 + }
21844 +
21845 +}
21846 +
21847 +
21848 +/*-----------------------------------------------------------------*/
21849 +
21850 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
21851 + int buflen)
21852 +{
21853 + unsigned char *alias;
21854 + int ret;
21855 +
21856 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
21857 +
21858 + yaffs_gross_lock(dev);
21859 +
21860 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
21861 +
21862 + yaffs_gross_unlock(dev);
21863 +
21864 + if (!alias)
21865 + return -ENOMEM;
21866 +
21867 + ret = vfs_readlink(dentry, buffer, buflen, alias);
21868 + kfree(alias);
21869 + return ret;
21870 +}
21871 +
21872 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21873 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
21874 +#else
21875 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
21876 +#endif
21877 +{
21878 + unsigned char *alias;
21879 + int ret;
21880 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
21881 +
21882 + yaffs_gross_lock(dev);
21883 +
21884 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
21885 + yaffs_gross_unlock(dev);
21886 +
21887 + if (!alias) {
21888 + ret = -ENOMEM;
21889 + goto out;
21890 + }
21891 +
21892 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21893 + nd_set_link(nd, alias);
21894 + ret = (int)alias;
21895 +out:
21896 + return ERR_PTR(ret);
21897 +#else
21898 + ret = vfs_follow_link(nd, alias);
21899 + kfree(alias);
21900 +out:
21901 + return ret;
21902 +#endif
21903 +}
21904 +
21905 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
21906 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
21907 + kfree(alias);
21908 +}
21909 +#endif
21910 +
21911 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
21912 + yaffs_obj_t *obj);
21913 +
21914 +/*
21915 + * Lookup is used to find objects in the fs
21916 + */
21917 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
21918 +
21919 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
21920 + struct nameidata *n)
21921 +#else
21922 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
21923 +#endif
21924 +{
21925 + yaffs_obj_t *obj;
21926 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
21927 +
21928 + yaffs_dev_t *dev = yaffs_InodeToObject(dir)->my_dev;
21929 +
21930 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
21931 + yaffs_gross_lock(dev);
21932 +
21933 + T(YAFFS_TRACE_OS,
21934 + (TSTR("yaffs_lookup for %d:%s\n"),
21935 + yaffs_InodeToObject(dir)->obj_id, dentry->d_name.name));
21936 +
21937 + obj = yaffs_find_by_name(yaffs_InodeToObject(dir),
21938 + dentry->d_name.name);
21939 +
21940 + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
21941 +
21942 + /* Can't hold gross lock when calling yaffs_get_inode() */
21943 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
21944 + yaffs_gross_unlock(dev);
21945 +
21946 + if (obj) {
21947 + T(YAFFS_TRACE_OS,
21948 + (TSTR("yaffs_lookup found %d\n"), obj->obj_id));
21949 +
21950 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
21951 +
21952 + if (inode) {
21953 + T(YAFFS_TRACE_OS,
21954 + (TSTR("yaffs_loookup dentry \n")));
21955 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
21956 + * d_add even if NULL inode */
21957 +#if 0
21958 + /*dget(dentry); // try to solve directory bug */
21959 + d_add(dentry, inode);
21960 +
21961 + /* return dentry; */
21962 + return NULL;
21963 +#endif
21964 + }
21965 +
21966 + } else {
21967 + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
21968 +
21969 + }
21970 +
21971 +/* added NCB for 2.5/6 compatability - forces add even if inode is
21972 + * NULL which creates dentry hash */
21973 + d_add(dentry, inode);
21974 +
21975 + return NULL;
21976 +}
21977 +
21978 +
21979 +#ifdef YAFFS_HAS_PUT_INODE
21980 +
21981 +/* For now put inode is just for debugging
21982 + * Put inode is called when the inode **structure** is put.
21983 + */
21984 +static void yaffs_put_inode(struct inode *inode)
21985 +{
21986 + T(YAFFS_TRACE_OS,
21987 + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
21988 + atomic_read(&inode->i_count)));
21989 +
21990 +}
21991 +#endif
21992 +
21993 +
21994 +static void yaffs_unstitch_obj(struct inode *inode, yaffs_obj_t *obj)
21995 +{
21996 + /* Clear the association between the inode and
21997 + * the yaffs_obj_t.
21998 + */
21999 + obj->my_inode = NULL;
22000 + yaffs_InodeToObjectLV(inode) = NULL;
22001 +
22002 + /* If the object freeing was deferred, then the real
22003 + * free happens now.
22004 + * This should fix the inode inconsistency problem.
22005 + */
22006 + yaffs_handle_defered_free(obj);
22007 +}
22008 +
22009 +#ifdef YAFFS_HAS_EVICT_INODE
22010 +/* yaffs_evict_inode combines into one operation what was previously done in
22011 + * yaffs_clear_inode() and yaffs_delete_inode()
22012 + *
22013 + */
22014 +static void yaffs_evict_inode( struct inode *inode)
22015 +{
22016 + yaffs_obj_t *obj;
22017 + yaffs_dev_t *dev;
22018 + int deleteme = 0;
22019 +
22020 + obj = yaffs_InodeToObject(inode);
22021 +
22022 + T(YAFFS_TRACE_OS,
22023 + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22024 + atomic_read(&inode->i_count),
22025 + obj ? "object exists" : "null object"));
22026 +
22027 + if (!inode->i_nlink && !is_bad_inode(inode))
22028 + deleteme = 1;
22029 + truncate_inode_pages(&inode->i_data,0);
22030 + end_writeback(inode);
22031 +
22032 + if(deleteme && obj){
22033 + dev = obj->my_dev;
22034 + yaffs_gross_lock(dev);
22035 + yaffs_del_obj(obj);
22036 + yaffs_gross_unlock(dev);
22037 + }
22038 + if (obj) {
22039 + dev = obj->my_dev;
22040 + yaffs_gross_lock(dev);
22041 + yaffs_unstitch_obj(inode,obj);
22042 + yaffs_gross_unlock(dev);
22043 + }
22044 +
22045 +
22046 +}
22047 +#else
22048 +
22049 +/* clear is called to tell the fs to release any per-inode data it holds.
22050 + * The object might still exist on disk and is just being thrown out of the cache
22051 + * or else the object has actually been deleted and we're being called via
22052 + * the chain
22053 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
22054 + */
22055 +
22056 +static void yaffs_clear_inode(struct inode *inode)
22057 +{
22058 + yaffs_obj_t *obj;
22059 + yaffs_dev_t *dev;
22060 +
22061 + obj = yaffs_InodeToObject(inode);
22062 +
22063 + T(YAFFS_TRACE_OS,
22064 + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22065 + atomic_read(&inode->i_count),
22066 + obj ? "object exists" : "null object"));
22067 +
22068 + if (obj) {
22069 + dev = obj->my_dev;
22070 + yaffs_gross_lock(dev);
22071 + yaffs_unstitch_obj(inode,obj);
22072 + yaffs_gross_unlock(dev);
22073 + }
22074 +
22075 +}
22076 +
22077 +/* delete is called when the link count is zero and the inode
22078 + * is put (ie. nobody wants to know about it anymore, time to
22079 + * delete the file).
22080 + * NB Must call clear_inode()
22081 + */
22082 +static void yaffs_delete_inode(struct inode *inode)
22083 +{
22084 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
22085 + yaffs_dev_t *dev;
22086 +
22087 + T(YAFFS_TRACE_OS,
22088 + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
22089 + atomic_read(&inode->i_count),
22090 + obj ? "object exists" : "null object"));
22091 +
22092 + if (obj) {
22093 + dev = obj->my_dev;
22094 + yaffs_gross_lock(dev);
22095 + yaffs_del_obj(obj);
22096 + yaffs_gross_unlock(dev);
22097 + }
22098 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
22099 + truncate_inode_pages(&inode->i_data, 0);
22100 +#endif
22101 + clear_inode(inode);
22102 +}
22103 +#endif
22104 +
22105 +
22106 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
22107 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
22108 +#else
22109 +static int yaffs_file_flush(struct file *file)
22110 +#endif
22111 +{
22112 + yaffs_obj_t *obj = yaffs_dentry_to_obj(file->f_dentry);
22113 +
22114 + yaffs_dev_t *dev = obj->my_dev;
22115 +
22116 + T(YAFFS_TRACE_OS,
22117 + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id,
22118 + obj->dirty ? "dirty" : "clean"));
22119 +
22120 + yaffs_gross_lock(dev);
22121 +
22122 + yaffs_flush_file(obj, 1, 0);
22123 +
22124 + yaffs_gross_unlock(dev);
22125 +
22126 + return 0;
22127 +}
22128 +
22129 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
22130 +{
22131 + /* Lifted from jffs2 */
22132 +
22133 + yaffs_obj_t *obj;
22134 + unsigned char *pg_buf;
22135 + int ret;
22136 +
22137 + yaffs_dev_t *dev;
22138 +
22139 + T(YAFFS_TRACE_OS,
22140 + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
22141 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
22142 + (unsigned)PAGE_CACHE_SIZE));
22143 +
22144 + obj = yaffs_dentry_to_obj(f->f_dentry);
22145 +
22146 + dev = obj->my_dev;
22147 +
22148 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22149 + BUG_ON(!PageLocked(pg));
22150 +#else
22151 + if (!PageLocked(pg))
22152 + PAGE_BUG(pg);
22153 +#endif
22154 +
22155 + pg_buf = kmap(pg);
22156 + /* FIXME: Can kmap fail? */
22157 +
22158 + yaffs_gross_lock(dev);
22159 +
22160 + ret = yaffs_file_rd(obj, pg_buf,
22161 + pg->index << PAGE_CACHE_SHIFT,
22162 + PAGE_CACHE_SIZE);
22163 +
22164 + yaffs_gross_unlock(dev);
22165 +
22166 + if (ret >= 0)
22167 + ret = 0;
22168 +
22169 + if (ret) {
22170 + ClearPageUptodate(pg);
22171 + SetPageError(pg);
22172 + } else {
22173 + SetPageUptodate(pg);
22174 + ClearPageError(pg);
22175 + }
22176 +
22177 + flush_dcache_page(pg);
22178 + kunmap(pg);
22179 +
22180 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
22181 + return ret;
22182 +}
22183 +
22184 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
22185 +{
22186 + int ret = yaffs_readpage_nolock(f, pg);
22187 + UnlockPage(pg);
22188 + return ret;
22189 +}
22190 +
22191 +static int yaffs_readpage(struct file *f, struct page *pg)
22192 +{
22193 + int ret;
22194 +
22195 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
22196 + ret=yaffs_readpage_unlock(f, pg);
22197 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
22198 + return ret;
22199 +}
22200 +
22201 +/* writepage inspired by/stolen from smbfs */
22202 +
22203 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22204 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
22205 +#else
22206 +static int yaffs_writepage(struct page *page)
22207 +#endif
22208 +{
22209 + yaffs_dev_t *dev;
22210 + struct address_space *mapping = page->mapping;
22211 + struct inode *inode;
22212 + unsigned long end_index;
22213 + char *buffer;
22214 + yaffs_obj_t *obj;
22215 + int nWritten = 0;
22216 + unsigned n_bytes;
22217 + loff_t i_size;
22218 +
22219 + if (!mapping)
22220 + BUG();
22221 + inode = mapping->host;
22222 + if (!inode)
22223 + BUG();
22224 + i_size = i_size_read(inode);
22225 +
22226 + end_index = i_size >> PAGE_CACHE_SHIFT;
22227 +
22228 + if(page->index < end_index)
22229 + n_bytes = PAGE_CACHE_SIZE;
22230 + else {
22231 + n_bytes = i_size & (PAGE_CACHE_SIZE -1);
22232 +
22233 + if (page->index > end_index || !n_bytes) {
22234 + T(YAFFS_TRACE_OS,
22235 + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
22236 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
22237 + (unsigned)inode->i_size));
22238 + T(YAFFS_TRACE_OS,
22239 + (TSTR(" -> don't care!!\n")));
22240 +
22241 + zero_user_segment(page,0,PAGE_CACHE_SIZE);
22242 + set_page_writeback(page);
22243 + unlock_page(page);
22244 + end_page_writeback(page);
22245 + return 0;
22246 + }
22247 + }
22248 +
22249 + if(n_bytes != PAGE_CACHE_SIZE)
22250 + zero_user_segment(page,n_bytes,PAGE_CACHE_SIZE);
22251 +
22252 + get_page(page);
22253 +
22254 + buffer = kmap(page);
22255 +
22256 + obj = yaffs_InodeToObject(inode);
22257 + dev = obj->my_dev;
22258 + yaffs_gross_lock(dev);
22259 +
22260 + T(YAFFS_TRACE_OS,
22261 + (TSTR("yaffs_writepage at %08x, size %08x\n"),
22262 + (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes));
22263 + T(YAFFS_TRACE_OS,
22264 + (TSTR("writepag0: obj = %05x, ino = %05x\n"),
22265 + (int)obj->variant.file_variant.file_size, (int)inode->i_size));
22266 +
22267 + nWritten = yaffs_wr_file(obj, buffer,
22268 + page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
22269 +
22270 + yaffs_touch_super(dev);
22271 +
22272 + T(YAFFS_TRACE_OS,
22273 + (TSTR("writepag1: obj = %05x, ino = %05x\n"),
22274 + (int)obj->variant.file_variant.file_size, (int)inode->i_size));
22275 +
22276 + yaffs_gross_unlock(dev);
22277 +
22278 + kunmap(page);
22279 + set_page_writeback(page);
22280 + unlock_page(page);
22281 + end_page_writeback(page);
22282 + put_page(page);
22283 +
22284 + return (nWritten == n_bytes) ? 0 : -ENOSPC;
22285 +}
22286 +
22287 +
22288 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
22289 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
22290 + loff_t pos, unsigned len, unsigned flags,
22291 + struct page **pagep, void **fsdata)
22292 +{
22293 + struct page *pg = NULL;
22294 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
22295 +
22296 + int ret = 0;
22297 + int space_held = 0;
22298 +
22299 + /* Get a page */
22300 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
22301 + pg = grab_cache_page_write_begin(mapping, index, flags);
22302 +#else
22303 + pg = __grab_cache_page(mapping, index);
22304 +#endif
22305 +
22306 + *pagep = pg;
22307 + if (!pg) {
22308 + ret = -ENOMEM;
22309 + goto out;
22310 + }
22311 + T(YAFFS_TRACE_OS,
22312 + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
22313 + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
22314 +
22315 + /* Get fs space */
22316 + space_held = yaffs_hold_space(filp);
22317 +
22318 + if (!space_held) {
22319 + ret = -ENOSPC;
22320 + goto out;
22321 + }
22322 +
22323 + /* Update page if required */
22324 +
22325 + if (!Page_Uptodate(pg))
22326 + ret = yaffs_readpage_nolock(filp, pg);
22327 +
22328 + if (ret)
22329 + goto out;
22330 +
22331 + /* Happy path return */
22332 + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
22333 +
22334 + return 0;
22335 +
22336 +out:
22337 + T(YAFFS_TRACE_OS,
22338 + (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
22339 + if (space_held)
22340 + yaffs_release_space(filp);
22341 + if (pg) {
22342 + unlock_page(pg);
22343 + page_cache_release(pg);
22344 + }
22345 + return ret;
22346 +}
22347 +
22348 +#else
22349 +
22350 +static int yaffs_prepare_write(struct file *f, struct page *pg,
22351 + unsigned offset, unsigned to)
22352 +{
22353 + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
22354 +
22355 + if (!Page_Uptodate(pg))
22356 + return yaffs_readpage_nolock(f, pg);
22357 + return 0;
22358 +}
22359 +#endif
22360 +
22361 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
22362 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
22363 + loff_t pos, unsigned len, unsigned copied,
22364 + struct page *pg, void *fsdadata)
22365 +{
22366 + int ret = 0;
22367 + void *addr, *kva;
22368 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
22369 +
22370 + kva = kmap(pg);
22371 + addr = kva + offset_into_page;
22372 +
22373 + T(YAFFS_TRACE_OS,
22374 + ("yaffs_write_end addr %p pos %x n_bytes %d\n",
22375 + addr,(unsigned)pos, copied));
22376 +
22377 + ret = yaffs_file_write(filp, addr, copied, &pos);
22378 +
22379 + if (ret != copied) {
22380 + T(YAFFS_TRACE_OS,
22381 + (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
22382 + ret, copied));
22383 + SetPageError(pg);
22384 + } else {
22385 + /* Nothing */
22386 + }
22387 +
22388 + kunmap(pg);
22389 +
22390 + yaffs_release_space(filp);
22391 + unlock_page(pg);
22392 + page_cache_release(pg);
22393 + return ret;
22394 +}
22395 +#else
22396 +
22397 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
22398 + unsigned to)
22399 +{
22400 + void *addr, *kva;
22401 +
22402 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
22403 + int n_bytes = to - offset;
22404 + int nWritten;
22405 +
22406 + unsigned spos = pos;
22407 + unsigned saddr;
22408 +
22409 + kva = kmap(pg);
22410 + addr = kva + offset;
22411 +
22412 + saddr = (unsigned) addr;
22413 +
22414 + T(YAFFS_TRACE_OS,
22415 + (TSTR("yaffs_commit_write addr %x pos %x n_bytes %d\n"),
22416 + saddr, spos, n_bytes));
22417 +
22418 + nWritten = yaffs_file_write(f, addr, n_bytes, &pos);
22419 +
22420 + if (nWritten != n_bytes) {
22421 + T(YAFFS_TRACE_OS,
22422 + (TSTR("yaffs_commit_write not same size nWritten %d n_bytes %d\n"),
22423 + nWritten, n_bytes));
22424 + SetPageError(pg);
22425 + } else {
22426 + /* Nothing */
22427 + }
22428 +
22429 + kunmap(pg);
22430 +
22431 + T(YAFFS_TRACE_OS,
22432 + (TSTR("yaffs_commit_write returning %d\n"),
22433 + nWritten == n_bytes ? 0 : nWritten));
22434 +
22435 + return nWritten == n_bytes ? 0 : nWritten;
22436 +}
22437 +#endif
22438 +
22439 +
22440 +static void yaffs_fill_inode_from_obj(struct inode *inode, yaffs_obj_t *obj)
22441 +{
22442 + if (inode && obj) {
22443 +
22444 +
22445 + /* Check mode against the variant type and attempt to repair if broken. */
22446 + __u32 mode = obj->yst_mode;
22447 + switch (obj->variant_type) {
22448 + case YAFFS_OBJECT_TYPE_FILE:
22449 + if (!S_ISREG(mode)) {
22450 + obj->yst_mode &= ~S_IFMT;
22451 + obj->yst_mode |= S_IFREG;
22452 + }
22453 +
22454 + break;
22455 + case YAFFS_OBJECT_TYPE_SYMLINK:
22456 + if (!S_ISLNK(mode)) {
22457 + obj->yst_mode &= ~S_IFMT;
22458 + obj->yst_mode |= S_IFLNK;
22459 + }
22460 +
22461 + break;
22462 + case YAFFS_OBJECT_TYPE_DIRECTORY:
22463 + if (!S_ISDIR(mode)) {
22464 + obj->yst_mode &= ~S_IFMT;
22465 + obj->yst_mode |= S_IFDIR;
22466 + }
22467 +
22468 + break;
22469 + case YAFFS_OBJECT_TYPE_UNKNOWN:
22470 + case YAFFS_OBJECT_TYPE_HARDLINK:
22471 + case YAFFS_OBJECT_TYPE_SPECIAL:
22472 + default:
22473 + /* TODO? */
22474 + break;
22475 + }
22476 +
22477 + inode->i_flags |= S_NOATIME;
22478 +
22479 + inode->i_ino = obj->obj_id;
22480 + inode->i_mode = obj->yst_mode;
22481 + inode->i_uid = obj->yst_uid;
22482 + inode->i_gid = obj->yst_gid;
22483 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
22484 + inode->i_blksize = inode->i_sb->s_blocksize;
22485 +#endif
22486 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22487 +
22488 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
22489 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
22490 + inode->i_atime.tv_nsec = 0;
22491 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
22492 + inode->i_mtime.tv_nsec = 0;
22493 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
22494 + inode->i_ctime.tv_nsec = 0;
22495 +#else
22496 + inode->i_rdev = obj->yst_rdev;
22497 + inode->i_atime = obj->yst_atime;
22498 + inode->i_mtime = obj->yst_mtime;
22499 + inode->i_ctime = obj->yst_ctime;
22500 +#endif
22501 + inode->i_size = yaffs_get_obj_length(obj);
22502 + inode->i_blocks = (inode->i_size + 511) >> 9;
22503 +
22504 + inode->i_nlink = yaffs_get_obj_link_count(obj);
22505 +
22506 + T(YAFFS_TRACE_OS,
22507 + (TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
22508 + inode->i_mode, inode->i_uid, inode->i_gid,
22509 + (int)inode->i_size, atomic_read(&inode->i_count)));
22510 +
22511 + switch (obj->yst_mode & S_IFMT) {
22512 + default: /* fifo, device or socket */
22513 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22514 + init_special_inode(inode, obj->yst_mode,
22515 + old_decode_dev(obj->yst_rdev));
22516 +#else
22517 + init_special_inode(inode, obj->yst_mode,
22518 + (dev_t) (obj->yst_rdev));
22519 +#endif
22520 + break;
22521 + case S_IFREG: /* file */
22522 + inode->i_op = &yaffs_file_inode_operations;
22523 + inode->i_fop = &yaffs_file_operations;
22524 + inode->i_mapping->a_ops =
22525 + &yaffs_file_address_operations;
22526 + break;
22527 + case S_IFDIR: /* directory */
22528 + inode->i_op = &yaffs_dir_inode_operations;
22529 + inode->i_fop = &yaffs_dir_operations;
22530 + break;
22531 + case S_IFLNK: /* symlink */
22532 + inode->i_op = &yaffs_symlink_inode_operations;
22533 + break;
22534 + }
22535 +
22536 + yaffs_InodeToObjectLV(inode) = obj;
22537 +
22538 + obj->my_inode = inode;
22539 +
22540 + } else {
22541 + T(YAFFS_TRACE_OS,
22542 + (TSTR("yaffs_FileInode invalid parameters\n")));
22543 + }
22544 +
22545 +}
22546 +
22547 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
22548 + yaffs_obj_t *obj)
22549 +{
22550 + struct inode *inode;
22551 +
22552 + if (!sb) {
22553 + T(YAFFS_TRACE_OS,
22554 + (TSTR("yaffs_get_inode for NULL super_block!!\n")));
22555 + return NULL;
22556 +
22557 + }
22558 +
22559 + if (!obj) {
22560 + T(YAFFS_TRACE_OS,
22561 + (TSTR("yaffs_get_inode for NULL object!!\n")));
22562 + return NULL;
22563 +
22564 + }
22565 +
22566 + T(YAFFS_TRACE_OS,
22567 + (TSTR("yaffs_get_inode for object %d\n"), obj->obj_id));
22568 +
22569 + inode = Y_IGET(sb, obj->obj_id);
22570 + if (IS_ERR(inode))
22571 + return NULL;
22572 +
22573 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
22574 + /* iget also increments the inode's i_count */
22575 + /* NB You can't be holding grossLock or deadlock will happen! */
22576 +
22577 + return inode;
22578 +}
22579 +
22580 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
22581 + loff_t *pos)
22582 +{
22583 + yaffs_obj_t *obj;
22584 + int nWritten, ipos;
22585 + struct inode *inode;
22586 + yaffs_dev_t *dev;
22587 +
22588 + obj = yaffs_dentry_to_obj(f->f_dentry);
22589 +
22590 + dev = obj->my_dev;
22591 +
22592 + yaffs_gross_lock(dev);
22593 +
22594 + inode = f->f_dentry->d_inode;
22595 +
22596 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
22597 + ipos = inode->i_size;
22598 + else
22599 + ipos = *pos;
22600 +
22601 + if (!obj)
22602 + T(YAFFS_TRACE_OS,
22603 + (TSTR("yaffs_file_write: hey obj is null!\n")));
22604 + else
22605 + T(YAFFS_TRACE_OS,
22606 + (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
22607 + "to object %d at %d(%x)\n"),
22608 + (unsigned) n, (unsigned) n, obj->obj_id, ipos,ipos));
22609 +
22610 + nWritten = yaffs_wr_file(obj, buf, ipos, n, 0);
22611 +
22612 + yaffs_touch_super(dev);
22613 +
22614 + T(YAFFS_TRACE_OS,
22615 + (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
22616 + (unsigned )n,(unsigned)n));
22617 +
22618 + if (nWritten > 0) {
22619 + ipos += nWritten;
22620 + *pos = ipos;
22621 + if (ipos > inode->i_size) {
22622 + inode->i_size = ipos;
22623 + inode->i_blocks = (ipos + 511) >> 9;
22624 +
22625 + T(YAFFS_TRACE_OS,
22626 + (TSTR("yaffs_file_write size updated to %d bytes, "
22627 + "%d blocks\n"),
22628 + ipos, (int)(inode->i_blocks)));
22629 + }
22630 +
22631 + }
22632 + yaffs_gross_unlock(dev);
22633 + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
22634 +}
22635 +
22636 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
22637 +/* For now we just assume few parallel writes and check against a small number. */
22638 +/* Todo: need to do this with a counter to handle parallel reads better */
22639 +
22640 +static ssize_t yaffs_hold_space(struct file *f)
22641 +{
22642 + yaffs_obj_t *obj;
22643 + yaffs_dev_t *dev;
22644 +
22645 + int n_free_chunks;
22646 +
22647 +
22648 + obj = yaffs_dentry_to_obj(f->f_dentry);
22649 +
22650 + dev = obj->my_dev;
22651 +
22652 + yaffs_gross_lock(dev);
22653 +
22654 + n_free_chunks = yaffs_get_n_free_chunks(dev);
22655 +
22656 + yaffs_gross_unlock(dev);
22657 +
22658 + return (n_free_chunks > 20) ? 1 : 0;
22659 +}
22660 +
22661 +static void yaffs_release_space(struct file *f)
22662 +{
22663 + yaffs_obj_t *obj;
22664 + yaffs_dev_t *dev;
22665 +
22666 +
22667 + obj = yaffs_dentry_to_obj(f->f_dentry);
22668 +
22669 + dev = obj->my_dev;
22670 +
22671 + yaffs_gross_lock(dev);
22672 +
22673 +
22674 + yaffs_gross_unlock(dev);
22675 +}
22676 +
22677 +
22678 +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
22679 +{
22680 + long long retval;
22681 +
22682 + lock_kernel();
22683 +
22684 + switch (origin){
22685 + case 2:
22686 + offset += i_size_read(file->f_path.dentry->d_inode);
22687 + break;
22688 + case 1:
22689 + offset += file->f_pos;
22690 + }
22691 + retval = -EINVAL;
22692 +
22693 + if (offset >= 0){
22694 + if (offset != file->f_pos)
22695 + file->f_pos = offset;
22696 +
22697 + retval = offset;
22698 + }
22699 + unlock_kernel();
22700 + return retval;
22701 +}
22702 +
22703 +
22704 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
22705 +{
22706 + yaffs_obj_t *obj;
22707 + yaffs_dev_t *dev;
22708 + struct yaffs_SearchContext *sc;
22709 + struct inode *inode = f->f_dentry->d_inode;
22710 + unsigned long offset, curoffs;
22711 + yaffs_obj_t *l;
22712 + int retVal = 0;
22713 +
22714 + char name[YAFFS_MAX_NAME_LENGTH + 1];
22715 +
22716 + obj = yaffs_dentry_to_obj(f->f_dentry);
22717 + dev = obj->my_dev;
22718 +
22719 + yaffs_gross_lock(dev);
22720 +
22721 + yaffs_dev_to_lc(dev)->readdirProcess = current;
22722 +
22723 + offset = f->f_pos;
22724 +
22725 + sc = yaffs_NewSearch(obj);
22726 + if(!sc){
22727 + retVal = -ENOMEM;
22728 + goto out;
22729 + }
22730 +
22731 + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
22732 +
22733 + if (offset == 0) {
22734 + T(YAFFS_TRACE_OS,
22735 + (TSTR("yaffs_readdir: entry . ino %d \n"),
22736 + (int)inode->i_ino));
22737 + yaffs_gross_unlock(dev);
22738 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
22739 + yaffs_gross_lock(dev);
22740 + goto out;
22741 + }
22742 + yaffs_gross_lock(dev);
22743 + offset++;
22744 + f->f_pos++;
22745 + }
22746 + if (offset == 1) {
22747 + T(YAFFS_TRACE_OS,
22748 + (TSTR("yaffs_readdir: entry .. ino %d \n"),
22749 + (int)f->f_dentry->d_parent->d_inode->i_ino));
22750 + yaffs_gross_unlock(dev);
22751 + if (filldir(dirent, "..", 2, offset,
22752 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
22753 + yaffs_gross_lock(dev);
22754 + goto out;
22755 + }
22756 + yaffs_gross_lock(dev);
22757 + offset++;
22758 + f->f_pos++;
22759 + }
22760 +
22761 + curoffs = 1;
22762 +
22763 + /* If the directory has changed since the open or last call to
22764 + readdir, rewind to after the 2 canned entries. */
22765 + if (f->f_version != inode->i_version) {
22766 + offset = 2;
22767 + f->f_pos = offset;
22768 + f->f_version = inode->i_version;
22769 + }
22770 +
22771 + while(sc->nextReturn){
22772 + curoffs++;
22773 + l = sc->nextReturn;
22774 + if (curoffs >= offset) {
22775 + int this_inode = yaffs_get_obj_inode(l);
22776 + int this_type = yaffs_get_obj_type(l);
22777 +
22778 + yaffs_get_obj_name(l, name,
22779 + YAFFS_MAX_NAME_LENGTH + 1);
22780 + T(YAFFS_TRACE_OS,
22781 + (TSTR("yaffs_readdir: %s inode %d\n"),
22782 + name, yaffs_get_obj_inode(l)));
22783 +
22784 + yaffs_gross_unlock(dev);
22785 +
22786 + if (filldir(dirent,
22787 + name,
22788 + strlen(name),
22789 + offset,
22790 + this_inode,
22791 + this_type) < 0){
22792 + yaffs_gross_lock(dev);
22793 + goto out;
22794 + }
22795 +
22796 + yaffs_gross_lock(dev);
22797 +
22798 + offset++;
22799 + f->f_pos++;
22800 + }
22801 + yaffs_search_advance(sc);
22802 + }
22803 +
22804 +out:
22805 + yaffs_search_end(sc);
22806 + yaffs_dev_to_lc(dev)->readdirProcess = NULL;
22807 + yaffs_gross_unlock(dev);
22808 +
22809 + return retVal;
22810 +}
22811 +
22812 +
22813 +
22814 +/*
22815 + * File creation. Allocate an inode, and we're done..
22816 + */
22817 +
22818 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
22819 +#define YCRED(x) x
22820 +#else
22821 +#define YCRED(x) (x->cred)
22822 +#endif
22823 +
22824 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22825 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
22826 + dev_t rdev)
22827 +#else
22828 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
22829 + int rdev)
22830 +#endif
22831 +{
22832 + struct inode *inode;
22833 +
22834 + yaffs_obj_t *obj = NULL;
22835 + yaffs_dev_t *dev;
22836 +
22837 + yaffs_obj_t *parent = yaffs_InodeToObject(dir);
22838 +
22839 + int error = -ENOSPC;
22840 + uid_t uid = YCRED(current)->fsuid;
22841 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
22842 +
22843 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
22844 + mode |= S_ISGID;
22845 +
22846 + if (parent) {
22847 + T(YAFFS_TRACE_OS,
22848 + (TSTR("yaffs_mknod: parent object %d type %d\n"),
22849 + parent->obj_id, parent->variant_type));
22850 + } else {
22851 + T(YAFFS_TRACE_OS,
22852 + (TSTR("yaffs_mknod: could not get parent object\n")));
22853 + return -EPERM;
22854 + }
22855 +
22856 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
22857 + "mode %x dev %x\n"),
22858 + dentry->d_name.name, mode, rdev));
22859 +
22860 + dev = parent->my_dev;
22861 +
22862 + yaffs_gross_lock(dev);
22863 +
22864 + switch (mode & S_IFMT) {
22865 + default:
22866 + /* Special (socket, fifo, device...) */
22867 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
22868 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22869 + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
22870 + gid, old_encode_dev(rdev));
22871 +#else
22872 + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
22873 + gid, rdev);
22874 +#endif
22875 + break;
22876 + case S_IFREG: /* file */
22877 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
22878 + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
22879 + gid);
22880 + break;
22881 + case S_IFDIR: /* directory */
22882 + T(YAFFS_TRACE_OS,
22883 + (TSTR("yaffs_mknod: making directory\n")));
22884 + obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
22885 + uid, gid);
22886 + break;
22887 + case S_IFLNK: /* symlink */
22888 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
22889 + obj = NULL; /* Do we ever get here? */
22890 + break;
22891 + }
22892 +
22893 + /* Can not call yaffs_get_inode() with gross lock held */
22894 + yaffs_gross_unlock(dev);
22895 +
22896 + if (obj) {
22897 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
22898 + d_instantiate(dentry, inode);
22899 + update_dir_time(dir);
22900 + T(YAFFS_TRACE_OS,
22901 + (TSTR("yaffs_mknod created object %d count = %d\n"),
22902 + obj->obj_id, atomic_read(&inode->i_count)));
22903 + error = 0;
22904 + yaffs_fill_inode_from_obj(dir,parent);
22905 + } else {
22906 + T(YAFFS_TRACE_OS,
22907 + (TSTR("yaffs_mknod failed making object\n")));
22908 + error = -ENOMEM;
22909 + }
22910 +
22911 + return error;
22912 +}
22913 +
22914 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
22915 +{
22916 + int retVal;
22917 + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
22918 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
22919 + return retVal;
22920 +}
22921 +
22922 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
22923 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
22924 + struct nameidata *n)
22925 +#else
22926 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
22927 +#endif
22928 +{
22929 + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
22930 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
22931 +}
22932 +
22933 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
22934 +{
22935 + int retVal;
22936 +
22937 + yaffs_dev_t *dev;
22938 + yaffs_obj_t *obj;
22939 +
22940 + T(YAFFS_TRACE_OS,
22941 + (TSTR("yaffs_unlink %d:%s\n"),
22942 + (int)(dir->i_ino),
22943 + dentry->d_name.name));
22944 + obj = yaffs_InodeToObject(dir);
22945 + dev = obj->my_dev;
22946 +
22947 + yaffs_gross_lock(dev);
22948 +
22949 + retVal = yaffs_unlinker(obj, dentry->d_name.name);
22950 +
22951 + if (retVal == YAFFS_OK) {
22952 + dentry->d_inode->i_nlink--;
22953 + dir->i_version++;
22954 + yaffs_gross_unlock(dev);
22955 + mark_inode_dirty(dentry->d_inode);
22956 + update_dir_time(dir);
22957 + return 0;
22958 + }
22959 + yaffs_gross_unlock(dev);
22960 + return -ENOTEMPTY;
22961 +}
22962 +
22963 +/*
22964 + * Create a link...
22965 + */
22966 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
22967 + struct dentry *dentry)
22968 +{
22969 + struct inode *inode = old_dentry->d_inode;
22970 + yaffs_obj_t *obj = NULL;
22971 + yaffs_obj_t *link = NULL;
22972 + yaffs_dev_t *dev;
22973 +
22974 + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
22975 +
22976 + obj = yaffs_InodeToObject(inode);
22977 + dev = obj->my_dev;
22978 +
22979 + yaffs_gross_lock(dev);
22980 +
22981 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
22982 + link = yaffs_link_obj(yaffs_InodeToObject(dir), dentry->d_name.name,
22983 + obj);
22984 +
22985 + if (link) {
22986 + old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
22987 + d_instantiate(dentry, old_dentry->d_inode);
22988 + atomic_inc(&old_dentry->d_inode->i_count);
22989 + T(YAFFS_TRACE_OS,
22990 + (TSTR("yaffs_link link count %d i_count %d\n"),
22991 + old_dentry->d_inode->i_nlink,
22992 + atomic_read(&old_dentry->d_inode->i_count)));
22993 + }
22994 +
22995 + yaffs_gross_unlock(dev);
22996 +
22997 + if (link){
22998 + update_dir_time(dir);
22999 + return 0;
23000 + }
23001 +
23002 + return -EPERM;
23003 +}
23004 +
23005 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
23006 + const char *symname)
23007 +{
23008 + yaffs_obj_t *obj;
23009 + yaffs_dev_t *dev;
23010 + uid_t uid = YCRED(current)->fsuid;
23011 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
23012 +
23013 + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
23014 +
23015 + dev = yaffs_InodeToObject(dir)->my_dev;
23016 + yaffs_gross_lock(dev);
23017 + obj = yaffs_create_symlink(yaffs_InodeToObject(dir), dentry->d_name.name,
23018 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
23019 + yaffs_gross_unlock(dev);
23020 +
23021 + if (obj) {
23022 + struct inode *inode;
23023 +
23024 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
23025 + d_instantiate(dentry, inode);
23026 + update_dir_time(dir);
23027 + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
23028 + return 0;
23029 + } else {
23030 + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
23031 + }
23032 +
23033 + return -ENOMEM;
23034 +}
23035 +
23036 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
23037 +static int yaffs_sync_object(struct file *file, int datasync)
23038 +#else
23039 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
23040 + int datasync)
23041 +#endif
23042 +{
23043 +
23044 + yaffs_obj_t *obj;
23045 + yaffs_dev_t *dev;
23046 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
23047 + struct dentry *dentry = file->f_path.dentry;
23048 +#endif
23049 +
23050 + obj = yaffs_dentry_to_obj(dentry);
23051 +
23052 + dev = obj->my_dev;
23053 +
23054 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
23055 + (TSTR("yaffs_sync_object\n")));
23056 + yaffs_gross_lock(dev);
23057 + yaffs_flush_file(obj, 1, datasync);
23058 + yaffs_gross_unlock(dev);
23059 + return 0;
23060 +}
23061 +
23062 +/*
23063 + * The VFS layer already does all the dentry stuff for rename.
23064 + *
23065 + * NB: POSIX says you can rename an object over an old object of the same name
23066 + */
23067 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
23068 + struct inode *new_dir, struct dentry *new_dentry)
23069 +{
23070 + yaffs_dev_t *dev;
23071 + int retVal = YAFFS_FAIL;
23072 + yaffs_obj_t *target;
23073 +
23074 + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
23075 + dev = yaffs_InodeToObject(old_dir)->my_dev;
23076 +
23077 + yaffs_gross_lock(dev);
23078 +
23079 + /* Check if the target is an existing directory that is not empty. */
23080 + target = yaffs_find_by_name(yaffs_InodeToObject(new_dir),
23081 + new_dentry->d_name.name);
23082 +
23083 +
23084 +
23085 + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
23086 + !ylist_empty(&target->variant.dir_variant.children)) {
23087 +
23088 + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
23089 +
23090 + retVal = YAFFS_FAIL;
23091 + } else {
23092 + /* Now does unlinking internally using shadowing mechanism */
23093 + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_rename_obj\n")));
23094 +
23095 + retVal = yaffs_rename_obj(yaffs_InodeToObject(old_dir),
23096 + old_dentry->d_name.name,
23097 + yaffs_InodeToObject(new_dir),
23098 + new_dentry->d_name.name);
23099 + }
23100 + yaffs_gross_unlock(dev);
23101 +
23102 + if (retVal == YAFFS_OK) {
23103 + if (target) {
23104 + new_dentry->d_inode->i_nlink--;
23105 + mark_inode_dirty(new_dentry->d_inode);
23106 + }
23107 +
23108 + update_dir_time(old_dir);
23109 + if(old_dir != new_dir)
23110 + update_dir_time(new_dir);
23111 + return 0;
23112 + } else {
23113 + return -ENOTEMPTY;
23114 + }
23115 +}
23116 +
23117 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
23118 +{
23119 + struct inode *inode = dentry->d_inode;
23120 + int error = 0;
23121 + yaffs_dev_t *dev;
23122 +
23123 + T(YAFFS_TRACE_OS,
23124 + (TSTR("yaffs_setattr of object %d\n"),
23125 + yaffs_InodeToObject(inode)->obj_id));
23126 +
23127 + /* Fail if a requested resize >= 2GB */
23128 + if (attr->ia_valid & ATTR_SIZE &&
23129 + (attr->ia_size >> 31))
23130 + error = -EINVAL;
23131 +
23132 + if (error == 0)
23133 + error = inode_change_ok(inode, attr);
23134 + if (error == 0) {
23135 + int result;
23136 + if (!error){
23137 + error = yaffs_vfs_setattr(inode, attr);
23138 + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
23139 + if (attr->ia_valid & ATTR_SIZE){
23140 + yaffs_vfs_setsize(inode,attr->ia_size);
23141 + inode->i_blocks = (inode->i_size + 511) >> 9;
23142 + }
23143 + }
23144 + dev = yaffs_InodeToObject(inode)->my_dev;
23145 + if (attr->ia_valid & ATTR_SIZE){
23146 + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
23147 + (int)(attr->ia_size),(int)(attr->ia_size)));
23148 + }
23149 + yaffs_gross_lock(dev);
23150 + result = yaffs_set_attribs(yaffs_InodeToObject(inode), attr);
23151 + if(result == YAFFS_OK) {
23152 + error = 0;
23153 + } else {
23154 + error = -EPERM;
23155 + }
23156 + yaffs_gross_unlock(dev);
23157 +
23158 + }
23159 +
23160 + T(YAFFS_TRACE_OS,
23161 + (TSTR("yaffs_setattr done returning %d\n"),error));
23162 +
23163 + return error;
23164 +}
23165 +
23166 +#ifdef CONFIG_YAFFS_XATTR
23167 +int yaffs_setxattr(struct dentry *dentry, const char *name,
23168 + const void *value, size_t size, int flags)
23169 +{
23170 + struct inode *inode = dentry->d_inode;
23171 + int error = 0;
23172 + yaffs_dev_t *dev;
23173 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23174 +
23175 + T(YAFFS_TRACE_OS,
23176 + (TSTR("yaffs_setxattr of object %d\n"),
23177 + obj->obj_id));
23178 +
23179 +
23180 + if (error == 0) {
23181 + int result;
23182 + dev = obj->my_dev;
23183 + yaffs_gross_lock(dev);
23184 + result = yaffs_set_xattrib(obj, name, value, size, flags);
23185 + if(result == YAFFS_OK)
23186 + error = 0;
23187 + else if(result < 0)
23188 + error = result;
23189 + yaffs_gross_unlock(dev);
23190 +
23191 + }
23192 + T(YAFFS_TRACE_OS,
23193 + (TSTR("yaffs_setxattr done returning %d\n"),error));
23194 +
23195 + return error;
23196 +}
23197 +
23198 +
23199 +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
23200 + size_t size)
23201 +{
23202 + struct inode *inode = dentry->d_inode;
23203 + int error = 0;
23204 + yaffs_dev_t *dev;
23205 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23206 +
23207 + T(YAFFS_TRACE_OS,
23208 + (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
23209 + name, obj->obj_id));
23210 +
23211 + if (error == 0) {
23212 + dev = obj->my_dev;
23213 + yaffs_gross_lock(dev);
23214 + error = yaffs_get_xattrib(obj, name, buff, size);
23215 + yaffs_gross_unlock(dev);
23216 +
23217 + }
23218 + T(YAFFS_TRACE_OS,
23219 + (TSTR("yaffs_getxattr done returning %d\n"),error));
23220 +
23221 + return error;
23222 +}
23223 +
23224 +int yaffs_removexattr(struct dentry *dentry, const char *name)
23225 +{
23226 + struct inode *inode = dentry->d_inode;
23227 + int error = 0;
23228 + yaffs_dev_t *dev;
23229 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23230 +
23231 + T(YAFFS_TRACE_OS,
23232 + (TSTR("yaffs_removexattr of object %d\n"),
23233 + obj->obj_id));
23234 +
23235 +
23236 + if (error == 0) {
23237 + int result;
23238 + dev = obj->my_dev;
23239 + yaffs_gross_lock(dev);
23240 + result = yaffs_remove_xattrib(obj, name);
23241 + if(result == YAFFS_OK)
23242 + error = 0;
23243 + else if(result < 0)
23244 + error = result;
23245 + yaffs_gross_unlock(dev);
23246 +
23247 + }
23248 + T(YAFFS_TRACE_OS,
23249 + (TSTR("yaffs_removexattr done returning %d\n"),error));
23250 +
23251 + return error;
23252 +}
23253 +
23254 +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
23255 +{
23256 + struct inode *inode = dentry->d_inode;
23257 + int error = 0;
23258 + yaffs_dev_t *dev;
23259 + yaffs_obj_t *obj = yaffs_InodeToObject(inode);
23260 +
23261 + T(YAFFS_TRACE_OS,
23262 + (TSTR("yaffs_listxattr of object %d\n"),
23263 + obj->obj_id));
23264 +
23265 +
23266 + if (error == 0) {
23267 + dev = obj->my_dev;
23268 + yaffs_gross_lock(dev);
23269 + error = yaffs_list_xattrib(obj, buff, size);
23270 + yaffs_gross_unlock(dev);
23271 +
23272 + }
23273 + T(YAFFS_TRACE_OS,
23274 + (TSTR("yaffs_listxattr done returning %d\n"),error));
23275 +
23276 + return error;
23277 +}
23278 +
23279 +#endif
23280 +
23281 +
23282 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23283 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
23284 +{
23285 + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
23286 + struct super_block *sb = dentry->d_sb;
23287 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
23288 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
23289 +{
23290 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23291 +#else
23292 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
23293 +{
23294 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23295 +#endif
23296 +
23297 + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
23298 +
23299 + yaffs_gross_lock(dev);
23300 +
23301 + buf->f_type = YAFFS_MAGIC;
23302 + buf->f_bsize = sb->s_blocksize;
23303 + buf->f_namelen = 255;
23304 +
23305 + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
23306 + /* Do this if chunk size is not a power of 2 */
23307 +
23308 + uint64_t bytesInDev;
23309 + uint64_t bytesFree;
23310 +
23311 + bytesInDev = ((uint64_t)((dev->param.end_block - dev->param.start_block + 1))) *
23312 + ((uint64_t)(dev->param.chunks_per_block * dev->data_bytes_per_chunk));
23313 +
23314 + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
23315 + buf->f_blocks = bytesInDev;
23316 +
23317 + bytesFree = ((uint64_t)(yaffs_get_n_free_chunks(dev))) *
23318 + ((uint64_t)(dev->data_bytes_per_chunk));
23319 +
23320 + do_div(bytesFree, sb->s_blocksize);
23321 +
23322 + buf->f_bfree = bytesFree;
23323 +
23324 + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
23325 +
23326 + buf->f_blocks =
23327 + (dev->param.end_block - dev->param.start_block + 1) *
23328 + dev->param.chunks_per_block /
23329 + (sb->s_blocksize / dev->data_bytes_per_chunk);
23330 + buf->f_bfree =
23331 + yaffs_get_n_free_chunks(dev) /
23332 + (sb->s_blocksize / dev->data_bytes_per_chunk);
23333 + } else {
23334 + buf->f_blocks =
23335 + (dev->param.end_block - dev->param.start_block + 1) *
23336 + dev->param.chunks_per_block *
23337 + (dev->data_bytes_per_chunk / sb->s_blocksize);
23338 +
23339 + buf->f_bfree =
23340 + yaffs_get_n_free_chunks(dev) *
23341 + (dev->data_bytes_per_chunk / sb->s_blocksize);
23342 + }
23343 +
23344 + buf->f_files = 0;
23345 + buf->f_ffree = 0;
23346 + buf->f_bavail = buf->f_bfree;
23347 +
23348 + yaffs_gross_unlock(dev);
23349 + return 0;
23350 +}
23351 +
23352 +
23353 +
23354 +static void yaffs_flush_inodes(struct super_block *sb)
23355 +{
23356 + struct inode *iptr;
23357 + yaffs_obj_t *obj;
23358 +
23359 + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
23360 + obj = yaffs_InodeToObject(iptr);
23361 + if(obj){
23362 + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
23363 + obj->obj_id));
23364 + yaffs_flush_file(obj,1,0);
23365 + }
23366 + }
23367 +}
23368 +
23369 +
23370 +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
23371 +{
23372 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23373 + if(!dev)
23374 + return;
23375 +
23376 + yaffs_flush_inodes(sb);
23377 + yaffs_update_dirty_dirs(dev);
23378 + yaffs_flush_whole_cache(dev);
23379 + if(do_checkpoint)
23380 + yaffs_checkpoint_save(dev);
23381 +}
23382 +
23383 +
23384 +static unsigned yaffs_bg_gc_urgency(yaffs_dev_t *dev)
23385 +{
23386 + unsigned erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
23387 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23388 + unsigned scatteredFree = 0; /* Free chunks not in an erased block */
23389 +
23390 + if(erasedChunks < dev->n_free_chunks)
23391 + scatteredFree = (dev->n_free_chunks - erasedChunks);
23392 +
23393 + if(!context->bgRunning)
23394 + return 0;
23395 + else if(scatteredFree < (dev->param.chunks_per_block * 2))
23396 + return 0;
23397 + else if(erasedChunks > dev->n_free_chunks/2)
23398 + return 0;
23399 + else if(erasedChunks > dev->n_free_chunks/4)
23400 + return 1;
23401 + else
23402 + return 2;
23403 +}
23404 +
23405 +static int yaffs_do_sync_fs(struct super_block *sb,
23406 + int request_checkpoint)
23407 +{
23408 +
23409 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23410 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
23411 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
23412 + int do_checkpoint;
23413 +
23414 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
23415 + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
23416 + gc_urgent,
23417 + sb->s_dirt ? "dirty" : "clean",
23418 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
23419 + oneshot_checkpoint ? " one-shot" : "" ));
23420 +
23421 + yaffs_gross_lock(dev);
23422 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
23423 + oneshot_checkpoint) &&
23424 + !dev->is_checkpointed;
23425 +
23426 + if (sb->s_dirt || do_checkpoint) {
23427 + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
23428 + sb->s_dirt = 0;
23429 + if(oneshot_checkpoint)
23430 + yaffs_auto_checkpoint &= ~4;
23431 + }
23432 + yaffs_gross_unlock(dev);
23433 +
23434 + return 0;
23435 +}
23436 +
23437 +/*
23438 + * yaffs background thread functions .
23439 + * yaffs_bg_thread_fn() the thread function
23440 + * yaffs_bg_start() launches the background thread.
23441 + * yaffs_bg_stop() cleans up the background thread.
23442 + *
23443 + * NB:
23444 + * The thread should only run after the yaffs is initialised
23445 + * The thread should be stopped before yaffs is unmounted.
23446 + * The thread should not do any writing while the fs is in read only.
23447 + */
23448 +
23449 +#ifdef YAFFS_COMPILE_BACKGROUND
23450 +
23451 +void yaffs_background_waker(unsigned long data)
23452 +{
23453 + wake_up_process((struct task_struct *)data);
23454 +}
23455 +
23456 +static int yaffs_bg_thread_fn(void *data)
23457 +{
23458 + yaffs_dev_t *dev = (yaffs_dev_t *)data;
23459 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23460 + unsigned long now = jiffies;
23461 + unsigned long next_dir_update = now;
23462 + unsigned long next_gc = now;
23463 + unsigned long expires;
23464 + unsigned int urgency;
23465 +
23466 + int gcResult;
23467 + struct timer_list timer;
23468 +
23469 + T(YAFFS_TRACE_BACKGROUND,
23470 + (TSTR("yaffs_background starting for dev %p\n"),
23471 + (void *)dev));
23472 +
23473 +#ifdef YAFFS_COMPILE_FREEZER
23474 + set_freezable();
23475 +#endif
23476 + while(context->bgRunning){
23477 + T(YAFFS_TRACE_BACKGROUND,
23478 + (TSTR("yaffs_background\n")));
23479 +
23480 + if(kthread_should_stop())
23481 + break;
23482 +
23483 +#ifdef YAFFS_COMPILE_FREEZER
23484 + if(try_to_freeze())
23485 + continue;
23486 +#endif
23487 + yaffs_gross_lock(dev);
23488 +
23489 + now = jiffies;
23490 +
23491 + if(time_after(now, next_dir_update) && yaffs_bg_enable){
23492 + yaffs_update_dirty_dirs(dev);
23493 + next_dir_update = now + HZ;
23494 + }
23495 +
23496 + if(time_after(now,next_gc) && yaffs_bg_enable){
23497 + if(!dev->is_checkpointed){
23498 + urgency = yaffs_bg_gc_urgency(dev);
23499 + gcResult = yaffs_bg_gc(dev, urgency);
23500 + if(urgency > 1)
23501 + next_gc = now + HZ/20+1;
23502 + else if(urgency > 0)
23503 + next_gc = now + HZ/10+1;
23504 + else
23505 + next_gc = now + HZ * 2;
23506 + } else /*
23507 + * gc not running so set to next_dir_update
23508 + * to cut down on wake ups
23509 + */
23510 + next_gc = next_dir_update;
23511 + }
23512 + yaffs_gross_unlock(dev);
23513 +#if 1
23514 + expires = next_dir_update;
23515 + if (time_before(next_gc,expires))
23516 + expires = next_gc;
23517 + if(time_before(expires,now))
23518 + expires = now + HZ;
23519 +
23520 + Y_INIT_TIMER(&timer);
23521 + timer.expires = expires+1;
23522 + timer.data = (unsigned long) current;
23523 + timer.function = yaffs_background_waker;
23524 +
23525 + set_current_state(TASK_INTERRUPTIBLE);
23526 + add_timer(&timer);
23527 + schedule();
23528 + del_timer_sync(&timer);
23529 +#else
23530 + msleep(10);
23531 +#endif
23532 + }
23533 +
23534 + return 0;
23535 +}
23536 +
23537 +static int yaffs_bg_start(yaffs_dev_t *dev)
23538 +{
23539 + int retval = 0;
23540 + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
23541 +
23542 + if(dev->read_only)
23543 + return -1;
23544 +
23545 + context->bgRunning = 1;
23546 +
23547 + context->bgThread = kthread_run(yaffs_bg_thread_fn,
23548 + (void *)dev,"yaffs-bg-%d",context->mount_id);
23549 +
23550 + if(IS_ERR(context->bgThread)){
23551 + retval = PTR_ERR(context->bgThread);
23552 + context->bgThread = NULL;
23553 + context->bgRunning = 0;
23554 + }
23555 + return retval;
23556 +}
23557 +
23558 +static void yaffs_bg_stop(yaffs_dev_t *dev)
23559 +{
23560 + struct yaffs_LinuxContext *ctxt = yaffs_dev_to_lc(dev);
23561 +
23562 + ctxt->bgRunning = 0;
23563 +
23564 + if( ctxt->bgThread){
23565 + kthread_stop(ctxt->bgThread);
23566 + ctxt->bgThread = NULL;
23567 + }
23568 +}
23569 +#else
23570 +static int yaffs_bg_thread_fn(void *data)
23571 +{
23572 + return 0;
23573 +}
23574 +
23575 +static int yaffs_bg_start(yaffs_dev_t *dev)
23576 +{
23577 + return 0;
23578 +}
23579 +
23580 +static void yaffs_bg_stop(yaffs_dev_t *dev)
23581 +{
23582 +}
23583 +#endif
23584 +
23585 +
23586 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23587 +static void yaffs_write_super(struct super_block *sb)
23588 +#else
23589 +static int yaffs_write_super(struct super_block *sb)
23590 +#endif
23591 +{
23592 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
23593 +
23594 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
23595 + (TSTR("yaffs_write_super%s\n"),
23596 + request_checkpoint ? " checkpt" : ""));
23597 +
23598 + yaffs_do_sync_fs(sb, request_checkpoint);
23599 +
23600 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
23601 + return 0;
23602 +#endif
23603 +}
23604 +
23605 +
23606 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23607 +static int yaffs_sync_fs(struct super_block *sb, int wait)
23608 +#else
23609 +static int yaffs_sync_fs(struct super_block *sb)
23610 +#endif
23611 +{
23612 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
23613 +
23614 + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
23615 + (TSTR("yaffs_sync_fs%s\n"),
23616 + request_checkpoint ? " checkpt" : ""));
23617 +
23618 + yaffs_do_sync_fs(sb, request_checkpoint);
23619 +
23620 + return 0;
23621 +}
23622 +
23623 +#ifdef YAFFS_USE_OWN_IGET
23624 +
23625 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
23626 +{
23627 + struct inode *inode;
23628 + yaffs_obj_t *obj;
23629 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23630 +
23631 + T(YAFFS_TRACE_OS,
23632 + (TSTR("yaffs_iget for %lu\n"), ino));
23633 +
23634 + inode = iget_locked(sb, ino);
23635 + if (!inode)
23636 + return ERR_PTR(-ENOMEM);
23637 + if (!(inode->i_state & I_NEW))
23638 + return inode;
23639 +
23640 + /* NB This is called as a side effect of other functions, but
23641 + * we had to release the lock to prevent deadlocks, so
23642 + * need to lock again.
23643 + */
23644 +
23645 + yaffs_gross_lock(dev);
23646 +
23647 + obj = yaffs_find_by_number(dev, inode->i_ino);
23648 +
23649 + yaffs_fill_inode_from_obj(inode, obj);
23650 +
23651 + yaffs_gross_unlock(dev);
23652 +
23653 + unlock_new_inode(inode);
23654 + return inode;
23655 +}
23656 +
23657 +#else
23658 +
23659 +static void yaffs_read_inode(struct inode *inode)
23660 +{
23661 + /* NB This is called as a side effect of other functions, but
23662 + * we had to release the lock to prevent deadlocks, so
23663 + * need to lock again.
23664 + */
23665 +
23666 + yaffs_obj_t *obj;
23667 + yaffs_dev_t *dev = yaffs_SuperToDevice(inode->i_sb);
23668 +
23669 + T(YAFFS_TRACE_OS,
23670 + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
23671 +
23672 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
23673 + yaffs_gross_lock(dev);
23674 +
23675 + obj = yaffs_find_by_number(dev, inode->i_ino);
23676 +
23677 + yaffs_fill_inode_from_obj(inode, obj);
23678 +
23679 + if(current != yaffs_dev_to_lc(dev)->readdirProcess)
23680 + yaffs_gross_unlock(dev);
23681 +}
23682 +
23683 +#endif
23684 +
23685 +static YLIST_HEAD(yaffs_context_list);
23686 +struct semaphore yaffs_context_lock;
23687 +
23688 +static void yaffs_put_super(struct super_block *sb)
23689 +{
23690 + yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
23691 +
23692 + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
23693 +
23694 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
23695 + (TSTR("Shutting down yaffs background thread\n")));
23696 + yaffs_bg_stop(dev);
23697 + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
23698 + (TSTR("yaffs background thread shut down\n")));
23699 +
23700 + yaffs_gross_lock(dev);
23701 +
23702 + yaffs_flush_super(sb,1);
23703 +
23704 + if (yaffs_dev_to_lc(dev)->putSuperFunc)
23705 + yaffs_dev_to_lc(dev)->putSuperFunc(sb);
23706 +
23707 +
23708 + yaffs_deinitialise(dev);
23709 +
23710 + yaffs_gross_unlock(dev);
23711 +
23712 + down(&yaffs_context_lock);
23713 + ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
23714 + up(&yaffs_context_lock);
23715 +
23716 + if (yaffs_dev_to_lc(dev)->spareBuffer) {
23717 + YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
23718 + yaffs_dev_to_lc(dev)->spareBuffer = NULL;
23719 + }
23720 +
23721 + kfree(dev);
23722 +}
23723 +
23724 +
23725 +static void yaffs_MTDPutSuper(struct super_block *sb)
23726 +{
23727 + struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb));
23728 +
23729 + if (mtd->sync)
23730 + mtd->sync(mtd);
23731 +
23732 + put_mtd_device(mtd);
23733 +}
23734 +
23735 +
23736 +static void yaffs_touch_super(yaffs_dev_t *dev)
23737 +{
23738 + struct super_block *sb = yaffs_dev_to_lc(dev)->superBlock;
23739 +
23740 + T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
23741 + if (sb)
23742 + sb->s_dirt = 1;
23743 +}
23744 +
23745 +typedef struct {
23746 + int inband_tags;
23747 + int skip_checkpoint_read;
23748 + int skip_checkpoint_write;
23749 + int no_cache;
23750 + int tags_ecc_on;
23751 + int tags_ecc_overridden;
23752 + int lazy_loading_enabled;
23753 + int lazy_loading_overridden;
23754 + int empty_lost_and_found;
23755 + int empty_lost_and_found_overridden;
23756 +} yaffs_options;
23757 +
23758 +#define MAX_OPT_LEN 30
23759 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
23760 +{
23761 + char cur_opt[MAX_OPT_LEN + 1];
23762 + int p;
23763 + int error = 0;
23764 +
23765 + /* Parse through the options which is a comma seperated list */
23766 +
23767 + while (options_str && *options_str && !error) {
23768 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
23769 + p = 0;
23770 +
23771 + while(*options_str == ',')
23772 + options_str++;
23773 +
23774 + while (*options_str && *options_str != ',') {
23775 + if (p < MAX_OPT_LEN) {
23776 + cur_opt[p] = *options_str;
23777 + p++;
23778 + }
23779 + options_str++;
23780 + }
23781 +
23782 + if (!strcmp(cur_opt, "inband-tags"))
23783 + options->inband_tags = 1;
23784 + else if (!strcmp(cur_opt, "tags-ecc-off")){
23785 + options->tags_ecc_on = 0;
23786 + options->tags_ecc_overridden=1;
23787 + } else if (!strcmp(cur_opt, "tags-ecc-on")){
23788 + options->tags_ecc_on = 1;
23789 + options->tags_ecc_overridden = 1;
23790 + } else if (!strcmp(cur_opt, "lazy-loading-off")){
23791 + options->lazy_loading_enabled = 0;
23792 + options->lazy_loading_overridden=1;
23793 + } else if (!strcmp(cur_opt, "lazy-loading-on")){
23794 + options->lazy_loading_enabled = 1;
23795 + options->lazy_loading_overridden = 1;
23796 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
23797 + options->empty_lost_and_found = 0;
23798 + options->empty_lost_and_found_overridden=1;
23799 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
23800 + options->empty_lost_and_found = 1;
23801 + options->empty_lost_and_found_overridden=1;
23802 + } else if (!strcmp(cur_opt, "no-cache"))
23803 + options->no_cache = 1;
23804 + else if (!strcmp(cur_opt, "no-checkpoint-read"))
23805 + options->skip_checkpoint_read = 1;
23806 + else if (!strcmp(cur_opt, "no-checkpoint-write"))
23807 + options->skip_checkpoint_write = 1;
23808 + else if (!strcmp(cur_opt, "no-checkpoint")) {
23809 + options->skip_checkpoint_read = 1;
23810 + options->skip_checkpoint_write = 1;
23811 + } else {
23812 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
23813 + cur_opt);
23814 + error = 1;
23815 + }
23816 + }
23817 +
23818 + return error;
23819 +}
23820 +
23821 +static struct super_block *yaffs_internal_read_super(int yaffs_version,
23822 + struct super_block *sb,
23823 + void *data, int silent)
23824 +{
23825 + int nBlocks;
23826 + struct inode *inode = NULL;
23827 + struct dentry *root;
23828 + yaffs_dev_t *dev = 0;
23829 + char devname_buf[BDEVNAME_SIZE + 1];
23830 + struct mtd_info *mtd;
23831 + int err;
23832 + char *data_str = (char *)data;
23833 + struct yaffs_LinuxContext *context = NULL;
23834 + yaffs_param_t *param;
23835 +
23836 + int read_only = 0;
23837 +
23838 + yaffs_options options;
23839 +
23840 + unsigned mount_id;
23841 + int found;
23842 + struct yaffs_LinuxContext *context_iterator;
23843 + struct ylist_head *l;
23844 +
23845 + sb->s_magic = YAFFS_MAGIC;
23846 + sb->s_op = &yaffs_super_ops;
23847 + sb->s_flags |= MS_NOATIME;
23848 +
23849 + read_only =((sb->s_flags & MS_RDONLY) != 0);
23850 +
23851 +
23852 +#ifdef YAFFS_COMPILE_EXPORTFS
23853 + sb->s_export_op = &yaffs_export_ops;
23854 +#endif
23855 +
23856 + if (!sb)
23857 + printk(KERN_INFO "yaffs: sb is NULL\n");
23858 + else if (!sb->s_dev)
23859 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
23860 + else if (!yaffs_devname(sb, devname_buf))
23861 + printk(KERN_INFO "yaffs: devname is NULL\n");
23862 + else
23863 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
23864 + sb->s_dev,
23865 + yaffs_devname(sb, devname_buf),
23866 + read_only ? "ro" : "rw");
23867 +
23868 + if (!data_str)
23869 + data_str = "";
23870 +
23871 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
23872 +
23873 + memset(&options, 0, sizeof(options));
23874 +
23875 + if (yaffs_parse_options(&options, data_str)) {
23876 + /* Option parsing failed */
23877 + return NULL;
23878 + }
23879 +
23880 +
23881 + sb->s_blocksize = PAGE_CACHE_SIZE;
23882 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
23883 +
23884 + T(YAFFS_TRACE_OS,
23885 + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffs_version));
23886 + T(YAFFS_TRACE_OS,
23887 + (TSTR("yaffs_read_super: block size %d\n"),
23888 + (int)(sb->s_blocksize)));
23889 +
23890 + T(YAFFS_TRACE_ALWAYS,
23891 + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
23892 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
23893 + yaffs_devname(sb, devname_buf)));
23894 +
23895 + /* Check it's an mtd device..... */
23896 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
23897 + return NULL; /* This isn't an mtd device */
23898 +
23899 + /* Get the device */
23900 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
23901 + if (!mtd) {
23902 + T(YAFFS_TRACE_ALWAYS,
23903 + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
23904 + MINOR(sb->s_dev)));
23905 + return NULL;
23906 + }
23907 + /* Check it's NAND */
23908 + if (mtd->type != MTD_NANDFLASH) {
23909 + T(YAFFS_TRACE_ALWAYS,
23910 + (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
23911 + mtd->type));
23912 + return NULL;
23913 + }
23914 +
23915 + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
23916 + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
23917 + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
23918 + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
23919 + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
23920 + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
23921 + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
23922 + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
23923 + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
23924 + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
23925 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
23926 + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
23927 +#else
23928 + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
23929 +#endif
23930 +
23931 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
23932 +
23933 + if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
23934 + T(YAFFS_TRACE_ALWAYS,
23935 + (TSTR("yaffs: auto selecting yaffs2\n")));
23936 + yaffs_version = 2;
23937 + }
23938 +
23939 + /* Added NCB 26/5/2006 for completeness */
23940 + if (yaffs_version == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
23941 + T(YAFFS_TRACE_ALWAYS,
23942 + (TSTR("yaffs: auto selecting yaffs1\n")));
23943 + yaffs_version = 1;
23944 + }
23945 +
23946 +#endif
23947 +
23948 + if (yaffs_version == 2) {
23949 + /* Check for version 2 style functions */
23950 + if (!mtd->erase ||
23951 + !mtd->block_isbad ||
23952 + !mtd->block_markbad ||
23953 + !mtd->read ||
23954 + !mtd->write ||
23955 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23956 + !mtd->read_oob || !mtd->write_oob) {
23957 +#else
23958 + !mtd->write_ecc ||
23959 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
23960 +#endif
23961 + T(YAFFS_TRACE_ALWAYS,
23962 + (TSTR("yaffs: MTD device does not support required "
23963 + "functions\n")));
23964 + return NULL;
23965 + }
23966 +
23967 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
23968 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
23969 + !options.inband_tags) {
23970 + T(YAFFS_TRACE_ALWAYS,
23971 + (TSTR("yaffs: MTD device does not have the "
23972 + "right page sizes\n")));
23973 + return NULL;
23974 + }
23975 + } else {
23976 + /* Check for V1 style functions */
23977 + if (!mtd->erase ||
23978 + !mtd->read ||
23979 + !mtd->write ||
23980 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
23981 + !mtd->read_oob || !mtd->write_oob) {
23982 +#else
23983 + !mtd->write_ecc ||
23984 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
23985 +#endif
23986 + T(YAFFS_TRACE_ALWAYS,
23987 + (TSTR("yaffs: MTD device does not support required "
23988 + "functions\n")));
23989 + return NULL;
23990 + }
23991 +
23992 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
23993 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
23994 + T(YAFFS_TRACE_ALWAYS,
23995 + (TSTR("yaffs: MTD device does not support have the "
23996 + "right page sizes\n")));
23997 + return NULL;
23998 + }
23999 + }
24000 +
24001 + /* OK, so if we got here, we have an MTD that's NAND and looks
24002 + * like it has the right capabilities
24003 + * Set the yaffs_dev_t up for mtd
24004 + */
24005 +
24006 + if (!read_only && !(mtd->flags & MTD_WRITEABLE)){
24007 + read_only = 1;
24008 + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
24009 + sb->s_flags |= MS_RDONLY;
24010 + }
24011 +
24012 + dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL);
24013 + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
24014 +
24015 + if(!dev || !context ){
24016 + if(dev)
24017 + kfree(dev);
24018 + if(context)
24019 + kfree(context);
24020 + dev = NULL;
24021 + context = NULL;
24022 + }
24023 +
24024 + if (!dev) {
24025 + /* Deep shit could not allocate device structure */
24026 + T(YAFFS_TRACE_ALWAYS,
24027 + (TSTR("yaffs_read_super: Failed trying to allocate "
24028 + "yaffs_dev_t. \n")));
24029 + return NULL;
24030 + }
24031 + memset(dev, 0, sizeof(yaffs_dev_t));
24032 + param = &(dev->param);
24033 +
24034 + memset(context,0,sizeof(struct yaffs_LinuxContext));
24035 + dev->os_context = context;
24036 + YINIT_LIST_HEAD(&(context->contextList));
24037 + context->dev = dev;
24038 + context->superBlock = sb;
24039 +
24040 + dev->read_only = read_only;
24041 +
24042 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24043 + sb->s_fs_info = dev;
24044 +#else
24045 + sb->u.generic_sbp = dev;
24046 +#endif
24047 +
24048 + dev->driver_context = mtd;
24049 + param->name = mtd->name;
24050 +
24051 + /* Set up the memory size parameters.... */
24052 +
24053 + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
24054 +
24055 + param->start_block = 0;
24056 + param->end_block = nBlocks - 1;
24057 + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
24058 + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
24059 + param->n_reserved_blocks = 5;
24060 + param->n_caches = (options.no_cache) ? 0 : 10;
24061 + param->inband_tags = options.inband_tags;
24062 +
24063 +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
24064 + param->disable_lazy_load = 1;
24065 +#endif
24066 +#ifdef CONFIG_YAFFS_XATTR
24067 + param->enable_xattr = 1;
24068 +#endif
24069 + if(options.lazy_loading_overridden)
24070 + param->disable_lazy_load = !options.lazy_loading_enabled;
24071 +
24072 +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
24073 + param->no_tags_ecc = 1;
24074 +#endif
24075 +
24076 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
24077 +#else
24078 + param->defered_dir_update = 1;
24079 +#endif
24080 +
24081 + if(options.tags_ecc_overridden)
24082 + param->no_tags_ecc = !options.tags_ecc_on;
24083 +
24084 +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
24085 + param->empty_lost_n_found = 1;
24086 +#endif
24087 +
24088 +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
24089 + param->refresh_period = 0;
24090 +#else
24091 + param->refresh_period = 500;
24092 +#endif
24093 +
24094 +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
24095 + param->always_check_erased = 1;
24096 +#endif
24097 +
24098 + if(options.empty_lost_and_found_overridden)
24099 + param->empty_lost_n_found = options.empty_lost_and_found;
24100 +
24101 + /* ... and the functions. */
24102 + if (yaffs_version == 2) {
24103 + param->write_chunk_tags_fn =
24104 + nandmtd2_WriteChunkWithTagsToNAND;
24105 + param->read_chunk_tags_fn =
24106 + nandmtd2_ReadChunkWithTagsFromNAND;
24107 + param->bad_block_fn = nandmtd2_MarkNANDBlockBad;
24108 + param->query_block_fn = nandmtd2_QueryNANDBlock;
24109 + yaffs_dev_to_lc(dev)->spareBuffer = YMALLOC(mtd->oobsize);
24110 + param->is_yaffs2 = 1;
24111 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24112 + param->total_bytes_per_chunk = mtd->writesize;
24113 + param->chunks_per_block = mtd->erasesize / mtd->writesize;
24114 +#else
24115 + param->total_bytes_per_chunk = mtd->oobblock;
24116 + param->chunks_per_block = mtd->erasesize / mtd->oobblock;
24117 +#endif
24118 + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
24119 +
24120 + param->start_block = 0;
24121 + param->end_block = nBlocks - 1;
24122 + } else {
24123 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24124 + /* use the MTD interface in yaffs_mtdif1.c */
24125 + param->write_chunk_tags_fn =
24126 + nandmtd1_WriteChunkWithTagsToNAND;
24127 + param->read_chunk_tags_fn =
24128 + nandmtd1_ReadChunkWithTagsFromNAND;
24129 + param->bad_block_fn = nandmtd1_MarkNANDBlockBad;
24130 + param->query_block_fn = nandmtd1_QueryNANDBlock;
24131 +#else
24132 + param->write_chunk_fn = nandmtd_WriteChunkToNAND;
24133 + param->read_chunk_fn = nandmtd_ReadChunkFromNAND;
24134 +#endif
24135 + param->is_yaffs2 = 0;
24136 + }
24137 + /* ... and common functions */
24138 + param->erase_fn = nandmtd_EraseBlockInNAND;
24139 + param->initialise_flash_fn = nandmtd_InitialiseNAND;
24140 +
24141 + yaffs_dev_to_lc(dev)->putSuperFunc = yaffs_MTDPutSuper;
24142 +
24143 + param->sb_dirty_fn = yaffs_touch_super;
24144 + param->gc_control = yaffs_gc_control_callback;
24145 +
24146 + yaffs_dev_to_lc(dev)->superBlock= sb;
24147 +
24148 +
24149 +#ifndef CONFIG_YAFFS_DOES_ECC
24150 + param->use_nand_ecc = 1;
24151 +#endif
24152 +
24153 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
24154 + param->wide_tnodes_disabled = 1;
24155 +#endif
24156 +
24157 + param->skip_checkpt_rd = options.skip_checkpoint_read;
24158 + param->skip_checkpt_wr = options.skip_checkpoint_write;
24159 +
24160 + down(&yaffs_context_lock);
24161 + /* Get a mount id */
24162 + found = 0;
24163 + for(mount_id=0; ! found; mount_id++){
24164 + found = 1;
24165 + ylist_for_each(l,&yaffs_context_list){
24166 + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
24167 + if(context_iterator->mount_id == mount_id)
24168 + found = 0;
24169 + }
24170 + }
24171 + context->mount_id = mount_id;
24172 +
24173 + ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
24174 + up(&yaffs_context_lock);
24175 +
24176 + /* Directory search handling...*/
24177 + YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts));
24178 + param->remove_obj_fn = yaffs_remove_obj_callback;
24179 +
24180 + init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock));
24181 +
24182 + yaffs_gross_lock(dev);
24183 +
24184 + err = yaffs_guts_initialise(dev);
24185 +
24186 + T(YAFFS_TRACE_OS,
24187 + (TSTR("yaffs_read_super: guts initialised %s\n"),
24188 + (err == YAFFS_OK) ? "OK" : "FAILED"));
24189 +
24190 + if(err == YAFFS_OK)
24191 + yaffs_bg_start(dev);
24192 +
24193 + if(!context->bgThread)
24194 + param->defered_dir_update = 0;
24195 +
24196 +
24197 + /* Release lock before yaffs_get_inode() */
24198 + yaffs_gross_unlock(dev);
24199 +
24200 + /* Create root inode */
24201 + if (err == YAFFS_OK)
24202 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
24203 + yaffs_root(dev));
24204 +
24205 + if (!inode)
24206 + return NULL;
24207 +
24208 + inode->i_op = &yaffs_dir_inode_operations;
24209 + inode->i_fop = &yaffs_dir_operations;
24210 +
24211 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
24212 +
24213 + root = d_alloc_root(inode);
24214 +
24215 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
24216 +
24217 + if (!root) {
24218 + iput(inode);
24219 + return NULL;
24220 + }
24221 + sb->s_root = root;
24222 + sb->s_dirt = !dev->is_checkpointed;
24223 + T(YAFFS_TRACE_ALWAYS,
24224 + (TSTR("yaffs_read_super: is_checkpointed %d\n"),
24225 + dev->is_checkpointed));
24226 +
24227 + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
24228 + return sb;
24229 +}
24230 +
24231 +
24232 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24233 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
24234 + int silent)
24235 +{
24236 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
24237 +}
24238 +
24239 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24240 +static int yaffs_read_super(struct file_system_type *fs,
24241 + int flags, const char *dev_name,
24242 + void *data, struct vfsmount *mnt)
24243 +{
24244 +
24245 + return get_sb_bdev(fs, flags, dev_name, data,
24246 + yaffs_internal_read_super_mtd, mnt);
24247 +}
24248 +#else
24249 +static struct super_block *yaffs_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 + yaffs_internal_read_super_mtd);
24256 +}
24257 +#endif
24258 +
24259 +static struct file_system_type yaffs_fs_type = {
24260 + .owner = THIS_MODULE,
24261 + .name = "yaffs",
24262 + .get_sb = yaffs_read_super,
24263 + .kill_sb = kill_block_super,
24264 + .fs_flags = FS_REQUIRES_DEV,
24265 +};
24266 +#else
24267 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
24268 + int silent)
24269 +{
24270 + return yaffs_internal_read_super(1, sb, data, silent);
24271 +}
24272 +
24273 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
24274 + FS_REQUIRES_DEV);
24275 +#endif
24276 +
24277 +
24278 +#ifdef CONFIG_YAFFS_YAFFS2
24279 +
24280 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
24281 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
24282 + int silent)
24283 +{
24284 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
24285 +}
24286 +
24287 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
24288 +static int yaffs2_read_super(struct file_system_type *fs,
24289 + int flags, const char *dev_name, void *data,
24290 + struct vfsmount *mnt)
24291 +{
24292 + return get_sb_bdev(fs, flags, dev_name, data,
24293 + yaffs2_internal_read_super_mtd, mnt);
24294 +}
24295 +#else
24296 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
24297 + int flags, const char *dev_name,
24298 + void *data)
24299 +{
24300 +
24301 + return get_sb_bdev(fs, flags, dev_name, data,
24302 + yaffs2_internal_read_super_mtd);
24303 +}
24304 +#endif
24305 +
24306 +static struct file_system_type yaffs2_fs_type = {
24307 + .owner = THIS_MODULE,
24308 + .name = "yaffs2",
24309 + .get_sb = yaffs2_read_super,
24310 + .kill_sb = kill_block_super,
24311 + .fs_flags = FS_REQUIRES_DEV,
24312 +};
24313 +#else
24314 +static struct super_block *yaffs2_read_super(struct super_block *sb,
24315 + void *data, int silent)
24316 +{
24317 + return yaffs_internal_read_super(2, sb, data, silent);
24318 +}
24319 +
24320 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
24321 + FS_REQUIRES_DEV);
24322 +#endif
24323 +
24324 +#endif /* CONFIG_YAFFS_YAFFS2 */
24325 +
24326 +static struct proc_dir_entry *my_proc_entry;
24327 +static struct proc_dir_entry *debug_proc_entry;
24328 +
24329 +static char *yaffs_dump_dev_part0(char *buf, yaffs_dev_t * dev)
24330 +{
24331 + buf += sprintf(buf, "start_block.......... %d\n", dev->param.start_block);
24332 + buf += sprintf(buf, "end_block............ %d\n", dev->param.end_block);
24333 + buf += sprintf(buf, "total_bytes_per_chunk %d\n", dev->param.total_bytes_per_chunk);
24334 + buf += sprintf(buf, "use_nand_ecc......... %d\n", dev->param.use_nand_ecc);
24335 + buf += sprintf(buf, "no_tags_ecc.......... %d\n", dev->param.no_tags_ecc);
24336 + buf += sprintf(buf, "is_yaffs2............ %d\n", dev->param.is_yaffs2);
24337 + buf += sprintf(buf, "inband_tags.......... %d\n", dev->param.inband_tags);
24338 + buf += sprintf(buf, "empty_lost_n_found... %d\n", dev->param.empty_lost_n_found);
24339 + buf += sprintf(buf, "disable_lazy_load.... %d\n", dev->param.disable_lazy_load);
24340 + buf += sprintf(buf, "refresh_period....... %d\n", dev->param.refresh_period);
24341 + buf += sprintf(buf, "n_caches............. %d\n", dev->param.n_caches);
24342 + buf += sprintf(buf, "n_reserved_blocks.... %d\n", dev->param.n_reserved_blocks);
24343 + buf += sprintf(buf, "always_check_erased.. %d\n", dev->param.always_check_erased);
24344 +
24345 + buf += sprintf(buf, "\n");
24346 +
24347 + return buf;
24348 +}
24349 +
24350 +
24351 +static char *yaffs_dump_dev_part1(char *buf, yaffs_dev_t * dev)
24352 +{
24353 + buf += sprintf(buf, "data_bytes_per_chunk. %d\n", dev->data_bytes_per_chunk);
24354 + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
24355 + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
24356 + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
24357 + buf += sprintf(buf, "blocks_in_checkpt.... %d\n", dev->blocks_in_checkpt);
24358 + buf += sprintf(buf, "\n");
24359 + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
24360 + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
24361 + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
24362 + buf += sprintf(buf, "\n");
24363 + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
24364 + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
24365 + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
24366 + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
24367 + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
24368 + buf += sprintf(buf, "passive_gc_count..... %u\n", dev->passive_gc_count);
24369 + buf += sprintf(buf, "oldest_dirty_gc_count %u\n", dev->oldest_dirty_gc_count);
24370 + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
24371 + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
24372 + buf += sprintf(buf, "n_retired_writes..... %u\n", dev->n_retired_writes);
24373 + buf += sprintf(buf, "nRetireBlocks........ %u\n", dev->n_retired_blocks);
24374 + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
24375 + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
24376 + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", dev->n_tags_ecc_fixed);
24377 + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", dev->n_tags_ecc_unfixed);
24378 + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
24379 + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
24380 + buf += sprintf(buf, "n_unlinked_files..... %u\n", dev->n_unlinked_files);
24381 + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
24382 + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
24383 +
24384 + return buf;
24385 +}
24386 +
24387 +static int yaffs_proc_read(char *page,
24388 + char **start,
24389 + off_t offset, int count, int *eof, void *data)
24390 +{
24391 + struct ylist_head *item;
24392 + char *buf = page;
24393 + int step = offset;
24394 + int n = 0;
24395 +
24396 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
24397 + * We use 'offset' (*ppos) to indicate where we are in dev_list.
24398 + * This also assumes the user has posted a read buffer large
24399 + * enough to hold the complete output; but that's life in /proc.
24400 + */
24401 +
24402 + *(int *)start = 1;
24403 +
24404 + /* Print header first */
24405 + if (step == 0)
24406 + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
24407 + else if (step == 1)
24408 + buf += sprintf(buf,"\n");
24409 + else {
24410 + step-=2;
24411 +
24412 + down(&yaffs_context_lock);
24413 +
24414 + /* Locate and print the Nth entry. Order N-squared but N is small. */
24415 + ylist_for_each(item, &yaffs_context_list) {
24416 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
24417 + yaffs_dev_t *dev = dc->dev;
24418 +
24419 + if (n < (step & ~1)) {
24420 + n+=2;
24421 + continue;
24422 + }
24423 + if((step & 1)==0){
24424 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
24425 + buf = yaffs_dump_dev_part0(buf, dev);
24426 + } else
24427 + buf = yaffs_dump_dev_part1(buf, dev);
24428 +
24429 + break;
24430 + }
24431 + up(&yaffs_context_lock);
24432 + }
24433 +
24434 + return buf - page < count ? buf - page : count;
24435 +}
24436 +
24437 +static int yaffs_stats_proc_read(char *page,
24438 + char **start,
24439 + off_t offset, int count, int *eof, void *data)
24440 +{
24441 + struct ylist_head *item;
24442 + char *buf = page;
24443 + int n = 0;
24444 +
24445 + down(&yaffs_context_lock);
24446 +
24447 + /* Locate and print the Nth entry. Order N-squared but N is small. */
24448 + ylist_for_each(item, &yaffs_context_list) {
24449 + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
24450 + yaffs_dev_t *dev = dc->dev;
24451 +
24452 + int erasedChunks;
24453 +
24454 + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
24455 +
24456 + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
24457 + n, dev->n_free_chunks, erasedChunks,
24458 + dev->bg_gcs, dev->oldest_dirty_gc_count,
24459 + dev->n_obj, dev->n_tnodes);
24460 + }
24461 + up(&yaffs_context_lock);
24462 +
24463 +
24464 + return buf - page < count ? buf - page : count;
24465 +}
24466 +
24467 +/**
24468 + * Set the verbosity of the warnings and error messages.
24469 + *
24470 + * Note that the names can only be a..z or _ with the current code.
24471 + */
24472 +
24473 +static struct {
24474 + char *mask_name;
24475 + unsigned mask_bitfield;
24476 +} mask_flags[] = {
24477 + {"allocate", YAFFS_TRACE_ALLOCATE},
24478 + {"always", YAFFS_TRACE_ALWAYS},
24479 + {"background", YAFFS_TRACE_BACKGROUND},
24480 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
24481 + {"buffers", YAFFS_TRACE_BUFFERS},
24482 + {"bug", YAFFS_TRACE_BUG},
24483 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
24484 + {"deletion", YAFFS_TRACE_DELETION},
24485 + {"erase", YAFFS_TRACE_ERASE},
24486 + {"error", YAFFS_TRACE_ERROR},
24487 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
24488 + {"gc", YAFFS_TRACE_GC},
24489 + {"lock", YAFFS_TRACE_LOCK},
24490 + {"mtd", YAFFS_TRACE_MTD},
24491 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
24492 + {"os", YAFFS_TRACE_OS},
24493 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
24494 + {"scan", YAFFS_TRACE_SCAN},
24495 + {"tracing", YAFFS_TRACE_TRACING},
24496 + {"sync", YAFFS_TRACE_SYNC},
24497 + {"write", YAFFS_TRACE_WRITE},
24498 +
24499 + {"verify", YAFFS_TRACE_VERIFY},
24500 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
24501 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
24502 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
24503 +
24504 + {"all", 0xffffffff},
24505 + {"none", 0},
24506 + {NULL, 0},
24507 +};
24508 +
24509 +#define MAX_MASK_NAME_LENGTH 40
24510 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
24511 + unsigned long count, void *data)
24512 +{
24513 + unsigned rg = 0, mask_bitfield;
24514 + char *end;
24515 + char *mask_name;
24516 + const char *x;
24517 + char substring[MAX_MASK_NAME_LENGTH + 1];
24518 + int i;
24519 + int done = 0;
24520 + int add, len = 0;
24521 + int pos = 0;
24522 +
24523 + rg = yaffs_trace_mask;
24524 +
24525 + while (!done && (pos < count)) {
24526 + done = 1;
24527 + while ((pos < count) && isspace(buf[pos]))
24528 + pos++;
24529 +
24530 + switch (buf[pos]) {
24531 + case '+':
24532 + case '-':
24533 + case '=':
24534 + add = buf[pos];
24535 + pos++;
24536 + break;
24537 +
24538 + default:
24539 + add = ' ';
24540 + break;
24541 + }
24542 + mask_name = NULL;
24543 +
24544 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
24545 +
24546 + if (end > buf + pos) {
24547 + mask_name = "numeral";
24548 + len = end - (buf + pos);
24549 + pos += len;
24550 + done = 0;
24551 + } else {
24552 + for (x = buf + pos, i = 0;
24553 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
24554 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
24555 + substring[i] = *x;
24556 + substring[i] = '\0';
24557 +
24558 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
24559 + if (strcmp(substring, mask_flags[i].mask_name) == 0) {
24560 + mask_name = mask_flags[i].mask_name;
24561 + mask_bitfield = mask_flags[i].mask_bitfield;
24562 + done = 0;
24563 + break;
24564 + }
24565 + }
24566 + }
24567 +
24568 + if (mask_name != NULL) {
24569 + done = 0;
24570 + switch (add) {
24571 + case '-':
24572 + rg &= ~mask_bitfield;
24573 + break;
24574 + case '+':
24575 + rg |= mask_bitfield;
24576 + break;
24577 + case '=':
24578 + rg = mask_bitfield;
24579 + break;
24580 + default:
24581 + rg |= mask_bitfield;
24582 + break;
24583 + }
24584 + }
24585 + }
24586 +
24587 + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
24588 +
24589 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
24590 +
24591 + if (rg & YAFFS_TRACE_ALWAYS) {
24592 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
24593 + char flag;
24594 + flag = ((rg & mask_flags[i].mask_bitfield) ==
24595 + mask_flags[i].mask_bitfield) ? '+' : '-';
24596 + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
24597 + }
24598 + }
24599 +
24600 + return count;
24601 +}
24602 +
24603 +
24604 +static int yaffs_proc_write(struct file *file, const char *buf,
24605 + unsigned long count, void *data)
24606 +{
24607 + return yaffs_proc_write_trace_options(file, buf, count, data);
24608 +}
24609 +
24610 +/* Stuff to handle installation of file systems */
24611 +struct file_system_to_install {
24612 + struct file_system_type *fst;
24613 + int installed;
24614 +};
24615 +
24616 +static struct file_system_to_install fs_to_install[] = {
24617 + {&yaffs_fs_type, 0},
24618 + {&yaffs2_fs_type, 0},
24619 + {NULL, 0}
24620 +};
24621 +
24622 +static int __init init_yaffs_fs(void)
24623 +{
24624 + int error = 0;
24625 + struct file_system_to_install *fsinst;
24626 +
24627 + T(YAFFS_TRACE_ALWAYS,
24628 + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
24629 +
24630 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
24631 + T(YAFFS_TRACE_ALWAYS,
24632 + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
24633 +#endif
24634 +
24635 +
24636 +
24637 +
24638 + init_MUTEX(&yaffs_context_lock);
24639 +
24640 + /* Install the proc_fs entries */
24641 + my_proc_entry = create_proc_entry("yaffs",
24642 + S_IRUGO | S_IFREG,
24643 + YPROC_ROOT);
24644 +
24645 + if (my_proc_entry) {
24646 + my_proc_entry->write_proc = yaffs_proc_write;
24647 + my_proc_entry->read_proc = yaffs_proc_read;
24648 + my_proc_entry->data = NULL;
24649 + } else
24650 + return -ENOMEM;
24651 +
24652 + debug_proc_entry = create_proc_entry("yaffs_stats",
24653 + S_IRUGO | S_IFREG,
24654 + YPROC_ROOT);
24655 +
24656 + if (debug_proc_entry) {
24657 + debug_proc_entry->write_proc = NULL;
24658 + debug_proc_entry->read_proc = yaffs_stats_proc_read;
24659 + debug_proc_entry->data = NULL;
24660 + } else
24661 + return -ENOMEM;
24662 +
24663 + /* Now add the file system entries */
24664 +
24665 + fsinst = fs_to_install;
24666 +
24667 + while (fsinst->fst && !error) {
24668 + error = register_filesystem(fsinst->fst);
24669 + if (!error)
24670 + fsinst->installed = 1;
24671 + fsinst++;
24672 + }
24673 +
24674 + /* Any errors? uninstall */
24675 + if (error) {
24676 + fsinst = fs_to_install;
24677 +
24678 + while (fsinst->fst) {
24679 + if (fsinst->installed) {
24680 + unregister_filesystem(fsinst->fst);
24681 + fsinst->installed = 0;
24682 + }
24683 + fsinst++;
24684 + }
24685 + }
24686 +
24687 + return error;
24688 +}
24689 +
24690 +static void __exit exit_yaffs_fs(void)
24691 +{
24692 +
24693 + struct file_system_to_install *fsinst;
24694 +
24695 + T(YAFFS_TRACE_ALWAYS,
24696 + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
24697 +
24698 + remove_proc_entry("yaffs", YPROC_ROOT);
24699 + remove_proc_entry("yaffs_stats", YPROC_ROOT);
24700 +
24701 + fsinst = fs_to_install;
24702 +
24703 + while (fsinst->fst) {
24704 + if (fsinst->installed) {
24705 + unregister_filesystem(fsinst->fst);
24706 + fsinst->installed = 0;
24707 + }
24708 + fsinst++;
24709 + }
24710 +}
24711 +
24712 +module_init(init_yaffs_fs)
24713 +module_exit(exit_yaffs_fs)
24714 +
24715 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
24716 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
24717 +MODULE_LICENSE("GPL");
24718 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.c
24719 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 02:00:00.000000000 +0200
24720 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.c 2010-10-20 13:28:16.039000295 +0300
24721 @@ -0,0 +1,465 @@
24722 +/*
24723 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
24724 + *
24725 + * Copyright (C) 2002-2010 Aleph One Ltd.
24726 + * for Toby Churchill Ltd and Brightstar Engineering
24727 + *
24728 + * Created by Charles Manning <charles@aleph1.co.uk>
24729 + *
24730 + * This program is free software; you can redistribute it and/or modify
24731 + * it under the terms of the GNU General Public License version 2 as
24732 + * published by the Free Software Foundation.
24733 + */
24734 +#include "yaffs_yaffs1.h"
24735 +#include "yportenv.h"
24736 +#include "yaffs_trace.h"
24737 +#include "yaffs_bitmap.h"
24738 +#include "yaffs_getblockinfo.h"
24739 +#include "yaffs_nand.h"
24740 +
24741 +
24742 +int yaffs1_scan(yaffs_dev_t *dev)
24743 +{
24744 + yaffs_ext_tags tags;
24745 + int blk;
24746 + int blockIterator;
24747 + int startIterator;
24748 + int endIterator;
24749 + int result;
24750 +
24751 + int chunk;
24752 + int c;
24753 + int deleted;
24754 + yaffs_block_state_t state;
24755 + yaffs_obj_t *hard_list = NULL;
24756 + yaffs_block_info_t *bi;
24757 + __u32 seq_number;
24758 + yaffs_obj_header *oh;
24759 + yaffs_obj_t *in;
24760 + yaffs_obj_t *parent;
24761 +
24762 + int alloc_failed = 0;
24763 +
24764 + struct yaffs_shadow_fixer_s *shadowFixerList = NULL;
24765 +
24766 +
24767 + __u8 *chunkData;
24768 +
24769 +
24770 +
24771 + T(YAFFS_TRACE_SCAN,
24772 + (TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
24773 + dev->internal_start_block, dev->internal_end_block));
24774 +
24775 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
24776 +
24777 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
24778 +
24779 + /* Scan all the blocks to determine their state */
24780 + bi = dev->block_info;
24781 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
24782 + yaffs_clear_chunk_bits(dev, blk);
24783 + bi->pages_in_use = 0;
24784 + bi->soft_del_pages = 0;
24785 +
24786 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
24787 +
24788 + bi->block_state = state;
24789 + bi->seq_number = seq_number;
24790 +
24791 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
24792 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
24793 +
24794 + T(YAFFS_TRACE_SCAN_DEBUG,
24795 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
24796 + state, seq_number));
24797 +
24798 + if (state == YAFFS_BLOCK_STATE_DEAD) {
24799 + T(YAFFS_TRACE_BAD_BLOCKS,
24800 + (TSTR("block %d is bad" TENDSTR), blk));
24801 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
24802 + T(YAFFS_TRACE_SCAN_DEBUG,
24803 + (TSTR("Block empty " TENDSTR)));
24804 + dev->n_erased_blocks++;
24805 + dev->n_free_chunks += dev->param.chunks_per_block;
24806 + }
24807 + bi++;
24808 + }
24809 +
24810 + startIterator = dev->internal_start_block;
24811 + endIterator = dev->internal_end_block;
24812 +
24813 + /* For each block.... */
24814 + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
24815 + blockIterator++) {
24816 +
24817 + YYIELD();
24818 +
24819 + YYIELD();
24820 +
24821 + blk = blockIterator;
24822 +
24823 + bi = yaffs_get_block_info(dev, blk);
24824 + state = bi->block_state;
24825 +
24826 + deleted = 0;
24827 +
24828 + /* For each chunk in each block that needs scanning....*/
24829 + for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
24830 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
24831 + /* Read the tags and decide what to do */
24832 + chunk = blk * dev->param.chunks_per_block + c;
24833 +
24834 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
24835 + &tags);
24836 +
24837 + /* Let's have a good look at this chunk... */
24838 +
24839 + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) {
24840 + /* YAFFS1 only...
24841 + * A deleted chunk
24842 + */
24843 + deleted++;
24844 + dev->n_free_chunks++;
24845 + /*T((" %d %d deleted\n",blk,c)); */
24846 + } else if (!tags.chunk_used) {
24847 + /* An unassigned chunk in the block
24848 + * This means that either the block is empty or
24849 + * this is the one being allocated from
24850 + */
24851 +
24852 + if (c == 0) {
24853 + /* We're looking at the first chunk in the block so the block is unused */
24854 + state = YAFFS_BLOCK_STATE_EMPTY;
24855 + dev->n_erased_blocks++;
24856 + } else {
24857 + /* this is the block being allocated from */
24858 + T(YAFFS_TRACE_SCAN,
24859 + (TSTR
24860 + (" Allocating from %d %d" TENDSTR),
24861 + blk, c));
24862 + state = YAFFS_BLOCK_STATE_ALLOCATING;
24863 + dev->alloc_block = blk;
24864 + dev->alloc_page = c;
24865 + dev->alloc_block_finder = blk;
24866 + /* Set block finder here to encourage the allocator to go forth from here. */
24867 +
24868 + }
24869 +
24870 + dev->n_free_chunks += (dev->param.chunks_per_block - c);
24871 + } else if (tags.chunk_id > 0) {
24872 + /* chunk_id > 0 so it is a data chunk... */
24873 + unsigned int endpos;
24874 +
24875 + yaffs_set_chunk_bit(dev, blk, c);
24876 + bi->pages_in_use++;
24877 +
24878 + in = yaffs_find_or_create_by_number(dev,
24879 + tags.
24880 + obj_id,
24881 + YAFFS_OBJECT_TYPE_FILE);
24882 + /* PutChunkIntoFile checks for a clash (two data chunks with
24883 + * the same chunk_id).
24884 + */
24885 +
24886 + if (!in)
24887 + alloc_failed = 1;
24888 +
24889 + if (in) {
24890 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1))
24891 + alloc_failed = 1;
24892 + }
24893 +
24894 + endpos =
24895 + (tags.chunk_id - 1) * dev->data_bytes_per_chunk +
24896 + tags.n_bytes;
24897 + if (in &&
24898 + in->variant_type == YAFFS_OBJECT_TYPE_FILE
24899 + && in->variant.file_variant.scanned_size <
24900 + endpos) {
24901 + in->variant.file_variant.
24902 + scanned_size = endpos;
24903 + if (!dev->param.use_header_file_size) {
24904 + in->variant.file_variant.
24905 + file_size =
24906 + in->variant.file_variant.
24907 + scanned_size;
24908 + }
24909 +
24910 + }
24911 + /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
24912 + } else {
24913 + /* chunk_id == 0, so it is an ObjectHeader.
24914 + * Thus, we read in the object header and make the object
24915 + */
24916 + yaffs_set_chunk_bit(dev, blk, c);
24917 + bi->pages_in_use++;
24918 +
24919 + result = yaffs_rd_chunk_tags_nand(dev, chunk,
24920 + chunkData,
24921 + NULL);
24922 +
24923 + oh = (yaffs_obj_header *) chunkData;
24924 +
24925 + in = yaffs_find_by_number(dev,
24926 + tags.obj_id);
24927 + if (in && in->variant_type != oh->type) {
24928 + /* This should not happen, but somehow
24929 + * Wev'e ended up with an obj_id that has been reused but not yet
24930 + * deleted, and worse still it has changed type. Delete the old object.
24931 + */
24932 +
24933 + yaffs_del_obj(in);
24934 +
24935 + in = 0;
24936 + }
24937 +
24938 + in = yaffs_find_or_create_by_number(dev,
24939 + tags.
24940 + obj_id,
24941 + oh->type);
24942 +
24943 + if (!in)
24944 + alloc_failed = 1;
24945 +
24946 + if (in && oh->shadows_obj > 0) {
24947 +
24948 + struct yaffs_shadow_fixer_s *fixer;
24949 + fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s));
24950 + if (fixer) {
24951 + fixer->next = shadowFixerList;
24952 + shadowFixerList = fixer;
24953 + fixer->obj_id = tags.obj_id;
24954 + fixer->shadowed_id = oh->shadows_obj;
24955 + T(YAFFS_TRACE_SCAN,
24956 + (TSTR
24957 + (" Shadow fixer: %d shadows %d" TENDSTR),
24958 + fixer->obj_id, fixer->shadowed_id));
24959 +
24960 + }
24961 +
24962 + }
24963 +
24964 + if (in && in->valid) {
24965 + /* We have already filled this one. We have a duplicate and need to resolve it. */
24966 +
24967 + unsigned existingSerial = in->serial;
24968 + unsigned newSerial = tags.serial_number;
24969 +
24970 + if (((existingSerial + 1) & 3) == newSerial) {
24971 + /* Use new one - destroy the exisiting one */
24972 + yaffs_chunk_del(dev,
24973 + in->hdr_chunk,
24974 + 1, __LINE__);
24975 + in->valid = 0;
24976 + } else {
24977 + /* Use existing - destroy this one. */
24978 + yaffs_chunk_del(dev, chunk, 1,
24979 + __LINE__);
24980 + }
24981 + }
24982 +
24983 + if (in && !in->valid &&
24984 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
24985 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
24986 + /* We only load some info, don't fiddle with directory structure */
24987 + in->valid = 1;
24988 + in->variant_type = oh->type;
24989 +
24990 + in->yst_mode = oh->yst_mode;
24991 +#ifdef CONFIG_YAFFS_WINCE
24992 + in->win_atime[0] = oh->win_atime[0];
24993 + in->win_ctime[0] = oh->win_ctime[0];
24994 + in->win_mtime[0] = oh->win_mtime[0];
24995 + in->win_atime[1] = oh->win_atime[1];
24996 + in->win_ctime[1] = oh->win_ctime[1];
24997 + in->win_mtime[1] = oh->win_mtime[1];
24998 +#else
24999 + in->yst_uid = oh->yst_uid;
25000 + in->yst_gid = oh->yst_gid;
25001 + in->yst_atime = oh->yst_atime;
25002 + in->yst_mtime = oh->yst_mtime;
25003 + in->yst_ctime = oh->yst_ctime;
25004 + in->yst_rdev = oh->yst_rdev;
25005 +#endif
25006 + in->hdr_chunk = chunk;
25007 + in->serial = tags.serial_number;
25008 +
25009 + } else if (in && !in->valid) {
25010 + /* we need to load this info */
25011 +
25012 + in->valid = 1;
25013 + in->variant_type = oh->type;
25014 +
25015 + in->yst_mode = oh->yst_mode;
25016 +#ifdef CONFIG_YAFFS_WINCE
25017 + in->win_atime[0] = oh->win_atime[0];
25018 + in->win_ctime[0] = oh->win_ctime[0];
25019 + in->win_mtime[0] = oh->win_mtime[0];
25020 + in->win_atime[1] = oh->win_atime[1];
25021 + in->win_ctime[1] = oh->win_ctime[1];
25022 + in->win_mtime[1] = oh->win_mtime[1];
25023 +#else
25024 + in->yst_uid = oh->yst_uid;
25025 + in->yst_gid = oh->yst_gid;
25026 + in->yst_atime = oh->yst_atime;
25027 + in->yst_mtime = oh->yst_mtime;
25028 + in->yst_ctime = oh->yst_ctime;
25029 + in->yst_rdev = oh->yst_rdev;
25030 +#endif
25031 + in->hdr_chunk = chunk;
25032 + in->serial = tags.serial_number;
25033 +
25034 + yaffs_set_obj_name_from_oh(in, oh);
25035 + in->dirty = 0;
25036 +
25037 + /* directory stuff...
25038 + * hook up to parent
25039 + */
25040 +
25041 + parent =
25042 + yaffs_find_or_create_by_number
25043 + (dev, oh->parent_obj_id,
25044 + YAFFS_OBJECT_TYPE_DIRECTORY);
25045 + if (!parent)
25046 + alloc_failed = 1;
25047 + if (parent && parent->variant_type ==
25048 + YAFFS_OBJECT_TYPE_UNKNOWN) {
25049 + /* Set up as a directory */
25050 + parent->variant_type =
25051 + YAFFS_OBJECT_TYPE_DIRECTORY;
25052 + YINIT_LIST_HEAD(&parent->variant.
25053 + dir_variant.
25054 + children);
25055 + } else if (!parent || parent->variant_type !=
25056 + YAFFS_OBJECT_TYPE_DIRECTORY) {
25057 + /* Hoosterman, another problem....
25058 + * We're trying to use a non-directory as a directory
25059 + */
25060 +
25061 + T(YAFFS_TRACE_ERROR,
25062 + (TSTR
25063 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
25064 + TENDSTR)));
25065 + parent = dev->lost_n_found;
25066 + }
25067 +
25068 + yaffs_add_obj_to_dir(parent, in);
25069 +
25070 + if (0 && (parent == dev->del_dir ||
25071 + parent == dev->unlinked_dir)) {
25072 + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
25073 + dev->n_deleted_files++;
25074 + }
25075 + /* Note re hardlinks.
25076 + * Since we might scan a hardlink before its equivalent object is scanned
25077 + * we put them all in a list.
25078 + * After scanning is complete, we should have all the objects, so we run through this
25079 + * list and fix up all the chains.
25080 + */
25081 +
25082 + switch (in->variant_type) {
25083 + case YAFFS_OBJECT_TYPE_UNKNOWN:
25084 + /* Todo got a problem */
25085 + break;
25086 + case YAFFS_OBJECT_TYPE_FILE:
25087 + if (dev->param.use_header_file_size)
25088 +
25089 + in->variant.file_variant.
25090 + file_size =
25091 + oh->file_size;
25092 +
25093 + break;
25094 + case YAFFS_OBJECT_TYPE_HARDLINK:
25095 + in->variant.hardlink_variant.
25096 + equiv_id =
25097 + oh->equiv_id;
25098 + in->hard_links.next =
25099 + (struct ylist_head *)
25100 + hard_list;
25101 + hard_list = in;
25102 + break;
25103 + case YAFFS_OBJECT_TYPE_DIRECTORY:
25104 + /* Do nothing */
25105 + break;
25106 + case YAFFS_OBJECT_TYPE_SPECIAL:
25107 + /* Do nothing */
25108 + break;
25109 + case YAFFS_OBJECT_TYPE_SYMLINK:
25110 + in->variant.symlink_variant.alias =
25111 + yaffs_clone_str(oh->alias);
25112 + if (!in->variant.symlink_variant.alias)
25113 + alloc_failed = 1;
25114 + break;
25115 + }
25116 +
25117 + }
25118 + }
25119 + }
25120 +
25121 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
25122 + /* If we got this far while scanning, then the block is fully allocated.*/
25123 + state = YAFFS_BLOCK_STATE_FULL;
25124 + }
25125 +
25126 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
25127 + /* If the block was partially allocated then treat it as fully allocated.*/
25128 + state = YAFFS_BLOCK_STATE_FULL;
25129 + dev->alloc_block = -1;
25130 + }
25131 +
25132 + bi->block_state = state;
25133 +
25134 + /* Now let's see if it was dirty */
25135 + if (bi->pages_in_use == 0 &&
25136 + !bi->has_shrink_hdr &&
25137 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
25138 + yaffs_block_became_dirty(dev, blk);
25139 + }
25140 +
25141 + }
25142 +
25143 +
25144 + /* Ok, we've done all the scanning.
25145 + * Fix up the hard link chains.
25146 + * We should now have scanned all the objects, now it's time to add these
25147 + * hardlinks.
25148 + */
25149 +
25150 + yaffs_link_fixup(dev, hard_list);
25151 +
25152 + /* Fix up any shadowed objects */
25153 + {
25154 + struct yaffs_shadow_fixer_s *fixer;
25155 + yaffs_obj_t *obj;
25156 +
25157 + while (shadowFixerList) {
25158 + fixer = shadowFixerList;
25159 + shadowFixerList = fixer->next;
25160 + /* Complete the rename transaction by deleting the shadowed object
25161 + * then setting the object header to unshadowed.
25162 + */
25163 + obj = yaffs_find_by_number(dev, fixer->shadowed_id);
25164 + if (obj)
25165 + yaffs_del_obj(obj);
25166 +
25167 + obj = yaffs_find_by_number(dev, fixer->obj_id);
25168 +
25169 + if (obj)
25170 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
25171 +
25172 + YFREE(fixer);
25173 + }
25174 + }
25175 +
25176 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
25177 +
25178 + if (alloc_failed)
25179 + return YAFFS_FAIL;
25180 +
25181 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
25182 +
25183 +
25184 + return YAFFS_OK;
25185 +}
25186 +
25187 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.h
25188 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 02:00:00.000000000 +0200
25189 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs1.h 2010-10-20 13:28:16.064000294 +0300
25190 @@ -0,0 +1,22 @@
25191 +/*
25192 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
25193 + *
25194 + * Copyright (C) 2002-2010 Aleph One Ltd.
25195 + * for Toby Churchill Ltd and Brightstar Engineering
25196 + *
25197 + * Created by Charles Manning <charles@aleph1.co.uk>
25198 + *
25199 + * This program is free software; you can redistribute it and/or modify
25200 + * it under the terms of the GNU Lesser General Public License version 2.1 as
25201 + * published by the Free Software Foundation.
25202 + *
25203 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
25204 + */
25205 +
25206 +#ifndef __YAFFS_YAFFS1_H__
25207 +#define __YAFFS_YAFFS1_H__
25208 +
25209 +#include "yaffs_guts.h"
25210 +int yaffs1_scan(yaffs_dev_t *dev);
25211 +
25212 +#endif
25213 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.c linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.c
25214 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 02:00:00.000000000 +0200
25215 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.c 2010-10-20 13:28:16.050000294 +0300
25216 @@ -0,0 +1,1540 @@
25217 +/*
25218 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
25219 + *
25220 + * Copyright (C) 2002-2010 Aleph One Ltd.
25221 + * for Toby Churchill Ltd and Brightstar Engineering
25222 + *
25223 + * Created by Charles Manning <charles@aleph1.co.uk>
25224 + *
25225 + * This program is free software; you can redistribute it and/or modify
25226 + * it under the terms of the GNU General Public License version 2 as
25227 + * published by the Free Software Foundation.
25228 + */
25229 +
25230 +
25231 +#include "yaffs_guts.h"
25232 +#include "yaffs_trace.h"
25233 +#include "yaffs_yaffs2.h"
25234 +#include "yaffs_checkptrw.h"
25235 +#include "yaffs_bitmap.h"
25236 +#include "yaffs_qsort.h"
25237 +#include "yaffs_nand.h"
25238 +#include "yaffs_getblockinfo.h"
25239 +#include "yaffs_verify.h"
25240 +
25241 +/*
25242 + * Checkpoints are really no benefit on very small partitions.
25243 + *
25244 + * To save space on small partitions don't bother with checkpoints unless
25245 + * the partition is at least this big.
25246 + */
25247 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
25248 +
25249 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
25250 +
25251 +
25252 +/*
25253 + * Oldest Dirty Sequence Number handling.
25254 + */
25255 +
25256 +/* yaffs_calc_oldest_dirty_seq()
25257 + * yaffs2_find_oldest_dirty_seq()
25258 + * Calculate the oldest dirty sequence number if we don't know it.
25259 + */
25260 +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev)
25261 +{
25262 + int i;
25263 + unsigned seq;
25264 + unsigned block_no = 0;
25265 + yaffs_block_info_t *b;
25266 +
25267 + if(!dev->param.is_yaffs2)
25268 + return;
25269 +
25270 + /* Find the oldest dirty sequence number. */
25271 + seq = dev->seq_number + 1;
25272 + b = dev->block_info;
25273 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
25274 + if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
25275 + (b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block &&
25276 + b->seq_number < seq) {
25277 + seq = b->seq_number;
25278 + block_no = i;
25279 + }
25280 + b++;
25281 + }
25282 +
25283 + if(block_no){
25284 + dev->oldest_dirty_seq = seq;
25285 + dev->oldest_dirty_block = block_no;
25286 + }
25287 +
25288 +}
25289 +
25290 +
25291 +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev)
25292 +{
25293 + if(!dev->param.is_yaffs2)
25294 + return;
25295 +
25296 + if(!dev->oldest_dirty_seq)
25297 + yaffs_calc_oldest_dirty_seq(dev);
25298 +}
25299 +
25300 +/*
25301 + * yaffs_clear_oldest_dirty_seq()
25302 + * Called when a block is erased or marked bad. (ie. when its seq_number
25303 + * becomes invalid). If the value matches the oldest then we clear
25304 + * dev->oldest_dirty_seq to force its recomputation.
25305 + */
25306 +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi)
25307 +{
25308 +
25309 + if(!dev->param.is_yaffs2)
25310 + return;
25311 +
25312 + if(!bi || bi->seq_number == dev->oldest_dirty_seq){
25313 + dev->oldest_dirty_seq = 0;
25314 + dev->oldest_dirty_block = 0;
25315 + }
25316 +}
25317 +
25318 +/*
25319 + * yaffs2_update_oldest_dirty_seq()
25320 + * Update the oldest dirty sequence number whenever we dirty a block.
25321 + * Only do this if the oldest_dirty_seq is actually being tracked.
25322 + */
25323 +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi)
25324 +{
25325 + if(!dev->param.is_yaffs2)
25326 + return;
25327 +
25328 + if(dev->oldest_dirty_seq){
25329 + if(dev->oldest_dirty_seq > bi->seq_number){
25330 + dev->oldest_dirty_seq = bi->seq_number;
25331 + dev->oldest_dirty_block = block_no;
25332 + }
25333 + }
25334 +}
25335 +
25336 +int yaffs_block_ok_for_gc(yaffs_dev_t *dev,
25337 + yaffs_block_info_t *bi)
25338 +{
25339 +
25340 + if (!dev->param.is_yaffs2)
25341 + return 1; /* disqualification only applies to yaffs2. */
25342 +
25343 + if (!bi->has_shrink_hdr)
25344 + return 1; /* can gc */
25345 +
25346 + yaffs2_find_oldest_dirty_seq(dev);
25347 +
25348 + /* Can't do gc of this block if there are any blocks older than this one that have
25349 + * discarded pages.
25350 + */
25351 + return (bi->seq_number <= dev->oldest_dirty_seq);
25352 +}
25353 +
25354 +/*
25355 + * yaffs2_find_refresh_block()
25356 + * periodically finds the oldest full block by sequence number for refreshing.
25357 + * Only for yaffs2.
25358 + */
25359 +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev)
25360 +{
25361 + __u32 b ;
25362 +
25363 + __u32 oldest = 0;
25364 + __u32 oldestSequence = 0;
25365 +
25366 + yaffs_block_info_t *bi;
25367 +
25368 + if(!dev->param.is_yaffs2)
25369 + return oldest;
25370 +
25371 + /*
25372 + * If refresh period < 10 then refreshing is disabled.
25373 + */
25374 + if(dev->param.refresh_period < 10)
25375 + return oldest;
25376 +
25377 + /*
25378 + * Fix broken values.
25379 + */
25380 + if(dev->refresh_skip > dev->param.refresh_period)
25381 + dev->refresh_skip = dev->param.refresh_period;
25382 +
25383 + if(dev->refresh_skip > 0)
25384 + return oldest;
25385 +
25386 + /*
25387 + * Refresh skip is now zero.
25388 + * We'll do a refresh this time around....
25389 + * Update the refresh skip and find the oldest block.
25390 + */
25391 + dev->refresh_skip = dev->param.refresh_period;
25392 + dev->refresh_count++;
25393 + bi = dev->block_info;
25394 + for (b = dev->internal_start_block; b <=dev->internal_end_block; b++){
25395 +
25396 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL){
25397 +
25398 + if(oldest < 1 ||
25399 + bi->seq_number < oldestSequence){
25400 + oldest = b;
25401 + oldestSequence = bi->seq_number;
25402 + }
25403 + }
25404 + bi++;
25405 + }
25406 +
25407 + if (oldest > 0) {
25408 + T(YAFFS_TRACE_GC,
25409 + (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR),
25410 + dev->refresh_count, oldest, oldestSequence));
25411 + }
25412 +
25413 + return oldest;
25414 +}
25415 +
25416 +int yaffs2_checkpt_required(yaffs_dev_t *dev)
25417 +{
25418 + int nblocks;
25419 +
25420 + if(!dev->param.is_yaffs2)
25421 + return 0;
25422 +
25423 + nblocks = dev->internal_end_block - dev->internal_start_block + 1 ;
25424 +
25425 + return !dev->param.skip_checkpt_wr &&
25426 + !dev->read_only &&
25427 + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
25428 +}
25429 +
25430 +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev)
25431 +{
25432 + int retval;
25433 +
25434 + if(!dev->param.is_yaffs2)
25435 + return 0;
25436 +
25437 + if (!dev->checkpoint_blocks_required &&
25438 + yaffs2_checkpt_required(dev)){
25439 + /* Not a valid value so recalculate */
25440 + int n_bytes = 0;
25441 + int nBlocks;
25442 + int devBlocks = (dev->param.end_block - dev->param.start_block + 1);
25443 +
25444 + n_bytes += sizeof(yaffs_checkpt_validty_t);
25445 + n_bytes += sizeof(yaffs_checkpt_dev_t);
25446 + n_bytes += devBlocks * sizeof(yaffs_block_info_t);
25447 + n_bytes += devBlocks * dev->chunk_bit_stride;
25448 + n_bytes += (sizeof(yaffs_checkpt_obj_t) + sizeof(__u32)) * (dev->n_obj);
25449 + n_bytes += (dev->tnode_size + sizeof(__u32)) * (dev->n_tnodes);
25450 + n_bytes += sizeof(yaffs_checkpt_validty_t);
25451 + n_bytes += sizeof(__u32); /* checksum*/
25452 +
25453 + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
25454 +
25455 + nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3;
25456 +
25457 + dev->checkpoint_blocks_required = nBlocks;
25458 + }
25459 +
25460 + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
25461 + if(retval < 0)
25462 + retval = 0;
25463 + return retval;
25464 +}
25465 +
25466 +/*--------------------- Checkpointing --------------------*/
25467 +
25468 +
25469 +static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head)
25470 +{
25471 + yaffs_checkpt_validty_t cp;
25472 +
25473 + memset(&cp, 0, sizeof(cp));
25474 +
25475 + cp.struct_type = sizeof(cp);
25476 + cp.magic = YAFFS_MAGIC;
25477 + cp.version = YAFFS_CHECKPOINT_VERSION;
25478 + cp.head = (head) ? 1 : 0;
25479 +
25480 + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
25481 + 1 : 0;
25482 +}
25483 +
25484 +static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head)
25485 +{
25486 + yaffs_checkpt_validty_t cp;
25487 + int ok;
25488 +
25489 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25490 +
25491 + if (ok)
25492 + ok = (cp.struct_type == sizeof(cp)) &&
25493 + (cp.magic == YAFFS_MAGIC) &&
25494 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
25495 + (cp.head == ((head) ? 1 : 0));
25496 + return ok ? 1 : 0;
25497 +}
25498 +
25499 +static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp,
25500 + yaffs_dev_t *dev)
25501 +{
25502 + cp->n_erased_blocks = dev->n_erased_blocks;
25503 + cp->alloc_block = dev->alloc_block;
25504 + cp->alloc_page = dev->alloc_page;
25505 + cp->n_free_chunks = dev->n_free_chunks;
25506 +
25507 + cp->n_deleted_files = dev->n_deleted_files;
25508 + cp->n_unlinked_files = dev->n_unlinked_files;
25509 + cp->n_bg_deletions = dev->n_bg_deletions;
25510 + cp->seq_number = dev->seq_number;
25511 +
25512 +}
25513 +
25514 +static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev,
25515 + yaffs_checkpt_dev_t *cp)
25516 +{
25517 + dev->n_erased_blocks = cp->n_erased_blocks;
25518 + dev->alloc_block = cp->alloc_block;
25519 + dev->alloc_page = cp->alloc_page;
25520 + dev->n_free_chunks = cp->n_free_chunks;
25521 +
25522 + dev->n_deleted_files = cp->n_deleted_files;
25523 + dev->n_unlinked_files = cp->n_unlinked_files;
25524 + dev->n_bg_deletions = cp->n_bg_deletions;
25525 + dev->seq_number = cp->seq_number;
25526 +}
25527 +
25528 +
25529 +static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev)
25530 +{
25531 + yaffs_checkpt_dev_t cp;
25532 + __u32 n_bytes;
25533 + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
25534 +
25535 + int ok;
25536 +
25537 + /* Write device runtime values*/
25538 + yaffs2_dev_to_checkpt_dev(&cp, dev);
25539 + cp.struct_type = sizeof(cp);
25540 +
25541 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25542 +
25543 + /* Write block info */
25544 + if (ok) {
25545 + n_bytes = nBlocks * sizeof(yaffs_block_info_t);
25546 + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
25547 + }
25548 +
25549 + /* Write chunk bits */
25550 + if (ok) {
25551 + n_bytes = nBlocks * dev->chunk_bit_stride;
25552 + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
25553 + }
25554 + return ok ? 1 : 0;
25555 +
25556 +}
25557 +
25558 +static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev)
25559 +{
25560 + yaffs_checkpt_dev_t cp;
25561 + __u32 n_bytes;
25562 + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
25563 +
25564 + int ok;
25565 +
25566 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25567 + if (!ok)
25568 + return 0;
25569 +
25570 + if (cp.struct_type != sizeof(cp))
25571 + return 0;
25572 +
25573 +
25574 + yaffs_checkpt_dev_to_dev(dev, &cp);
25575 +
25576 + n_bytes = nBlocks * sizeof(yaffs_block_info_t);
25577 +
25578 + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
25579 +
25580 + if (!ok)
25581 + return 0;
25582 + n_bytes = nBlocks * dev->chunk_bit_stride;
25583 +
25584 + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
25585 +
25586 + return ok ? 1 : 0;
25587 +}
25588 +
25589 +static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp,
25590 + yaffs_obj_t *obj)
25591 +{
25592 +
25593 + cp->obj_id = obj->obj_id;
25594 + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
25595 + cp->hdr_chunk = obj->hdr_chunk;
25596 + cp->variant_type = obj->variant_type;
25597 + cp->deleted = obj->deleted;
25598 + cp->soft_del = obj->soft_del;
25599 + cp->unlinked = obj->unlinked;
25600 + cp->fake = obj->fake;
25601 + cp->rename_allowed = obj->rename_allowed;
25602 + cp->unlink_allowed = obj->unlink_allowed;
25603 + cp->serial = obj->serial;
25604 + cp->n_data_chunks = obj->n_data_chunks;
25605 +
25606 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25607 + cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
25608 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
25609 + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
25610 +}
25611 +
25612 +static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp)
25613 +{
25614 +
25615 + yaffs_obj_t *parent;
25616 +
25617 + if (obj->variant_type != cp->variant_type) {
25618 + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
25619 + TCONT("chunk %d does not match existing object type %d")
25620 + TENDSTR), cp->obj_id, cp->variant_type, cp->hdr_chunk,
25621 + obj->variant_type));
25622 + return 0;
25623 + }
25624 +
25625 + obj->obj_id = cp->obj_id;
25626 +
25627 + if (cp->parent_id)
25628 + parent = yaffs_find_or_create_by_number(
25629 + obj->my_dev,
25630 + cp->parent_id,
25631 + YAFFS_OBJECT_TYPE_DIRECTORY);
25632 + else
25633 + parent = NULL;
25634 +
25635 + if (parent) {
25636 + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
25637 + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
25638 + TCONT(" chunk %d Parent type, %d, not directory")
25639 + TENDSTR),
25640 + cp->obj_id, cp->parent_id, cp->variant_type,
25641 + cp->hdr_chunk, parent->variant_type));
25642 + return 0;
25643 + }
25644 + yaffs_add_obj_to_dir(parent, obj);
25645 + }
25646 +
25647 + obj->hdr_chunk = cp->hdr_chunk;
25648 + obj->variant_type = cp->variant_type;
25649 + obj->deleted = cp->deleted;
25650 + obj->soft_del = cp->soft_del;
25651 + obj->unlinked = cp->unlinked;
25652 + obj->fake = cp->fake;
25653 + obj->rename_allowed = cp->rename_allowed;
25654 + obj->unlink_allowed = cp->unlink_allowed;
25655 + obj->serial = cp->serial;
25656 + obj->n_data_chunks = cp->n_data_chunks;
25657 +
25658 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25659 + obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
25660 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
25661 + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
25662 +
25663 + if (obj->hdr_chunk > 0)
25664 + obj->lazy_loaded = 1;
25665 + return 1;
25666 +}
25667 +
25668 +
25669 +
25670 +static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
25671 + __u32 level, int chunk_offset)
25672 +{
25673 + int i;
25674 + yaffs_dev_t *dev = in->my_dev;
25675 + int ok = 1;
25676 +
25677 + if (tn) {
25678 + if (level > 0) {
25679 +
25680 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
25681 + if (tn->internal[i]) {
25682 + ok = yaffs2_checkpt_tnode_worker(in,
25683 + tn->internal[i],
25684 + level - 1,
25685 + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
25686 + }
25687 + }
25688 + } else if (level == 0) {
25689 + __u32 baseOffset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
25690 + ok = (yaffs2_checkpt_wr(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
25691 + if (ok)
25692 + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size);
25693 + }
25694 + }
25695 +
25696 + return ok;
25697 +
25698 +}
25699 +
25700 +static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj)
25701 +{
25702 + __u32 endMarker = ~0;
25703 + int ok = 1;
25704 +
25705 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
25706 + ok = yaffs2_checkpt_tnode_worker(obj,
25707 + obj->variant.file_variant.top,
25708 + obj->variant.file_variant.top_level,
25709 + 0);
25710 + if (ok)
25711 + ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) ==
25712 + sizeof(endMarker));
25713 + }
25714 +
25715 + return ok ? 1 : 0;
25716 +}
25717 +
25718 +static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj)
25719 +{
25720 + __u32 baseChunk;
25721 + int ok = 1;
25722 + yaffs_dev_t *dev = obj->my_dev;
25723 + yaffs_file_s *fileStructPtr = &obj->variant.file_variant;
25724 + yaffs_tnode_t *tn;
25725 + int nread = 0;
25726 +
25727 + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
25728 +
25729 + while (ok && (~baseChunk)) {
25730 + nread++;
25731 + /* Read level 0 tnode */
25732 +
25733 +
25734 + tn = yaffs_get_tnode(dev);
25735 + if (tn){
25736 + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size);
25737 + } else
25738 + ok = 0;
25739 +
25740 + if (tn && ok)
25741 + ok = yaffs_add_find_tnode_0(dev,
25742 + fileStructPtr,
25743 + baseChunk,
25744 + tn) ? 1 : 0;
25745 +
25746 + if (ok)
25747 + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
25748 +
25749 + }
25750 +
25751 + T(YAFFS_TRACE_CHECKPOINT, (
25752 + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
25753 + nread, baseChunk, ok));
25754 +
25755 + return ok ? 1 : 0;
25756 +}
25757 +
25758 +
25759 +static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev)
25760 +{
25761 + yaffs_obj_t *obj;
25762 + yaffs_checkpt_obj_t cp;
25763 + int i;
25764 + int ok = 1;
25765 + struct ylist_head *lh;
25766 +
25767 +
25768 + /* Iterate through the objects in each hash entry,
25769 + * dumping them to the checkpointing stream.
25770 + */
25771 +
25772 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
25773 + ylist_for_each(lh, &dev->obj_bucket[i].list) {
25774 + if (lh) {
25775 + obj = ylist_entry(lh, yaffs_obj_t, hash_link);
25776 + if (!obj->defered_free) {
25777 + yaffs2_obj_checkpt_obj(&cp, obj);
25778 + cp.struct_type = sizeof(cp);
25779 +
25780 + T(YAFFS_TRACE_CHECKPOINT, (
25781 + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
25782 + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk, obj));
25783 +
25784 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25785 +
25786 + if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
25787 + ok = yaffs2_wr_checkpt_tnodes(obj);
25788 + }
25789 + }
25790 + }
25791 + }
25792 +
25793 + /* Dump end of list */
25794 + memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t));
25795 + cp.struct_type = sizeof(cp);
25796 +
25797 + if (ok)
25798 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
25799 +
25800 + return ok ? 1 : 0;
25801 +}
25802 +
25803 +static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev)
25804 +{
25805 + yaffs_obj_t *obj;
25806 + yaffs_checkpt_obj_t cp;
25807 + int ok = 1;
25808 + int done = 0;
25809 + yaffs_obj_t *hard_list = NULL;
25810 +
25811 + while (ok && !done) {
25812 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
25813 + if (cp.struct_type != sizeof(cp)) {
25814 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
25815 + cp.struct_type, (int)sizeof(cp), ok));
25816 + ok = 0;
25817 + }
25818 +
25819 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
25820 + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk));
25821 +
25822 + if (ok && cp.obj_id == ~0)
25823 + done = 1;
25824 + else if (ok) {
25825 + obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type);
25826 + if (obj) {
25827 + ok = taffs2_checkpt_obj_to_obj(obj, &cp);
25828 + if (!ok)
25829 + break;
25830 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
25831 + ok = yaffs2_rd_checkpt_tnodes(obj);
25832 + } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
25833 + obj->hard_links.next =
25834 + (struct ylist_head *) hard_list;
25835 + hard_list = obj;
25836 + }
25837 + } else
25838 + ok = 0;
25839 + }
25840 + }
25841 +
25842 + if (ok)
25843 + yaffs_link_fixup(dev, hard_list);
25844 +
25845 + return ok ? 1 : 0;
25846 +}
25847 +
25848 +static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev)
25849 +{
25850 + __u32 checkpt_sum;
25851 + int ok;
25852 +
25853 + yaffs2_get_checkpt_sum(dev, &checkpt_sum);
25854 +
25855 + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum));
25856 +
25857 + if (!ok)
25858 + return 0;
25859 +
25860 + return 1;
25861 +}
25862 +
25863 +static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev)
25864 +{
25865 + __u32 checkpt_sum0;
25866 + __u32 checkpt_sum1;
25867 + int ok;
25868 +
25869 + yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
25870 +
25871 + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1));
25872 +
25873 + if (!ok)
25874 + return 0;
25875 +
25876 + if (checkpt_sum0 != checkpt_sum1)
25877 + return 0;
25878 +
25879 + return 1;
25880 +}
25881 +
25882 +
25883 +static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev)
25884 +{
25885 + int ok = 1;
25886 +
25887 + if (!yaffs2_checkpt_required(dev)) {
25888 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
25889 + ok = 0;
25890 + }
25891 +
25892 + if (ok)
25893 + ok = yaffs2_checkpt_open(dev, 1);
25894 +
25895 + if (ok) {
25896 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
25897 + ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
25898 + }
25899 + if (ok) {
25900 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
25901 + ok = yaffs2_wr_checkpt_dev(dev);
25902 + }
25903 + if (ok) {
25904 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
25905 + ok = yaffs2_wr_checkpt_objs(dev);
25906 + }
25907 + if (ok) {
25908 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
25909 + ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
25910 + }
25911 +
25912 + if (ok)
25913 + ok = yaffs2_wr_checkpt_sum(dev);
25914 +
25915 + if (!yaffs_checkpt_close(dev))
25916 + ok = 0;
25917 +
25918 + if (ok)
25919 + dev->is_checkpointed = 1;
25920 + else
25921 + dev->is_checkpointed = 0;
25922 +
25923 + return dev->is_checkpointed;
25924 +}
25925 +
25926 +static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev)
25927 +{
25928 + int ok = 1;
25929 +
25930 + if(!dev->param.is_yaffs2)
25931 + ok = 0;
25932 +
25933 + if (ok && dev->param.skip_checkpt_rd) {
25934 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
25935 + ok = 0;
25936 + }
25937 +
25938 + if (ok)
25939 + ok = yaffs2_checkpt_open(dev, 0); /* open for read */
25940 +
25941 + if (ok) {
25942 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
25943 + ok = yaffs2_rd_checkpt_validty_marker(dev, 1);
25944 + }
25945 + if (ok) {
25946 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
25947 + ok = yaffs2_rd_checkpt_dev(dev);
25948 + }
25949 + if (ok) {
25950 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
25951 + ok = yaffs2_rd_checkpt_objs(dev);
25952 + }
25953 + if (ok) {
25954 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
25955 + ok = yaffs2_rd_checkpt_validty_marker(dev, 0);
25956 + }
25957 +
25958 + if (ok) {
25959 + ok = yaffs2_rd_checkpt_sum(dev);
25960 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
25961 + }
25962 +
25963 + if (!yaffs_checkpt_close(dev))
25964 + ok = 0;
25965 +
25966 + if (ok)
25967 + dev->is_checkpointed = 1;
25968 + else
25969 + dev->is_checkpointed = 0;
25970 +
25971 + return ok ? 1 : 0;
25972 +
25973 +}
25974 +
25975 +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev)
25976 +{
25977 + if (dev->is_checkpointed ||
25978 + dev->blocks_in_checkpt > 0) {
25979 + dev->is_checkpointed = 0;
25980 + yaffs2_checkpt_invalidate_stream(dev);
25981 + }
25982 + if (dev->param.sb_dirty_fn)
25983 + dev->param.sb_dirty_fn(dev);
25984 +}
25985 +
25986 +
25987 +int yaffs_checkpoint_save(yaffs_dev_t *dev)
25988 +{
25989 +
25990 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
25991 +
25992 + yaffs_verify_objects(dev);
25993 + yaffs_verify_blocks(dev);
25994 + yaffs_verify_free_chunks(dev);
25995 +
25996 + if (!dev->is_checkpointed) {
25997 + yaffs2_checkpt_invalidate(dev);
25998 + yaffs2_wr_checkpt_data(dev);
25999 + }
26000 +
26001 + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
26002 +
26003 + return dev->is_checkpointed;
26004 +}
26005 +
26006 +int yaffs2_checkpt_restore(yaffs_dev_t *dev)
26007 +{
26008 + int retval;
26009 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
26010 +
26011 + retval = yaffs2_rd_checkpt_data(dev);
26012 +
26013 + if (dev->is_checkpointed) {
26014 + yaffs_verify_objects(dev);
26015 + yaffs_verify_blocks(dev);
26016 + yaffs_verify_free_chunks(dev);
26017 + }
26018 +
26019 + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
26020 +
26021 + return retval;
26022 +}
26023 +
26024 +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size)
26025 +{
26026 + /* if newsSize > oldFileSize.
26027 + * We're going to be writing a hole.
26028 + * If the hole is small then write zeros otherwise write a start of hole marker.
26029 + */
26030 +
26031 +
26032 + loff_t oldFileSize;
26033 + int increase;
26034 + int smallHole ;
26035 + int result = YAFFS_OK;
26036 + yaffs_dev_t *dev = NULL;
26037 +
26038 + __u8 *localBuffer = NULL;
26039 +
26040 + int smallIncreaseOk = 0;
26041 +
26042 + if(!obj)
26043 + return YAFFS_FAIL;
26044 +
26045 + if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
26046 + return YAFFS_FAIL;
26047 +
26048 + dev = obj->my_dev;
26049 +
26050 + /* Bail out if not yaffs2 mode */
26051 + if(!dev->param.is_yaffs2)
26052 + return YAFFS_OK;
26053 +
26054 + oldFileSize = obj->variant.file_variant.file_size;
26055 +
26056 + if (new_size <= oldFileSize)
26057 + return YAFFS_OK;
26058 +
26059 + increase = new_size - oldFileSize;
26060 +
26061 + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
26062 + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
26063 + smallHole = 1;
26064 + else
26065 + smallHole = 0;
26066 +
26067 + if(smallHole)
26068 + localBuffer= yaffs_get_temp_buffer(dev, __LINE__);
26069 +
26070 + if(localBuffer){
26071 + /* fill hole with zero bytes */
26072 + int pos = oldFileSize;
26073 + int thisWrite;
26074 + int written;
26075 + memset(localBuffer,0,dev->data_bytes_per_chunk);
26076 + smallIncreaseOk = 1;
26077 +
26078 + while(increase > 0 && smallIncreaseOk){
26079 + thisWrite = increase;
26080 + if(thisWrite > dev->data_bytes_per_chunk)
26081 + thisWrite = dev->data_bytes_per_chunk;
26082 + written = yaffs_do_file_wr(obj,localBuffer,pos,thisWrite,0);
26083 + if(written == thisWrite){
26084 + pos += thisWrite;
26085 + increase -= thisWrite;
26086 + } else
26087 + smallIncreaseOk = 0;
26088 + }
26089 +
26090 + yaffs_release_temp_buffer(dev,localBuffer,__LINE__);
26091 +
26092 + /* If we were out of space then reverse any chunks we've added */
26093 + if(!smallIncreaseOk)
26094 + yaffs_resize_file_down(obj, oldFileSize);
26095 + }
26096 +
26097 + if (!smallIncreaseOk &&
26098 + obj->parent &&
26099 + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
26100 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED){
26101 + /* Write a hole start header with the old file size */
26102 + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
26103 + }
26104 +
26105 + return result;
26106 +
26107 +}
26108 +
26109 +
26110 +typedef struct {
26111 + int seq;
26112 + int block;
26113 +} yaffs_BlockIndex;
26114 +
26115 +
26116 +static int yaffs2_ybicmp(const void *a, const void *b)
26117 +{
26118 + register int aseq = ((yaffs_BlockIndex *)a)->seq;
26119 + register int bseq = ((yaffs_BlockIndex *)b)->seq;
26120 + register int ablock = ((yaffs_BlockIndex *)a)->block;
26121 + register int bblock = ((yaffs_BlockIndex *)b)->block;
26122 + if (aseq == bseq)
26123 + return ablock - bblock;
26124 + else
26125 + return aseq - bseq;
26126 +}
26127 +
26128 +int yaffs2_scan_backwards(yaffs_dev_t *dev)
26129 +{
26130 + yaffs_ext_tags tags;
26131 + int blk;
26132 + int blockIterator;
26133 + int startIterator;
26134 + int endIterator;
26135 + int nBlocksToScan = 0;
26136 +
26137 + int chunk;
26138 + int result;
26139 + int c;
26140 + int deleted;
26141 + yaffs_block_state_t state;
26142 + yaffs_obj_t *hard_list = NULL;
26143 + yaffs_block_info_t *bi;
26144 + __u32 seq_number;
26145 + yaffs_obj_header *oh;
26146 + yaffs_obj_t *in;
26147 + yaffs_obj_t *parent;
26148 + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
26149 + int itsUnlinked;
26150 + __u8 *chunkData;
26151 +
26152 + int file_size;
26153 + int is_shrink;
26154 + int foundChunksInBlock;
26155 + int equiv_id;
26156 + int alloc_failed = 0;
26157 +
26158 +
26159 + yaffs_BlockIndex *blockIndex = NULL;
26160 + int altBlockIndex = 0;
26161 +
26162 + T(YAFFS_TRACE_SCAN,
26163 + (TSTR
26164 + ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
26165 + TENDSTR), dev->internal_start_block, dev->internal_end_block));
26166 +
26167 +
26168 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
26169 +
26170 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
26171 +
26172 + if (!blockIndex) {
26173 + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
26174 + altBlockIndex = 1;
26175 + }
26176 +
26177 + if (!blockIndex) {
26178 + T(YAFFS_TRACE_SCAN,
26179 + (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR)));
26180 + return YAFFS_FAIL;
26181 + }
26182 +
26183 + dev->blocks_in_checkpt = 0;
26184 +
26185 + chunkData = yaffs_get_temp_buffer(dev, __LINE__);
26186 +
26187 + /* Scan all the blocks to determine their state */
26188 + bi = dev->block_info;
26189 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
26190 + yaffs_clear_chunk_bits(dev, blk);
26191 + bi->pages_in_use = 0;
26192 + bi->soft_del_pages = 0;
26193 +
26194 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
26195 +
26196 + bi->block_state = state;
26197 + bi->seq_number = seq_number;
26198 +
26199 + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
26200 + bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
26201 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
26202 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
26203 +
26204 + T(YAFFS_TRACE_SCAN_DEBUG,
26205 + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
26206 + state, seq_number));
26207 +
26208 +
26209 + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
26210 + dev->blocks_in_checkpt++;
26211 +
26212 + } else if (state == YAFFS_BLOCK_STATE_DEAD) {
26213 + T(YAFFS_TRACE_BAD_BLOCKS,
26214 + (TSTR("block %d is bad" TENDSTR), blk));
26215 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
26216 + T(YAFFS_TRACE_SCAN_DEBUG,
26217 + (TSTR("Block empty " TENDSTR)));
26218 + dev->n_erased_blocks++;
26219 + dev->n_free_chunks += dev->param.chunks_per_block;
26220 + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
26221 +
26222 + /* Determine the highest sequence number */
26223 + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
26224 + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
26225 +
26226 + blockIndex[nBlocksToScan].seq = seq_number;
26227 + blockIndex[nBlocksToScan].block = blk;
26228 +
26229 + nBlocksToScan++;
26230 +
26231 + if (seq_number >= dev->seq_number)
26232 + dev->seq_number = seq_number;
26233 + } else {
26234 + /* TODO: Nasty sequence number! */
26235 + T(YAFFS_TRACE_SCAN,
26236 + (TSTR
26237 + ("Block scanning block %d has bad sequence number %d"
26238 + TENDSTR), blk, seq_number));
26239 +
26240 + }
26241 + }
26242 + bi++;
26243 + }
26244 +
26245 + T(YAFFS_TRACE_SCAN,
26246 + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
26247 +
26248 +
26249 +
26250 + YYIELD();
26251 +
26252 + /* Sort the blocks by sequence number*/
26253 + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
26254 +
26255 + YYIELD();
26256 +
26257 + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
26258 +
26259 + /* Now scan the blocks looking at the data. */
26260 + startIterator = 0;
26261 + endIterator = nBlocksToScan - 1;
26262 + T(YAFFS_TRACE_SCAN_DEBUG,
26263 + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
26264 +
26265 + /* For each block.... backwards */
26266 + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
26267 + blockIterator--) {
26268 + /* Cooperative multitasking! This loop can run for so
26269 + long that watchdog timers expire. */
26270 + YYIELD();
26271 +
26272 + /* get the block to scan in the correct order */
26273 + blk = blockIndex[blockIterator].block;
26274 +
26275 + bi = yaffs_get_block_info(dev, blk);
26276 +
26277 +
26278 + state = bi->block_state;
26279 +
26280 + deleted = 0;
26281 +
26282 + /* For each chunk in each block that needs scanning.... */
26283 + foundChunksInBlock = 0;
26284 + for (c = dev->param.chunks_per_block - 1;
26285 + !alloc_failed && c >= 0 &&
26286 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
26287 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
26288 + /* Scan backwards...
26289 + * Read the tags and decide what to do
26290 + */
26291 +
26292 + chunk = blk * dev->param.chunks_per_block + c;
26293 +
26294 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
26295 + &tags);
26296 +
26297 + /* Let's have a good look at this chunk... */
26298 +
26299 + if (!tags.chunk_used) {
26300 + /* An unassigned chunk in the block.
26301 + * If there are used chunks after this one, then
26302 + * it is a chunk that was skipped due to failing the erased
26303 + * check. Just skip it so that it can be deleted.
26304 + * But, more typically, We get here when this is an unallocated
26305 + * chunk and his means that either the block is empty or
26306 + * this is the one being allocated from
26307 + */
26308 +
26309 + if (foundChunksInBlock) {
26310 + /* This is a chunk that was skipped due to failing the erased check */
26311 + } else if (c == 0) {
26312 + /* We're looking at the first chunk in the block so the block is unused */
26313 + state = YAFFS_BLOCK_STATE_EMPTY;
26314 + dev->n_erased_blocks++;
26315 + } else {
26316 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
26317 + state == YAFFS_BLOCK_STATE_ALLOCATING) {
26318 + if (dev->seq_number == bi->seq_number) {
26319 + /* this is the block being allocated from */
26320 +
26321 + T(YAFFS_TRACE_SCAN,
26322 + (TSTR
26323 + (" Allocating from %d %d"
26324 + TENDSTR), blk, c));
26325 +
26326 + state = YAFFS_BLOCK_STATE_ALLOCATING;
26327 + dev->alloc_block = blk;
26328 + dev->alloc_page = c;
26329 + dev->alloc_block_finder = blk;
26330 + } else {
26331 + /* This is a partially written block that is not
26332 + * the current allocation block.
26333 + */
26334 +
26335 + T(YAFFS_TRACE_SCAN,
26336 + (TSTR("Partially written block %d detected" TENDSTR),
26337 + blk));
26338 + }
26339 + }
26340 + }
26341 +
26342 + dev->n_free_chunks++;
26343 +
26344 + } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
26345 + T(YAFFS_TRACE_SCAN,
26346 + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
26347 + blk, c));
26348 +
26349 + dev->n_free_chunks++;
26350 +
26351 + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
26352 + tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
26353 + (tags.chunk_id > 0 && tags.n_bytes > dev->data_bytes_per_chunk) ||
26354 + tags.seq_number != bi->seq_number ) {
26355 + T(YAFFS_TRACE_SCAN,
26356 + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR),
26357 + blk, c,tags.obj_id, tags.chunk_id, tags.n_bytes));
26358 +
26359 + dev->n_free_chunks++;
26360 +
26361 + } else if (tags.chunk_id > 0) {
26362 + /* chunk_id > 0 so it is a data chunk... */
26363 + unsigned int endpos;
26364 + __u32 chunkBase =
26365 + (tags.chunk_id - 1) * dev->data_bytes_per_chunk;
26366 +
26367 + foundChunksInBlock = 1;
26368 +
26369 +
26370 + yaffs_set_chunk_bit(dev, blk, c);
26371 + bi->pages_in_use++;
26372 +
26373 + in = yaffs_find_or_create_by_number(dev,
26374 + tags.
26375 + obj_id,
26376 + YAFFS_OBJECT_TYPE_FILE);
26377 + if (!in) {
26378 + /* Out of memory */
26379 + alloc_failed = 1;
26380 + }
26381 +
26382 + if (in &&
26383 + in->variant_type == YAFFS_OBJECT_TYPE_FILE
26384 + && chunkBase < in->variant.file_variant.shrink_size) {
26385 + /* This has not been invalidated by a resize */
26386 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, -1)) {
26387 + alloc_failed = 1;
26388 + }
26389 +
26390 + /* File size is calculated by looking at the data chunks if we have not
26391 + * seen an object header yet. Stop this practice once we find an object header.
26392 + */
26393 + endpos = chunkBase + tags.n_bytes;
26394 +
26395 + if (!in->valid && /* have not got an object header yet */
26396 + in->variant.file_variant.scanned_size < endpos) {
26397 + in->variant.file_variant.scanned_size = endpos;
26398 + in->variant.file_variant.file_size = endpos;
26399 + }
26400 +
26401 + } else if (in) {
26402 + /* This chunk has been invalidated by a resize, or a past file deletion
26403 + * so delete the chunk*/
26404 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
26405 +
26406 + }
26407 + } else {
26408 + /* chunk_id == 0, so it is an ObjectHeader.
26409 + * Thus, we read in the object header and make the object
26410 + */
26411 + foundChunksInBlock = 1;
26412 +
26413 + yaffs_set_chunk_bit(dev, blk, c);
26414 + bi->pages_in_use++;
26415 +
26416 + oh = NULL;
26417 + in = NULL;
26418 +
26419 + if (tags.extra_available) {
26420 + in = yaffs_find_or_create_by_number(dev,
26421 + tags.obj_id,
26422 + tags.extra_obj_type);
26423 + if (!in)
26424 + alloc_failed = 1;
26425 + }
26426 +
26427 + if (!in ||
26428 + (!in->valid && dev->param.disable_lazy_load) ||
26429 + tags.extra_shadows ||
26430 + (!in->valid &&
26431 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
26432 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
26433 +
26434 + /* If we don't have valid info then we need to read the chunk
26435 + * TODO In future we can probably defer reading the chunk and
26436 + * living with invalid data until needed.
26437 + */
26438 +
26439 + result = yaffs_rd_chunk_tags_nand(dev,
26440 + chunk,
26441 + chunkData,
26442 + NULL);
26443 +
26444 + oh = (yaffs_obj_header *) chunkData;
26445 +
26446 + if (dev->param.inband_tags) {
26447 + /* Fix up the header if they got corrupted by inband tags */
26448 + oh->shadows_obj = oh->inband_shadowed_obj_id;
26449 + oh->is_shrink = oh->inband_is_shrink;
26450 + }
26451 +
26452 + if (!in) {
26453 + in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
26454 + if (!in)
26455 + alloc_failed = 1;
26456 + }
26457 +
26458 + }
26459 +
26460 + if (!in) {
26461 + /* TODO Hoosterman we have a problem! */
26462 + T(YAFFS_TRACE_ERROR,
26463 + (TSTR
26464 + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
26465 + TENDSTR), tags.obj_id, chunk));
26466 + continue;
26467 + }
26468 +
26469 + if (in->valid) {
26470 + /* We have already filled this one.
26471 + * We have a duplicate that will be discarded, but
26472 + * we first have to suck out resize info if it is a file.
26473 + */
26474 +
26475 + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
26476 + ((oh &&
26477 + oh->type == YAFFS_OBJECT_TYPE_FILE) ||
26478 + (tags.extra_available &&
26479 + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) {
26480 + __u32 thisSize =
26481 + (oh) ? oh->file_size : tags.
26482 + extra_length;
26483 + __u32 parent_obj_id =
26484 + (oh) ? oh->
26485 + parent_obj_id : tags.
26486 + extra_parent_id;
26487 +
26488 +
26489 + is_shrink =
26490 + (oh) ? oh->is_shrink : tags.
26491 + extra_is_shrink;
26492 +
26493 + /* If it is deleted (unlinked at start also means deleted)
26494 + * we treat the file size as being zeroed at this point.
26495 + */
26496 + if (parent_obj_id ==
26497 + YAFFS_OBJECTID_DELETED
26498 + || parent_obj_id ==
26499 + YAFFS_OBJECTID_UNLINKED) {
26500 + thisSize = 0;
26501 + is_shrink = 1;
26502 + }
26503 +
26504 + if (is_shrink && in->variant.file_variant.shrink_size > thisSize)
26505 + in->variant.file_variant.shrink_size = thisSize;
26506 +
26507 + if (is_shrink)
26508 + bi->has_shrink_hdr = 1;
26509 +
26510 + }
26511 + /* Use existing - destroy this one. */
26512 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
26513 +
26514 + }
26515 +
26516 + if (!in->valid && in->variant_type !=
26517 + (oh ? oh->type : tags.extra_obj_type))
26518 + T(YAFFS_TRACE_ERROR, (
26519 + TSTR("yaffs tragedy: Bad object type, "
26520 + TCONT("%d != %d, for object %d at chunk ")
26521 + TCONT("%d during scan")
26522 + TENDSTR), oh ?
26523 + oh->type : tags.extra_obj_type,
26524 + in->variant_type, tags.obj_id,
26525 + chunk));
26526 +
26527 + if (!in->valid &&
26528 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
26529 + tags.obj_id ==
26530 + YAFFS_OBJECTID_LOSTNFOUND)) {
26531 + /* We only load some info, don't fiddle with directory structure */
26532 + in->valid = 1;
26533 +
26534 + if (oh) {
26535 +
26536 + in->yst_mode = oh->yst_mode;
26537 +#ifdef CONFIG_YAFFS_WINCE
26538 + in->win_atime[0] = oh->win_atime[0];
26539 + in->win_ctime[0] = oh->win_ctime[0];
26540 + in->win_mtime[0] = oh->win_mtime[0];
26541 + in->win_atime[1] = oh->win_atime[1];
26542 + in->win_ctime[1] = oh->win_ctime[1];
26543 + in->win_mtime[1] = oh->win_mtime[1];
26544 +#else
26545 + in->yst_uid = oh->yst_uid;
26546 + in->yst_gid = oh->yst_gid;
26547 + in->yst_atime = oh->yst_atime;
26548 + in->yst_mtime = oh->yst_mtime;
26549 + in->yst_ctime = oh->yst_ctime;
26550 + in->yst_rdev = oh->yst_rdev;
26551 +
26552 + in->lazy_loaded = 0;
26553 +
26554 +#endif
26555 + } else
26556 + in->lazy_loaded = 1;
26557 +
26558 + in->hdr_chunk = chunk;
26559 +
26560 + } else if (!in->valid) {
26561 + /* we need to load this info */
26562 +
26563 + in->valid = 1;
26564 + in->hdr_chunk = chunk;
26565 +
26566 + if (oh) {
26567 + in->variant_type = oh->type;
26568 +
26569 + in->yst_mode = oh->yst_mode;
26570 +#ifdef CONFIG_YAFFS_WINCE
26571 + in->win_atime[0] = oh->win_atime[0];
26572 + in->win_ctime[0] = oh->win_ctime[0];
26573 + in->win_mtime[0] = oh->win_mtime[0];
26574 + in->win_atime[1] = oh->win_atime[1];
26575 + in->win_ctime[1] = oh->win_ctime[1];
26576 + in->win_mtime[1] = oh->win_mtime[1];
26577 +#else
26578 + in->yst_uid = oh->yst_uid;
26579 + in->yst_gid = oh->yst_gid;
26580 + in->yst_atime = oh->yst_atime;
26581 + in->yst_mtime = oh->yst_mtime;
26582 + in->yst_ctime = oh->yst_ctime;
26583 + in->yst_rdev = oh->yst_rdev;
26584 +#endif
26585 +
26586 + if (oh->shadows_obj > 0)
26587 + yaffs_handle_shadowed_obj(dev,
26588 + oh->
26589 + shadows_obj,
26590 + 1);
26591 +
26592 +
26593 +
26594 + yaffs_set_obj_name_from_oh(in, oh);
26595 + parent =
26596 + yaffs_find_or_create_by_number
26597 + (dev, oh->parent_obj_id,
26598 + YAFFS_OBJECT_TYPE_DIRECTORY);
26599 +
26600 + file_size = oh->file_size;
26601 + is_shrink = oh->is_shrink;
26602 + equiv_id = oh->equiv_id;
26603 +
26604 + } else {
26605 + in->variant_type = tags.extra_obj_type;
26606 + parent =
26607 + yaffs_find_or_create_by_number
26608 + (dev, tags.extra_parent_id,
26609 + YAFFS_OBJECT_TYPE_DIRECTORY);
26610 + file_size = tags.extra_length;
26611 + is_shrink = tags.extra_is_shrink;
26612 + equiv_id = tags.extra_equiv_id;
26613 + in->lazy_loaded = 1;
26614 +
26615 + }
26616 + in->dirty = 0;
26617 +
26618 + if (!parent)
26619 + alloc_failed = 1;
26620 +
26621 + /* directory stuff...
26622 + * hook up to parent
26623 + */
26624 +
26625 + if (parent && parent->variant_type ==
26626 + YAFFS_OBJECT_TYPE_UNKNOWN) {
26627 + /* Set up as a directory */
26628 + parent->variant_type =
26629 + YAFFS_OBJECT_TYPE_DIRECTORY;
26630 + YINIT_LIST_HEAD(&parent->variant.
26631 + dir_variant.
26632 + children);
26633 + } else if (!parent || parent->variant_type !=
26634 + YAFFS_OBJECT_TYPE_DIRECTORY) {
26635 + /* Hoosterman, another problem....
26636 + * We're trying to use a non-directory as a directory
26637 + */
26638 +
26639 + T(YAFFS_TRACE_ERROR,
26640 + (TSTR
26641 + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
26642 + TENDSTR)));
26643 + parent = dev->lost_n_found;
26644 + }
26645 +
26646 + yaffs_add_obj_to_dir(parent, in);
26647 +
26648 + itsUnlinked = (parent == dev->del_dir) ||
26649 + (parent == dev->unlinked_dir);
26650 +
26651 + if (is_shrink) {
26652 + /* Mark the block as having a shrinkHeader */
26653 + bi->has_shrink_hdr = 1;
26654 + }
26655 +
26656 + /* Note re hardlinks.
26657 + * Since we might scan a hardlink before its equivalent object is scanned
26658 + * we put them all in a list.
26659 + * After scanning is complete, we should have all the objects, so we run
26660 + * through this list and fix up all the chains.
26661 + */
26662 +
26663 + switch (in->variant_type) {
26664 + case YAFFS_OBJECT_TYPE_UNKNOWN:
26665 + /* Todo got a problem */
26666 + break;
26667 + case YAFFS_OBJECT_TYPE_FILE:
26668 +
26669 + if (in->variant.file_variant.
26670 + scanned_size < file_size) {
26671 + /* This covers the case where the file size is greater
26672 + * than where the data is
26673 + * This will happen if the file is resized to be larger
26674 + * than its current data extents.
26675 + */
26676 + in->variant.file_variant.file_size = file_size;
26677 + in->variant.file_variant.scanned_size = file_size;
26678 + }
26679 +
26680 + if (in->variant.file_variant.shrink_size > file_size)
26681 + in->variant.file_variant.shrink_size = file_size;
26682 +
26683 +
26684 + break;
26685 + case YAFFS_OBJECT_TYPE_HARDLINK:
26686 + if (!itsUnlinked) {
26687 + in->variant.hardlink_variant.equiv_id =
26688 + equiv_id;
26689 + in->hard_links.next =
26690 + (struct ylist_head *) hard_list;
26691 + hard_list = in;
26692 + }
26693 + break;
26694 + case YAFFS_OBJECT_TYPE_DIRECTORY:
26695 + /* Do nothing */
26696 + break;
26697 + case YAFFS_OBJECT_TYPE_SPECIAL:
26698 + /* Do nothing */
26699 + break;
26700 + case YAFFS_OBJECT_TYPE_SYMLINK:
26701 + if (oh) {
26702 + in->variant.symlink_variant.alias =
26703 + yaffs_clone_str(oh->alias);
26704 + if (!in->variant.symlink_variant.alias)
26705 + alloc_failed = 1;
26706 + }
26707 + break;
26708 + }
26709 +
26710 + }
26711 +
26712 + }
26713 +
26714 + } /* End of scanning for each chunk */
26715 +
26716 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
26717 + /* If we got this far while scanning, then the block is fully allocated. */
26718 + state = YAFFS_BLOCK_STATE_FULL;
26719 + }
26720 +
26721 +
26722 + bi->block_state = state;
26723 +
26724 + /* Now let's see if it was dirty */
26725 + if (bi->pages_in_use == 0 &&
26726 + !bi->has_shrink_hdr &&
26727 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
26728 + yaffs_block_became_dirty(dev, blk);
26729 + }
26730 +
26731 + }
26732 +
26733 + yaffs_skip_rest_of_block(dev);
26734 +
26735 + if (altBlockIndex)
26736 + YFREE_ALT(blockIndex);
26737 + else
26738 + YFREE(blockIndex);
26739 +
26740 + /* Ok, we've done all the scanning.
26741 + * Fix up the hard link chains.
26742 + * We should now have scanned all the objects, now it's time to add these
26743 + * hardlinks.
26744 + */
26745 + yaffs_link_fixup(dev, hard_list);
26746 +
26747 +
26748 + yaffs_release_temp_buffer(dev, chunkData, __LINE__);
26749 +
26750 + if (alloc_failed)
26751 + return YAFFS_FAIL;
26752 +
26753 + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
26754 +
26755 + return YAFFS_OK;
26756 +}
26757 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.h linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.h
26758 --- linux-2.6.36-rc8/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 02:00:00.000000000 +0200
26759 +++ linux-2.6.36-rc8.new/fs/yaffs2/yaffs_yaffs2.h 2010-10-20 13:28:16.067000294 +0300
26760 @@ -0,0 +1,36 @@
26761 +/*
26762 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
26763 + *
26764 + * Copyright (C) 2002-2010 Aleph One Ltd.
26765 + * for Toby Churchill Ltd and Brightstar Engineering
26766 + *
26767 + * Created by Charles Manning <charles@aleph1.co.uk>
26768 + *
26769 + * This program is free software; you can redistribute it and/or modify
26770 + * it under the terms of the GNU General Public License version 2 as
26771 + * published by the Free Software Foundation.
26772 + */
26773 +
26774 +#ifndef __YAFFS_YAFFS2_H__
26775 +#define __YAFFS_YAFFS2_H__
26776 +
26777 +#include "yaffs_guts.h"
26778 +
26779 +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev);
26780 +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev);
26781 +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi);
26782 +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi);
26783 +int yaffs_block_ok_for_gc(yaffs_dev_t *dev, yaffs_block_info_t *bi);
26784 +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev);
26785 +int yaffs2_checkpt_required(yaffs_dev_t *dev);
26786 +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev);
26787 +
26788 +
26789 +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev);
26790 +int yaffs2_checkpt_save(yaffs_dev_t *dev);
26791 +int yaffs2_checkpt_restore(yaffs_dev_t *dev);
26792 +
26793 +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size);
26794 +int yaffs2_scan_backwards(yaffs_dev_t *dev);
26795 +
26796 +#endif
26797 diff -Nrup linux-2.6.36-rc8/fs/yaffs2/yportenv.h linux-2.6.36-rc8.new/fs/yaffs2/yportenv.h
26798 --- linux-2.6.36-rc8/fs/yaffs2/yportenv.h 2010-10-20 13:17:58.988000294 +0300
26799 +++ linux-2.6.36-rc8.new/fs/yaffs2/yportenv.h 2010-10-20 13:28:16.067000294 +0300
26800 @@ -1,7 +1,7 @@
26801 /*
26802 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
26803 *
26804 - * Copyright (C) 2002-2007 Aleph One Ltd.
26805 + * Copyright (C) 2002-2010 Aleph One Ltd.
26806 * for Toby Churchill Ltd and Brightstar Engineering
26807 *
26808 * Created by Charles Manning <charles@aleph1.co.uk>
26809 @@ -41,12 +41,14 @@
26810 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
26811 #include <linux/config.h>
26812 #endif
26813 +
26814 #include <linux/kernel.h>
26815 #include <linux/mm.h>
26816 #include <linux/sched.h>
26817 #include <linux/string.h>
26818 #include <linux/slab.h>
26819 #include <linux/vmalloc.h>
26820 +#include <linux/xattr.h>
26821
26822 #define YCHAR char
26823 #define YUCHAR unsigned char
26824 @@ -55,11 +57,11 @@
26825 #define yaffs_strcpy(a, b) strcpy(a, b)
26826 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
26827 #define yaffs_strncmp(a, b, c) strncmp(a, b, c)
26828 -#define yaffs_strlen(s) strlen(s)
26829 +#define yaffs_strnlen(s,m) strnlen(s,m)
26830 #define yaffs_sprintf sprintf
26831 #define yaffs_toupper(a) toupper(a)
26832
26833 -#define Y_INLINE inline
26834 +#define Y_INLINE __inline__
26835
26836 #define YAFFS_LOSTNFOUND_NAME "lost+found"
26837 #define YAFFS_LOSTNFOUND_PREFIX "obj"
26838 @@ -71,11 +73,11 @@
26839 #define YFREE_ALT(x) vfree(x)
26840 #define YMALLOC_DMA(x) YMALLOC(x)
26841
26842 -/* KR - added for use in scan so processes aren't blocked indefinitely. */
26843 #define YYIELD() schedule()
26844 +#define Y_DUMP_STACK() dump_stack()
26845
26846 -#define YAFFS_ROOT_MODE 0666
26847 -#define YAFFS_LOSTNFOUND_MODE 0666
26848 +#define YAFFS_ROOT_MODE 0755
26849 +#define YAFFS_LOSTNFOUND_MODE 0700
26850
26851 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
26852 #define Y_CURRENT_TIME CURRENT_TIME.tv_sec
26853 @@ -85,19 +87,14 @@
26854 #define Y_TIME_CONVERT(x) (x)
26855 #endif
26856
26857 -#define yaffs_SumCompare(x, y) ((x) == (y))
26858 +#define yaffs_sum_cmp(x, y) ((x) == (y))
26859 #define yaffs_strcmp(a, b) strcmp(a, b)
26860
26861 #define TENDSTR "\n"
26862 -#define TSTR(x) KERN_WARNING x
26863 +#define TSTR(x) KERN_DEBUG x
26864 #define TCONT(x) x
26865 #define TOUT(p) printk p
26866
26867 -#define yaffs_trace(mask, fmt, args...) \
26868 - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
26869 - printk(KERN_WARNING "yaffs: " fmt, ## args); \
26870 - } while (0)
26871 -
26872 #define compile_time_assertion(assertion) \
26873 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
26874
26875 @@ -116,7 +113,6 @@
26876 #include "stdio.h"
26877 #include "string.h"
26878
26879 -#include "devextras.h"
26880
26881 #define YMALLOC(x) malloc(x)
26882 #define YFREE(x) free(x)
26883 @@ -129,7 +125,7 @@
26884 #define yaffs_strcat(a, b) strcat(a, b)
26885 #define yaffs_strcpy(a, b) strcpy(a, b)
26886 #define yaffs_strncpy(a, b, c) strncpy(a, b, c)
26887 -#define yaffs_strlen(s) strlen(s)
26888 +#define yaffs_strnlen(s,m) strnlen(s,m)
26889 #define yaffs_sprintf sprintf
26890 #define yaffs_toupper(a) toupper(a)
26891
26892 @@ -146,10 +142,10 @@
26893 #define YAFFS_LOSTNFOUND_PREFIX "obj"
26894 /* #define YPRINTF(x) printf x */
26895
26896 -#define YAFFS_ROOT_MODE 0666
26897 -#define YAFFS_LOSTNFOUND_MODE 0666
26898 +#define YAFFS_ROOT_MODE 0755
26899 +#define YAFFS_LOSTNFOUND_MODE 0700
26900
26901 -#define yaffs_SumCompare(x, y) ((x) == (y))
26902 +#define yaffs_sum_cmp(x, y) ((x) == (y))
26903 #define yaffs_strcmp(a, b) strcmp(a, b)
26904
26905 #else
26906 @@ -158,46 +154,180 @@
26907
26908 #endif
26909
26910 -/* see yaffs_fs.c */
26911 -extern unsigned int yaffs_traceMask;
26912 -extern unsigned int yaffs_wr_attempts;
26913 +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
26914
26915 -/*
26916 - * Tracing flags.
26917 - * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
26918 - */
26919 +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
26920 +
26921 +#ifndef O_RDONLY
26922 +#define O_RDONLY 00
26923 +#endif
26924 +
26925 +#ifndef O_WRONLY
26926 +#define O_WRONLY 01
26927 +#endif
26928 +
26929 +#ifndef O_RDWR
26930 +#define O_RDWR 02
26931 +#endif
26932 +
26933 +#ifndef O_CREAT
26934 +#define O_CREAT 0100
26935 +#endif
26936 +
26937 +#ifndef O_EXCL
26938 +#define O_EXCL 0200
26939 +#endif
26940 +
26941 +#ifndef O_TRUNC
26942 +#define O_TRUNC 01000
26943 +#endif
26944 +
26945 +#ifndef O_APPEND
26946 +#define O_APPEND 02000
26947 +#endif
26948 +
26949 +#ifndef SEEK_SET
26950 +#define SEEK_SET 0
26951 +#endif
26952 +
26953 +#ifndef SEEK_CUR
26954 +#define SEEK_CUR 1
26955 +#endif
26956 +
26957 +#ifndef SEEK_END
26958 +#define SEEK_END 2
26959 +#endif
26960 +
26961 +#ifndef EBUSY
26962 +#define EBUSY 16
26963 +#endif
26964 +
26965 +#ifndef ENODEV
26966 +#define ENODEV 19
26967 +#endif
26968 +
26969 +#ifndef EINVAL
26970 +#define EINVAL 22
26971 +#endif
26972 +
26973 +#ifndef EBADF
26974 +#define EBADF 9
26975 +#endif
26976 +
26977 +#ifndef EACCES
26978 +#define EACCES 13
26979 +#endif
26980 +
26981 +#ifndef EXDEV
26982 +#define EXDEV 18
26983 +#endif
26984 +
26985 +#ifndef ENOENT
26986 +#define ENOENT 2
26987 +#endif
26988 +
26989 +#ifndef ENOSPC
26990 +#define ENOSPC 28
26991 +#endif
26992 +
26993 +#ifndef ERANGE
26994 +#define ERANGE 34
26995 +#endif
26996 +
26997 +#ifndef ENODATA
26998 +#define ENODATA 61
26999 +#endif
27000 +
27001 +#ifndef ENOTEMPTY
27002 +#define ENOTEMPTY 39
27003 +#endif
27004 +
27005 +#ifndef ENAMETOOLONG
27006 +#define ENAMETOOLONG 36
27007 +#endif
27008 +
27009 +#ifndef ENOMEM
27010 +#define ENOMEM 12
27011 +#endif
27012 +
27013 +#ifndef EEXIST
27014 +#define EEXIST 17
27015 +#endif
27016 +
27017 +#ifndef ENOTDIR
27018 +#define ENOTDIR 20
27019 +#endif
27020 +
27021 +#ifndef EISDIR
27022 +#define EISDIR 21
27023 +#endif
27024 +
27025 +
27026 +// Mode flags
27027 +
27028 +#ifndef S_IFMT
27029 +#define S_IFMT 0170000
27030 +#endif
27031 +
27032 +#ifndef S_IFLNK
27033 +#define S_IFLNK 0120000
27034 +#endif
27035
27036 -#define YAFFS_TRACE_OS 0x00000002
27037 -#define YAFFS_TRACE_ALLOCATE 0x00000004
27038 -#define YAFFS_TRACE_SCAN 0x00000008
27039 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
27040 -#define YAFFS_TRACE_ERASE 0x00000020
27041 -#define YAFFS_TRACE_GC 0x00000040
27042 -#define YAFFS_TRACE_WRITE 0x00000080
27043 -#define YAFFS_TRACE_TRACING 0x00000100
27044 -#define YAFFS_TRACE_DELETION 0x00000200
27045 -#define YAFFS_TRACE_BUFFERS 0x00000400
27046 -#define YAFFS_TRACE_NANDACCESS 0x00000800
27047 -#define YAFFS_TRACE_GC_DETAIL 0x00001000
27048 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
27049 -#define YAFFS_TRACE_MTD 0x00004000
27050 -#define YAFFS_TRACE_CHECKPOINT 0x00008000
27051 -
27052 -#define YAFFS_TRACE_VERIFY 0x00010000
27053 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000
27054 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000
27055 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
27056 -
27057 -
27058 -#define YAFFS_TRACE_ERROR 0x40000000
27059 -#define YAFFS_TRACE_BUG 0x80000000
27060 -#define YAFFS_TRACE_ALWAYS 0xF0000000
27061 +#ifndef S_IFDIR
27062 +#define S_IFDIR 0040000
27063 +#endif
27064 +
27065 +#ifndef S_IFREG
27066 +#define S_IFREG 0100000
27067 +#endif
27068
27069 +#ifndef S_IREAD
27070 +#define S_IREAD 0000400
27071 +#endif
27072 +
27073 +#ifndef S_IWRITE
27074 +#define S_IWRITE 0000200
27075 +#endif
27076
27077 -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
27078 +#ifndef S_IEXEC
27079 +#define S_IEXEC 0000100
27080 +#endif
27081 +
27082 +#ifndef XATTR_CREATE
27083 +#define XATTR_CREATE 1
27084 +#endif
27085 +
27086 +#ifndef XATTR_REPLACE
27087 +#define XATTR_REPLACE 2
27088 +#endif
27089 +
27090 +#ifndef R_OK
27091 +#define R_OK 4
27092 +#define W_OK 2
27093 +#define X_OK 1
27094 +#define F_OK 0
27095 +#endif
27096 +
27097 +#else
27098 +#include <errno.h>
27099 +#include <sys/stat.h>
27100 +#include <fcntl.h>
27101 +#endif
27102 +
27103 +#endif
27104 +
27105 +#ifndef Y_DUMP_STACK
27106 +#define Y_DUMP_STACK() do { } while (0)
27107 +#endif
27108
27109 #ifndef YBUG
27110 -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
27111 +#define YBUG() do {\
27112 + T(YAFFS_TRACE_BUG,\
27113 + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
27114 + __LINE__));\
27115 + Y_DUMP_STACK();\
27116 +} while (0)
27117 #endif
27118
27119 +
27120 #endif