Implement UBIFS rootfs support
[openadk.git] / target / linux / patches / 3.4.113 / yaffs2.patch
blob44c95915f5d6c248ed0a290740d5f7d4f2fbe1a6
1 diff -Nur linux-3.4.90.orig/fs/Kconfig linux-3.4.90/fs/Kconfig
2 --- linux-3.4.90.orig/fs/Kconfig 2014-05-13 14:11:45.000000000 +0200
3 +++ linux-3.4.90/fs/Kconfig 2014-05-17 15:08:09.000000000 +0200
4 @@ -203,6 +203,7 @@
5 source "fs/befs/Kconfig"
6 source "fs/bfs/Kconfig"
7 source "fs/efs/Kconfig"
8 +source "fs/yaffs2/Kconfig"
9 source "fs/jffs2/Kconfig"
10 # UBIFS File system configuration
11 source "fs/ubifs/Kconfig"
12 diff -Nur linux-3.4.90.orig/fs/Makefile linux-3.4.90/fs/Makefile
13 --- linux-3.4.90.orig/fs/Makefile 2014-05-13 14:11:45.000000000 +0200
14 +++ linux-3.4.90/fs/Makefile 2014-05-17 15:09:05.000000000 +0200
15 @@ -97,6 +97,7 @@
16 obj-$(CONFIG_UFS_FS) += ufs/
17 obj-$(CONFIG_EFS_FS) += efs/
18 obj-$(CONFIG_JFFS2_FS) += jffs2/
19 +obj-$(CONFIG_YAFFS_FS) += yaffs2/
20 obj-$(CONFIG_LOGFS) += logfs/
21 obj-$(CONFIG_UBIFS_FS) += ubifs/
22 obj-$(CONFIG_AFFS_FS) += affs/
23 diff -Nur linux-3.4.90.orig/fs/yaffs2/Kconfig linux-3.4.90/fs/yaffs2/Kconfig
24 --- linux-3.4.90.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
25 +++ linux-3.4.90/fs/yaffs2/Kconfig 2014-05-17 15:08:09.000000000 +0200
26 @@ -0,0 +1,171 @@
28 +# yaffs file system configurations
31 +config YAFFS_FS
32 + tristate "yaffs2 file system support"
33 + default n
34 + depends on MTD_BLOCK
35 + select YAFFS_YAFFS1
36 + select YAFFS_YAFFS2
37 + help
38 + yaffs2, or Yet Another Flash File System, is a file system
39 + optimised for NAND Flash chips.
41 + To compile the yaffs2 file system support as a module, choose M
42 + here: the module will be called yaffs2.
44 + If unsure, say N.
46 + Further information on yaffs2 is available at
47 + <http://www.aleph1.co.uk/yaffs/>.
49 +config YAFFS_YAFFS1
50 + bool "512 byte / page devices"
51 + depends on YAFFS_FS
52 + default y
53 + help
54 + Enable yaffs1 support -- yaffs for 512 byte / page devices
56 + Not needed for 2K-page devices.
58 + If unsure, say Y.
60 +config YAFFS_9BYTE_TAGS
61 + bool "Use older-style on-NAND data format with pageStatus byte"
62 + depends on YAFFS_YAFFS1
63 + default n
64 + help
66 + Older-style on-NAND data format has a "pageStatus" byte to record
67 + chunk/page state. This byte is zero when the page is discarded.
68 + Choose this option if you have existing on-NAND data using this
69 + format that you need to continue to support. New data written
70 + also uses the older-style format. Note: Use of this option
71 + generally requires that MTD's oob layout be adjusted to use the
72 + older-style format. See notes on tags formats and MTD versions
73 + in yaffs_mtdif1.c.
75 + If unsure, say N.
77 +config YAFFS_DOES_ECC
78 + bool "Lets yaffs do its own ECC"
79 + depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
80 + default n
81 + help
82 + This enables yaffs to use its own ECC functions instead of using
83 + the ones from the generic MTD-NAND driver.
85 + If unsure, say N.
87 +config YAFFS_ECC_WRONG_ORDER
88 + bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
89 + depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
90 + default n
91 + help
92 + This makes yaffs_ecc.c use the same ecc byte order as Steven
93 + Hill's nand_ecc.c. If not set, then you get the same ecc byte
94 + order as SmartMedia.
96 + If unsure, say N.
98 +config YAFFS_YAFFS2
99 + bool "2048 byte (or larger) / page devices"
100 + depends on YAFFS_FS
101 + default y
102 + help
103 + Enable yaffs2 support -- yaffs for >= 2K bytes per page devices
105 + If unsure, say Y.
107 +config YAFFS_AUTO_YAFFS2
108 + bool "Autoselect yaffs2 format"
109 + depends on YAFFS_YAFFS2
110 + default y
111 + help
112 + Without this, you need to explicitely use yaffs2 as the file
113 + system type. With this, you can say "yaffs" and yaffs or yaffs2
114 + will be used depending on the device page size (yaffs on
115 + 512-byte page devices, yaffs2 on 2K page devices).
117 + If unsure, say Y.
119 +config YAFFS_DISABLE_TAGS_ECC
120 + bool "Disable yaffs from doing ECC on tags by default"
121 + depends on YAFFS_FS && YAFFS_YAFFS2
122 + default n
123 + help
124 + This defaults yaffs to using its own ECC calculations on tags instead of
125 + just relying on the MTD.
126 + This behavior can also be overridden with tags_ecc_on and
127 + tags_ecc_off mount options.
129 + If unsure, say N.
131 +config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
132 + bool "Force chunk erase check"
133 + depends on YAFFS_FS
134 + default n
135 + help
136 + Normally yaffs only checks chunks before writing until an erased
137 + chunk is found. This helps to detect any partially written
138 + chunks that might have happened due to power loss.
140 + Enabling this forces on the test that chunks are erased in flash
141 + before writing to them. This takes more time but is potentially
142 + a bit more secure.
144 + Suggest setting Y during development and ironing out driver
145 + issues etc. Suggest setting to N if you want faster writing.
147 + If unsure, say Y.
149 +config YAFFS_EMPTY_LOST_AND_FOUND
150 + bool "Empty lost and found on boot"
151 + depends on YAFFS_FS
152 + default n
153 + help
154 + If this is enabled then the contents of lost and found is
155 + automatically dumped at mount.
157 + If unsure, say N.
159 +config YAFFS_DISABLE_BLOCK_REFRESHING
160 + bool "Disable yaffs2 block refreshing"
161 + depends on YAFFS_FS
162 + default n
163 + help
164 + If this is set, then block refreshing is disabled.
165 + Block refreshing infrequently refreshes the oldest block in
166 + a yaffs2 file system. This mechanism helps to refresh flash to
167 + mitigate against data loss. This is particularly useful for MLC.
169 + If unsure, say N.
171 +config YAFFS_DISABLE_BACKGROUND
172 + bool "Disable yaffs2 background processing"
173 + depends on YAFFS_FS
174 + default n
175 + help
176 + If this is set, then background processing is disabled.
177 + Background processing makes many foreground activities faster.
179 + If unsure, say N.
181 +config YAFFS_DISABLE_BAD_BLOCK_MARKING
182 + bool "Disable yaffs2 bad block marking"
183 + depends on YAFFS_FS
184 + default n
185 + help
186 + Useful during early flash bring up to prevent problems causing
187 + lots of bad block marking.
189 + If unsure, say N.
191 +config YAFFS_XATTR
192 + bool "Enable yaffs2 xattr support"
193 + depends on YAFFS_FS
194 + default y
195 + help
196 + If this is set then yaffs2 will provide xattr support.
197 + If unsure, say Y.
198 diff -Nur linux-3.4.90.orig/fs/yaffs2/Makefile linux-3.4.90/fs/yaffs2/Makefile
199 --- linux-3.4.90.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
200 +++ linux-3.4.90/fs/yaffs2/Makefile 2014-05-17 15:08:09.000000000 +0200
201 @@ -0,0 +1,18 @@
203 +# Makefile for the linux YAFFS filesystem routines.
206 +obj-$(CONFIG_YAFFS_FS) += yaffs.o
208 +yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
209 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
210 +yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
211 +yaffs-y += yaffs_mtdif.o
212 +yaffs-y += yaffs_nameval.o yaffs_attribs.o
213 +yaffs-y += yaffs_allocator.o
214 +yaffs-y += yaffs_yaffs1.o
215 +yaffs-y += yaffs_yaffs2.o
216 +yaffs-y += yaffs_bitmap.o
217 +yaffs-y += yaffs_summary.o
218 +yaffs-y += yaffs_verify.o
220 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.c linux-3.4.90/fs/yaffs2/yaffs_allocator.c
221 --- linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
222 +++ linux-3.4.90/fs/yaffs2/yaffs_allocator.c 2014-05-17 15:08:09.000000000 +0200
223 @@ -0,0 +1,357 @@
225 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
227 + * Copyright (C) 2002-2011 Aleph One Ltd.
228 + * for Toby Churchill Ltd and Brightstar Engineering
230 + * Created by Charles Manning <charles@aleph1.co.uk>
232 + * This program is free software; you can redistribute it and/or modify
233 + * it under the terms of the GNU General Public License version 2 as
234 + * published by the Free Software Foundation.
235 + */
237 +#include "yaffs_allocator.h"
238 +#include "yaffs_guts.h"
239 +#include "yaffs_trace.h"
240 +#include "yportenv.h"
243 + * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
244 + * of approx 100 objects that are themn allocated singly.
245 + * This is basically a simplified slab allocator.
247 + * We don't use the Linux slab allocator because slab does not allow
248 + * us to dump all the objects in one hit when we do a umount and tear
249 + * down all the tnodes and objects. slab requires that we first free
250 + * the individual objects.
252 + * Once yaffs has been mainlined I shall try to motivate for a change
253 + * to slab to provide the extra features we need here.
254 + */
256 +struct yaffs_tnode_list {
257 + struct yaffs_tnode_list *next;
258 + struct yaffs_tnode *tnodes;
261 +struct yaffs_obj_list {
262 + struct yaffs_obj_list *next;
263 + struct yaffs_obj *objects;
266 +struct yaffs_allocator {
267 + int n_tnodes_created;
268 + struct yaffs_tnode *free_tnodes;
269 + int n_free_tnodes;
270 + struct yaffs_tnode_list *alloc_tnode_list;
272 + int n_obj_created;
273 + struct list_head free_objs;
274 + int n_free_objects;
276 + struct yaffs_obj_list *allocated_obj_list;
279 +static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
281 + struct yaffs_allocator *allocator =
282 + (struct yaffs_allocator *)dev->allocator;
283 + struct yaffs_tnode_list *tmp;
285 + if (!allocator) {
286 + BUG();
287 + return;
290 + while (allocator->alloc_tnode_list) {
291 + tmp = allocator->alloc_tnode_list->next;
293 + kfree(allocator->alloc_tnode_list->tnodes);
294 + kfree(allocator->alloc_tnode_list);
295 + allocator->alloc_tnode_list = tmp;
298 + allocator->free_tnodes = NULL;
299 + allocator->n_free_tnodes = 0;
300 + allocator->n_tnodes_created = 0;
303 +static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
305 + struct yaffs_allocator *allocator = dev->allocator;
307 + if (!allocator) {
308 + BUG();
309 + return;
312 + allocator->alloc_tnode_list = NULL;
313 + allocator->free_tnodes = NULL;
314 + allocator->n_free_tnodes = 0;
315 + allocator->n_tnodes_created = 0;
318 +static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
320 + struct yaffs_allocator *allocator =
321 + (struct yaffs_allocator *)dev->allocator;
322 + int i;
323 + struct yaffs_tnode *new_tnodes;
324 + u8 *mem;
325 + struct yaffs_tnode *curr;
326 + struct yaffs_tnode *next;
327 + struct yaffs_tnode_list *tnl;
329 + if (!allocator) {
330 + BUG();
331 + return YAFFS_FAIL;
334 + if (n_tnodes < 1)
335 + return YAFFS_OK;
337 + /* make these things */
338 + new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
339 + mem = (u8 *) new_tnodes;
341 + if (!new_tnodes) {
342 + yaffs_trace(YAFFS_TRACE_ERROR,
343 + "yaffs: Could not allocate Tnodes");
344 + return YAFFS_FAIL;
347 + /* New hookup for wide tnodes */
348 + for (i = 0; i < n_tnodes - 1; i++) {
349 + curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
350 + next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
351 + curr->internal[0] = next;
354 + curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
355 + curr->internal[0] = allocator->free_tnodes;
356 + allocator->free_tnodes = (struct yaffs_tnode *)mem;
358 + allocator->n_free_tnodes += n_tnodes;
359 + allocator->n_tnodes_created += n_tnodes;
361 + /* Now add this bunch of tnodes to a list for freeing up.
362 + * NB If we can't add this to the management list it isn't fatal
363 + * but it just means we can't free this bunch of tnodes later.
364 + */
365 + tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
366 + if (!tnl) {
367 + yaffs_trace(YAFFS_TRACE_ERROR,
368 + "Could not add tnodes to management list");
369 + return YAFFS_FAIL;
370 + } else {
371 + tnl->tnodes = new_tnodes;
372 + tnl->next = allocator->alloc_tnode_list;
373 + allocator->alloc_tnode_list = tnl;
376 + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
378 + return YAFFS_OK;
381 +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
383 + struct yaffs_allocator *allocator =
384 + (struct yaffs_allocator *)dev->allocator;
385 + struct yaffs_tnode *tn = NULL;
387 + if (!allocator) {
388 + BUG();
389 + return NULL;
392 + /* If there are none left make more */
393 + if (!allocator->free_tnodes)
394 + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
396 + if (allocator->free_tnodes) {
397 + tn = allocator->free_tnodes;
398 + allocator->free_tnodes = allocator->free_tnodes->internal[0];
399 + allocator->n_free_tnodes--;
402 + return tn;
405 +/* FreeTnode frees up a tnode and puts it back on the free list */
406 +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
408 + struct yaffs_allocator *allocator = dev->allocator;
410 + if (!allocator) {
411 + BUG();
412 + return;
415 + if (tn) {
416 + tn->internal[0] = allocator->free_tnodes;
417 + allocator->free_tnodes = tn;
418 + allocator->n_free_tnodes++;
420 + dev->checkpoint_blocks_required = 0; /* force recalculation */
423 +/*--------------- yaffs_obj alloaction ------------------------
425 + * Free yaffs_objs are stored in a list using obj->siblings.
426 + * The blocks of allocated objects are stored in a linked list.
427 + */
429 +static void yaffs_init_raw_objs(struct yaffs_dev *dev)
431 + struct yaffs_allocator *allocator = dev->allocator;
433 + if (!allocator) {
434 + BUG();
435 + return;
438 + allocator->allocated_obj_list = NULL;
439 + INIT_LIST_HEAD(&allocator->free_objs);
440 + allocator->n_free_objects = 0;
443 +static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
445 + struct yaffs_allocator *allocator = dev->allocator;
446 + struct yaffs_obj_list *tmp;
448 + if (!allocator) {
449 + BUG();
450 + return;
453 + while (allocator->allocated_obj_list) {
454 + tmp = allocator->allocated_obj_list->next;
455 + kfree(allocator->allocated_obj_list->objects);
456 + kfree(allocator->allocated_obj_list);
457 + allocator->allocated_obj_list = tmp;
460 + INIT_LIST_HEAD(&allocator->free_objs);
461 + allocator->n_free_objects = 0;
462 + allocator->n_obj_created = 0;
465 +static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
467 + struct yaffs_allocator *allocator = dev->allocator;
468 + int i;
469 + struct yaffs_obj *new_objs;
470 + struct yaffs_obj_list *list;
472 + if (!allocator) {
473 + BUG();
474 + return YAFFS_FAIL;
477 + if (n_obj < 1)
478 + return YAFFS_OK;
480 + /* make these things */
481 + new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
482 + list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
484 + if (!new_objs || !list) {
485 + kfree(new_objs);
486 + new_objs = NULL;
487 + kfree(list);
488 + list = NULL;
489 + yaffs_trace(YAFFS_TRACE_ALLOCATE,
490 + "Could not allocate more objects");
491 + return YAFFS_FAIL;
494 + /* Hook them into the free list */
495 + for (i = 0; i < n_obj; i++)
496 + list_add(&new_objs[i].siblings, &allocator->free_objs);
498 + allocator->n_free_objects += n_obj;
499 + allocator->n_obj_created += n_obj;
501 + /* Now add this bunch of Objects to a list for freeing up. */
503 + list->objects = new_objs;
504 + list->next = allocator->allocated_obj_list;
505 + allocator->allocated_obj_list = list;
507 + return YAFFS_OK;
510 +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
512 + struct yaffs_obj *obj = NULL;
513 + struct list_head *lh;
514 + struct yaffs_allocator *allocator = dev->allocator;
516 + if (!allocator) {
517 + BUG();
518 + return obj;
521 + /* If there are none left make more */
522 + if (list_empty(&allocator->free_objs))
523 + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
525 + if (!list_empty(&allocator->free_objs)) {
526 + lh = allocator->free_objs.next;
527 + obj = list_entry(lh, struct yaffs_obj, siblings);
528 + list_del_init(lh);
529 + allocator->n_free_objects--;
532 + return obj;
535 +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
538 + struct yaffs_allocator *allocator = dev->allocator;
540 + if (!allocator) {
541 + BUG();
542 + return;
545 + /* Link into the free list. */
546 + list_add(&obj->siblings, &allocator->free_objs);
547 + allocator->n_free_objects++;
550 +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
553 + if (!dev->allocator) {
554 + BUG();
555 + return;
558 + yaffs_deinit_raw_tnodes(dev);
559 + yaffs_deinit_raw_objs(dev);
560 + kfree(dev->allocator);
561 + dev->allocator = NULL;
564 +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
566 + struct yaffs_allocator *allocator;
568 + if (dev->allocator) {
569 + BUG();
570 + return;
573 + allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
574 + if (allocator) {
575 + dev->allocator = allocator;
576 + yaffs_init_raw_tnodes(dev);
577 + yaffs_init_raw_objs(dev);
581 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.h linux-3.4.90/fs/yaffs2/yaffs_allocator.h
582 --- linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
583 +++ linux-3.4.90/fs/yaffs2/yaffs_allocator.h 2014-05-17 15:08:09.000000000 +0200
584 @@ -0,0 +1,30 @@
586 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
588 + * Copyright (C) 2002-2011 Aleph One Ltd.
589 + * for Toby Churchill Ltd and Brightstar Engineering
591 + * Created by Charles Manning <charles@aleph1.co.uk>
593 + * This program is free software; you can redistribute it and/or modify
594 + * it under the terms of the GNU Lesser General Public License version 2.1 as
595 + * published by the Free Software Foundation.
597 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
598 + */
600 +#ifndef __YAFFS_ALLOCATOR_H__
601 +#define __YAFFS_ALLOCATOR_H__
603 +#include "yaffs_guts.h"
605 +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
606 +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
608 +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
609 +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
611 +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
612 +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
614 +#endif
615 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.c linux-3.4.90/fs/yaffs2/yaffs_attribs.c
616 --- linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
617 +++ linux-3.4.90/fs/yaffs2/yaffs_attribs.c 2014-05-17 16:37:59.000000000 +0200
618 @@ -0,0 +1,166 @@
620 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
622 + * Copyright (C) 2002-2011 Aleph One Ltd.
623 + * for Toby Churchill Ltd and Brightstar Engineering
625 + * Created by Charles Manning <charles@aleph1.co.uk>
627 + * This program is free software; you can redistribute it and/or modify
628 + * it under the terms of the GNU General Public License version 2 as
629 + * published by the Free Software Foundation.
630 + */
632 +#include "yaffs_guts.h"
633 +#include "yaffs_attribs.h"
635 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
636 +static inline uid_t ia_uid_read(const struct iattr *iattr)
638 + return from_kuid(&init_user_ns, iattr->ia_uid);
641 +static inline gid_t ia_gid_read(const struct iattr *iattr)
643 + return from_kgid(&init_user_ns, iattr->ia_gid);
646 +static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
648 + iattr->ia_uid = make_kuid(&init_user_ns, uid);
651 +static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
653 + iattr->ia_gid = make_kgid(&init_user_ns, gid);
655 +#else
656 +static inline uid_t ia_uid_read(const struct iattr *iattr)
658 + return iattr->ia_uid;
661 +static inline gid_t ia_gid_read(const struct iattr *iattr)
663 + return iattr->ia_gid;
666 +static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
668 + iattr->ia_uid = uid;
671 +static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
673 + iattr->ia_gid = gid;
675 +#endif
677 +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
679 + obj->yst_uid = oh->yst_uid;
680 + obj->yst_gid = oh->yst_gid;
681 + obj->yst_atime = oh->yst_atime;
682 + obj->yst_mtime = oh->yst_mtime;
683 + obj->yst_ctime = oh->yst_ctime;
684 + obj->yst_rdev = oh->yst_rdev;
687 +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
689 + oh->yst_uid = obj->yst_uid;
690 + oh->yst_gid = obj->yst_gid;
691 + oh->yst_atime = obj->yst_atime;
692 + oh->yst_mtime = obj->yst_mtime;
693 + oh->yst_ctime = obj->yst_ctime;
694 + oh->yst_rdev = obj->yst_rdev;
698 +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
700 + obj->yst_mtime = Y_CURRENT_TIME;
701 + if (do_a)
702 + obj->yst_atime = obj->yst_mtime;
703 + if (do_c)
704 + obj->yst_ctime = obj->yst_mtime;
707 +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
709 + yaffs_load_current_time(obj, 1, 1);
710 + obj->yst_rdev = rdev;
711 + obj->yst_uid = uid;
712 + obj->yst_gid = gid;
715 +static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
717 + YCHAR *alias = NULL;
718 + obj = yaffs_get_equivalent_obj(obj);
720 + switch (obj->variant_type) {
721 + case YAFFS_OBJECT_TYPE_FILE:
722 + return obj->variant.file_variant.file_size;
723 + case YAFFS_OBJECT_TYPE_SYMLINK:
724 + alias = obj->variant.symlink_variant.alias;
725 + if (!alias)
726 + return 0;
727 + return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
728 + default:
729 + return 0;
733 +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
735 + unsigned int valid = attr->ia_valid;
737 + if (valid & ATTR_MODE)
738 + obj->yst_mode = attr->ia_mode;
739 + if (valid & ATTR_UID)
740 + obj->yst_uid = ia_uid_read(attr);
741 + if (valid & ATTR_GID)
742 + obj->yst_gid = ia_gid_read(attr);
744 + if (valid & ATTR_ATIME)
745 + obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
746 + if (valid & ATTR_CTIME)
747 + obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
748 + if (valid & ATTR_MTIME)
749 + obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
751 + if (valid & ATTR_SIZE)
752 + yaffs_resize_file(obj, attr->ia_size);
754 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
756 + return YAFFS_OK;
760 +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
762 + unsigned int valid = 0;
764 + attr->ia_mode = obj->yst_mode;
765 + valid |= ATTR_MODE;
766 + ia_uid_write(attr, obj->yst_uid);
767 + valid |= ATTR_UID;
768 + ia_gid_write(attr, obj->yst_gid);
769 + valid |= ATTR_GID;
771 + Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
772 + valid |= ATTR_ATIME;
773 + Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
774 + valid |= ATTR_CTIME;
775 + Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
776 + valid |= ATTR_MTIME;
778 + attr->ia_size = yaffs_get_file_size(obj);
779 + valid |= ATTR_SIZE;
781 + attr->ia_valid = valid;
783 + return YAFFS_OK;
785 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.h linux-3.4.90/fs/yaffs2/yaffs_attribs.h
786 --- linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
787 +++ linux-3.4.90/fs/yaffs2/yaffs_attribs.h 2014-05-17 15:08:09.000000000 +0200
788 @@ -0,0 +1,28 @@
790 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
792 + * Copyright (C) 2002-2011 Aleph One Ltd.
793 + * for Toby Churchill Ltd and Brightstar Engineering
795 + * Created by Charles Manning <charles@aleph1.co.uk>
797 + * This program is free software; you can redistribute it and/or modify
798 + * it under the terms of the GNU Lesser General Public License version 2.1 as
799 + * published by the Free Software Foundation.
801 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
802 + */
804 +#ifndef __YAFFS_ATTRIBS_H__
805 +#define __YAFFS_ATTRIBS_H__
807 +#include "yaffs_guts.h"
809 +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
810 +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
811 +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
812 +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
813 +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
814 +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
816 +#endif
817 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.c linux-3.4.90/fs/yaffs2/yaffs_bitmap.c
818 --- linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
819 +++ linux-3.4.90/fs/yaffs2/yaffs_bitmap.c 2014-05-17 15:08:09.000000000 +0200
820 @@ -0,0 +1,97 @@
822 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
824 + * Copyright (C) 2002-2011 Aleph One Ltd.
825 + * for Toby Churchill Ltd and Brightstar Engineering
827 + * Created by Charles Manning <charles@aleph1.co.uk>
829 + * This program is free software; you can redistribute it and/or modify
830 + * it under the terms of the GNU General Public License version 2 as
831 + * published by the Free Software Foundation.
832 + */
834 +#include "yaffs_bitmap.h"
835 +#include "yaffs_trace.h"
837 + * Chunk bitmap manipulations
838 + */
840 +static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
842 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
843 + yaffs_trace(YAFFS_TRACE_ERROR,
844 + "BlockBits block %d is not valid",
845 + blk);
846 + BUG();
848 + return dev->chunk_bits +
849 + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
852 +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
854 + if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
855 + chunk < 0 || chunk >= dev->param.chunks_per_block) {
856 + yaffs_trace(YAFFS_TRACE_ERROR,
857 + "Chunk Id (%d:%d) invalid",
858 + blk, chunk);
859 + BUG();
863 +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
865 + u8 *blk_bits = yaffs_block_bits(dev, blk);
867 + memset(blk_bits, 0, dev->chunk_bit_stride);
870 +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
872 + u8 *blk_bits = yaffs_block_bits(dev, blk);
874 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
875 + blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
878 +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
880 + u8 *blk_bits = yaffs_block_bits(dev, blk);
882 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
883 + blk_bits[chunk / 8] |= (1 << (chunk & 7));
886 +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
888 + u8 *blk_bits = yaffs_block_bits(dev, blk);
890 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
891 + return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
894 +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
896 + u8 *blk_bits = yaffs_block_bits(dev, blk);
897 + int i;
899 + for (i = 0; i < dev->chunk_bit_stride; i++) {
900 + if (*blk_bits)
901 + return 1;
902 + blk_bits++;
904 + return 0;
907 +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
909 + u8 *blk_bits = yaffs_block_bits(dev, blk);
910 + int i;
911 + int n = 0;
913 + for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
914 + n += hweight8(*blk_bits);
916 + return n;
918 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.h linux-3.4.90/fs/yaffs2/yaffs_bitmap.h
919 --- linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
920 +++ linux-3.4.90/fs/yaffs2/yaffs_bitmap.h 2014-05-17 15:08:09.000000000 +0200
921 @@ -0,0 +1,33 @@
923 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
925 + * Copyright (C) 2002-2011 Aleph One Ltd.
926 + * for Toby Churchill Ltd and Brightstar Engineering
928 + * Created by Charles Manning <charles@aleph1.co.uk>
930 + * This program is free software; you can redistribute it and/or modify
931 + * it under the terms of the GNU Lesser General Public License version 2.1 as
932 + * published by the Free Software Foundation.
934 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
935 + */
938 + * Chunk bitmap manipulations
939 + */
941 +#ifndef __YAFFS_BITMAP_H__
942 +#define __YAFFS_BITMAP_H__
944 +#include "yaffs_guts.h"
946 +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
947 +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
948 +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
949 +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
950 +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
951 +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
952 +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
954 +#endif
955 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.4.90/fs/yaffs2/yaffs_checkptrw.c
956 --- linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
957 +++ linux-3.4.90/fs/yaffs2/yaffs_checkptrw.c 2014-05-17 15:08:09.000000000 +0200
958 @@ -0,0 +1,474 @@
960 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
962 + * Copyright (C) 2002-2011 Aleph One Ltd.
963 + * for Toby Churchill Ltd and Brightstar Engineering
965 + * Created by Charles Manning <charles@aleph1.co.uk>
967 + * This program is free software; you can redistribute it and/or modify
968 + * it under the terms of the GNU General Public License version 2 as
969 + * published by the Free Software Foundation.
970 + */
972 +#include "yaffs_checkptrw.h"
973 +#include "yaffs_getblockinfo.h"
975 +struct yaffs_checkpt_chunk_hdr {
976 + int version;
977 + int seq;
978 + u32 sum;
979 + u32 xor;
980 +} ;
983 +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
985 + return chunk - dev->chunk_offset;
988 +static int apply_block_offset(struct yaffs_dev *dev, int block)
990 + return block - dev->block_offset;
993 +static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
995 + struct yaffs_checkpt_chunk_hdr hdr;
997 + hdr.version = YAFFS_CHECKPOINT_VERSION;
998 + hdr.seq = dev->checkpt_page_seq;
999 + hdr.sum = dev->checkpt_sum;
1000 + hdr.xor = dev->checkpt_xor;
1002 + dev->checkpt_byte_offs = sizeof(hdr);
1004 + memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
1007 +static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
1009 + struct yaffs_checkpt_chunk_hdr hdr;
1011 + memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
1013 + dev->checkpt_byte_offs = sizeof(hdr);
1015 + return hdr.version == YAFFS_CHECKPOINT_VERSION &&
1016 + hdr.seq == dev->checkpt_page_seq &&
1017 + hdr.sum == dev->checkpt_sum &&
1018 + hdr.xor == dev->checkpt_xor;
1021 +static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
1023 + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
1025 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1026 + "checkpt blocks_avail = %d", blocks_avail);
1028 + return (blocks_avail <= 0) ? 0 : 1;
1031 +static int yaffs_checkpt_erase(struct yaffs_dev *dev)
1033 + int i;
1035 + if (!dev->drv.drv_erase_fn)
1036 + return 0;
1037 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1038 + "checking blocks %d to %d",
1039 + dev->internal_start_block, dev->internal_end_block);
1041 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
1042 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
1043 + int offset_i = apply_block_offset(dev, i);
1044 + int result;
1046 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
1047 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1048 + "erasing checkpt block %d", i);
1050 + dev->n_erasures++;
1052 + result = dev->drv.drv_erase_fn(dev, offset_i);
1053 + if(result) {
1054 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
1055 + dev->n_erased_blocks++;
1056 + dev->n_free_chunks +=
1057 + dev->param.chunks_per_block;
1058 + } else {
1059 + dev->drv.drv_mark_bad_fn(dev, offset_i);
1060 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
1065 + dev->blocks_in_checkpt = 0;
1067 + return 1;
1070 +static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
1072 + int i;
1073 + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
1075 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1076 + "allocating checkpt block: erased %d reserved %d avail %d next %d ",
1077 + dev->n_erased_blocks, dev->param.n_reserved_blocks,
1078 + blocks_avail, dev->checkpt_next_block);
1080 + if (dev->checkpt_next_block >= 0 &&
1081 + dev->checkpt_next_block <= dev->internal_end_block &&
1082 + blocks_avail > 0) {
1084 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
1085 + i++) {
1086 + struct yaffs_block_info *bi;
1088 + bi = yaffs_get_block_info(dev, i);
1089 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
1090 + dev->checkpt_next_block = i + 1;
1091 + dev->checkpt_cur_block = i;
1092 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1093 + "allocating checkpt block %d", i);
1094 + return;
1098 + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
1100 + dev->checkpt_next_block = -1;
1101 + dev->checkpt_cur_block = -1;
1104 +static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
1106 + int i;
1107 + struct yaffs_ext_tags tags;
1109 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1110 + "find next checkpt block: start: blocks %d next %d",
1111 + dev->blocks_in_checkpt, dev->checkpt_next_block);
1113 + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
1114 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
1115 + i++) {
1116 + int chunk = i * dev->param.chunks_per_block;
1117 + enum yaffs_block_state state;
1118 + u32 seq;
1120 + dev->tagger.read_chunk_tags_fn(dev,
1121 + apply_chunk_offset(dev, chunk),
1122 + NULL, &tags);
1123 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1124 + "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
1125 + i, (int) state,
1126 + tags.obj_id, tags.seq_number,
1127 + tags.ecc_result);
1129 + if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1130 + continue;
1132 + dev->tagger.query_block_fn(dev,
1133 + apply_block_offset(dev, i),
1134 + &state, &seq);
1135 + if (state == YAFFS_BLOCK_STATE_DEAD)
1136 + continue;
1138 + /* Right kind of block */
1139 + dev->checkpt_next_block = tags.obj_id;
1140 + dev->checkpt_cur_block = i;
1141 + dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
1142 + dev->blocks_in_checkpt++;
1143 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1144 + "found checkpt block %d", i);
1145 + return;
1148 + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
1150 + dev->checkpt_next_block = -1;
1151 + dev->checkpt_cur_block = -1;
1154 +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
1156 + int i;
1158 + dev->checkpt_open_write = writing;
1160 + /* Got the functions we need? */
1161 + if (!dev->tagger.write_chunk_tags_fn ||
1162 + !dev->tagger.read_chunk_tags_fn ||
1163 + !dev->drv.drv_erase_fn ||
1164 + !dev->drv.drv_mark_bad_fn)
1165 + return 0;
1167 + if (writing && !yaffs2_checkpt_space_ok(dev))
1168 + return 0;
1170 + if (!dev->checkpt_buffer)
1171 + dev->checkpt_buffer =
1172 + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
1173 + if (!dev->checkpt_buffer)
1174 + return 0;
1176 + dev->checkpt_page_seq = 0;
1177 + dev->checkpt_byte_count = 0;
1178 + dev->checkpt_sum = 0;
1179 + dev->checkpt_xor = 0;
1180 + dev->checkpt_cur_block = -1;
1181 + dev->checkpt_cur_chunk = -1;
1182 + dev->checkpt_next_block = dev->internal_start_block;
1184 + if (writing) {
1185 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1186 + yaffs2_checkpt_init_chunk_hdr(dev);
1187 + return yaffs_checkpt_erase(dev);
1190 + /* Opening for a read */
1191 + /* Set to a value that will kick off a read */
1192 + dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
1193 + /* A checkpoint block list of 1 checkpoint block per 16 block is
1194 + * (hopefully) going to be way more than we need */
1195 + dev->blocks_in_checkpt = 0;
1196 + dev->checkpt_max_blocks =
1197 + (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
1198 + dev->checkpt_block_list =
1199 + kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
1201 + if (!dev->checkpt_block_list)
1202 + return 0;
1204 + for (i = 0; i < dev->checkpt_max_blocks; i++)
1205 + dev->checkpt_block_list[i] = -1;
1207 + return 1;
1210 +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
1212 + u32 composite_sum;
1214 + composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
1215 + *sum = composite_sum;
1216 + return 1;
1219 +static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
1221 + int chunk;
1222 + int offset_chunk;
1223 + struct yaffs_ext_tags tags;
1225 + if (dev->checkpt_cur_block < 0) {
1226 + yaffs2_checkpt_find_erased_block(dev);
1227 + dev->checkpt_cur_chunk = 0;
1230 + if (dev->checkpt_cur_block < 0)
1231 + return 0;
1233 + tags.is_deleted = 0;
1234 + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
1235 + tags.chunk_id = dev->checkpt_page_seq + 1;
1236 + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1237 + tags.n_bytes = dev->data_bytes_per_chunk;
1238 + if (dev->checkpt_cur_chunk == 0) {
1239 + /* First chunk we write for the block? Set block state to
1240 + checkpoint */
1241 + struct yaffs_block_info *bi =
1242 + yaffs_get_block_info(dev, dev->checkpt_cur_block);
1243 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1244 + dev->blocks_in_checkpt++;
1247 + chunk =
1248 + dev->checkpt_cur_block * dev->param.chunks_per_block +
1249 + dev->checkpt_cur_chunk;
1251 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1252 + "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
1253 + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
1254 + tags.obj_id, tags.chunk_id);
1256 + offset_chunk = apply_chunk_offset(dev, chunk);
1258 + dev->n_page_writes++;
1260 + dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
1261 + dev->checkpt_buffer, &tags);
1262 + dev->checkpt_page_seq++;
1263 + dev->checkpt_cur_chunk++;
1264 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
1265 + dev->checkpt_cur_chunk = 0;
1266 + dev->checkpt_cur_block = -1;
1268 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1270 + yaffs2_checkpt_init_chunk_hdr(dev);
1273 + return 1;
1276 +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
1278 + int i = 0;
1279 + int ok = 1;
1280 + u8 *data_bytes = (u8 *) data;
1282 + if (!dev->checkpt_buffer)
1283 + return 0;
1285 + if (!dev->checkpt_open_write)
1286 + return -1;
1288 + while (i < n_bytes && ok) {
1289 + dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
1290 + dev->checkpt_sum += *data_bytes;
1291 + dev->checkpt_xor ^= *data_bytes;
1293 + dev->checkpt_byte_offs++;
1294 + i++;
1295 + data_bytes++;
1296 + dev->checkpt_byte_count++;
1298 + if (dev->checkpt_byte_offs < 0 ||
1299 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
1300 + ok = yaffs2_checkpt_flush_buffer(dev);
1303 + return i;
1306 +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
1308 + int i = 0;
1309 + int ok = 1;
1310 + struct yaffs_ext_tags tags;
1311 + int chunk;
1312 + int offset_chunk;
1313 + u8 *data_bytes = (u8 *) data;
1315 + if (!dev->checkpt_buffer)
1316 + return 0;
1318 + if (dev->checkpt_open_write)
1319 + return -1;
1321 + while (i < n_bytes && ok) {
1323 + if (dev->checkpt_byte_offs < 0 ||
1324 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
1326 + if (dev->checkpt_cur_block < 0) {
1327 + yaffs2_checkpt_find_block(dev);
1328 + dev->checkpt_cur_chunk = 0;
1331 + if (dev->checkpt_cur_block < 0) {
1332 + ok = 0;
1333 + break;
1336 + chunk = dev->checkpt_cur_block *
1337 + dev->param.chunks_per_block +
1338 + dev->checkpt_cur_chunk;
1340 + offset_chunk = apply_chunk_offset(dev, chunk);
1341 + dev->n_page_reads++;
1343 + /* read in the next chunk */
1344 + dev->tagger.read_chunk_tags_fn(dev,
1345 + offset_chunk,
1346 + dev->checkpt_buffer,
1347 + &tags);
1349 + if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
1350 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
1351 + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
1352 + ok = 0;
1353 + break;
1355 + if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
1356 + ok = 0;
1357 + break;
1360 + dev->checkpt_page_seq++;
1361 + dev->checkpt_cur_chunk++;
1363 + if (dev->checkpt_cur_chunk >=
1364 + dev->param.chunks_per_block)
1365 + dev->checkpt_cur_block = -1;
1369 + *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
1370 + dev->checkpt_sum += *data_bytes;
1371 + dev->checkpt_xor ^= *data_bytes;
1372 + dev->checkpt_byte_offs++;
1373 + i++;
1374 + data_bytes++;
1375 + dev->checkpt_byte_count++;
1378 + return i;
1381 +int yaffs_checkpt_close(struct yaffs_dev *dev)
1383 + int i;
1385 + if (dev->checkpt_open_write) {
1386 + if (dev->checkpt_byte_offs !=
1387 + sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
1388 + yaffs2_checkpt_flush_buffer(dev);
1389 + } else if (dev->checkpt_block_list) {
1390 + for (i = 0;
1391 + i < dev->blocks_in_checkpt &&
1392 + dev->checkpt_block_list[i] >= 0; i++) {
1393 + int blk = dev->checkpt_block_list[i];
1394 + struct yaffs_block_info *bi = NULL;
1396 + if (dev->internal_start_block <= blk &&
1397 + blk <= dev->internal_end_block)
1398 + bi = yaffs_get_block_info(dev, blk);
1399 + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
1400 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1402 + kfree(dev->checkpt_block_list);
1403 + dev->checkpt_block_list = NULL;
1406 + dev->n_free_chunks -=
1407 + dev->blocks_in_checkpt * dev->param.chunks_per_block;
1408 + dev->n_erased_blocks -= dev->blocks_in_checkpt;
1410 + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
1411 + dev->checkpt_byte_count);
1413 + if (dev->checkpt_buffer) {
1414 + /* free the buffer */
1415 + kfree(dev->checkpt_buffer);
1416 + dev->checkpt_buffer = NULL;
1417 + return 1;
1418 + } else {
1419 + return 0;
1423 +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
1425 + /* Erase the checkpoint data */
1427 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1428 + "checkpoint invalidate of %d blocks",
1429 + dev->blocks_in_checkpt);
1431 + return yaffs_checkpt_erase(dev);
1433 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.4.90/fs/yaffs2/yaffs_checkptrw.h
1434 --- linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
1435 +++ linux-3.4.90/fs/yaffs2/yaffs_checkptrw.h 2014-05-17 15:08:09.000000000 +0200
1436 @@ -0,0 +1,33 @@
1438 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1440 + * Copyright (C) 2002-2011 Aleph One Ltd.
1441 + * for Toby Churchill Ltd and Brightstar Engineering
1443 + * Created by Charles Manning <charles@aleph1.co.uk>
1445 + * This program is free software; you can redistribute it and/or modify
1446 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1447 + * published by the Free Software Foundation.
1449 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1450 + */
1452 +#ifndef __YAFFS_CHECKPTRW_H__
1453 +#define __YAFFS_CHECKPTRW_H__
1455 +#include "yaffs_guts.h"
1457 +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
1459 +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
1461 +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
1463 +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
1465 +int yaffs_checkpt_close(struct yaffs_dev *dev);
1467 +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
1469 +#endif
1470 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.c linux-3.4.90/fs/yaffs2/yaffs_ecc.c
1471 --- linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
1472 +++ linux-3.4.90/fs/yaffs2/yaffs_ecc.c 2014-05-17 15:08:09.000000000 +0200
1473 @@ -0,0 +1,281 @@
1475 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1477 + * Copyright (C) 2002-2011 Aleph One Ltd.
1478 + * for Toby Churchill Ltd and Brightstar Engineering
1480 + * Created by Charles Manning <charles@aleph1.co.uk>
1482 + * This program is free software; you can redistribute it and/or modify
1483 + * it under the terms of the GNU General Public License version 2 as
1484 + * published by the Free Software Foundation.
1485 + */
1488 + * This code implements the ECC algorithm used in SmartMedia.
1490 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
1491 + * The two unused bit are set to 1.
1492 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
1493 + * such ECC blocks are used on a 512-byte NAND page.
1495 + */
1497 +#include "yportenv.h"
1499 +#include "yaffs_ecc.h"
1501 +/* Table generated by gen-ecc.c
1502 + * Using a table means we do not have to calculate p1..p4 and p1'..p4'
1503 + * for each byte of data. These are instead provided in a table in bits7..2.
1504 + * Bit 0 of each entry indicates whether the entry has an odd or even parity,
1505 + * and therefore this bytes influence on the line parity.
1506 + */
1508 +static const unsigned char column_parity_table[] = {
1509 + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1510 + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1511 + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1512 + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1513 + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1514 + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1515 + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
1516 + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1517 + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
1518 + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1519 + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
1520 + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1521 + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
1522 + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1523 + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
1524 + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1525 + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
1526 + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1527 + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
1528 + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1529 + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
1530 + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1531 + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
1532 + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1533 + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
1534 + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1535 + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1536 + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1537 + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1538 + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1539 + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1540 + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1544 +/* Calculate the ECC for a 256-byte block of data */
1545 +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
1547 + unsigned int i;
1548 + unsigned char col_parity = 0;
1549 + unsigned char line_parity = 0;
1550 + unsigned char line_parity_prime = 0;
1551 + unsigned char t;
1552 + unsigned char b;
1554 + for (i = 0; i < 256; i++) {
1555 + b = column_parity_table[*data++];
1556 + col_parity ^= b;
1558 + if (b & 0x01) { /* odd number of bits in the byte */
1559 + line_parity ^= i;
1560 + line_parity_prime ^= ~i;
1564 + ecc[2] = (~col_parity) | 0x03;
1566 + t = 0;
1567 + if (line_parity & 0x80)
1568 + t |= 0x80;
1569 + if (line_parity_prime & 0x80)
1570 + t |= 0x40;
1571 + if (line_parity & 0x40)
1572 + t |= 0x20;
1573 + if (line_parity_prime & 0x40)
1574 + t |= 0x10;
1575 + if (line_parity & 0x20)
1576 + t |= 0x08;
1577 + if (line_parity_prime & 0x20)
1578 + t |= 0x04;
1579 + if (line_parity & 0x10)
1580 + t |= 0x02;
1581 + if (line_parity_prime & 0x10)
1582 + t |= 0x01;
1583 + ecc[1] = ~t;
1585 + t = 0;
1586 + if (line_parity & 0x08)
1587 + t |= 0x80;
1588 + if (line_parity_prime & 0x08)
1589 + t |= 0x40;
1590 + if (line_parity & 0x04)
1591 + t |= 0x20;
1592 + if (line_parity_prime & 0x04)
1593 + t |= 0x10;
1594 + if (line_parity & 0x02)
1595 + t |= 0x08;
1596 + if (line_parity_prime & 0x02)
1597 + t |= 0x04;
1598 + if (line_parity & 0x01)
1599 + t |= 0x02;
1600 + if (line_parity_prime & 0x01)
1601 + t |= 0x01;
1602 + ecc[0] = ~t;
1606 +/* Correct the ECC on a 256 byte block of data */
1608 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1609 + const unsigned char *test_ecc)
1611 + unsigned char d0, d1, d2; /* deltas */
1613 + d0 = read_ecc[0] ^ test_ecc[0];
1614 + d1 = read_ecc[1] ^ test_ecc[1];
1615 + d2 = read_ecc[2] ^ test_ecc[2];
1617 + if ((d0 | d1 | d2) == 0)
1618 + return 0; /* no error */
1620 + if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
1621 + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
1622 + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
1623 + /* Single bit (recoverable) error in data */
1625 + unsigned byte;
1626 + unsigned bit;
1628 + bit = byte = 0;
1630 + if (d1 & 0x80)
1631 + byte |= 0x80;
1632 + if (d1 & 0x20)
1633 + byte |= 0x40;
1634 + if (d1 & 0x08)
1635 + byte |= 0x20;
1636 + if (d1 & 0x02)
1637 + byte |= 0x10;
1638 + if (d0 & 0x80)
1639 + byte |= 0x08;
1640 + if (d0 & 0x20)
1641 + byte |= 0x04;
1642 + if (d0 & 0x08)
1643 + byte |= 0x02;
1644 + if (d0 & 0x02)
1645 + byte |= 0x01;
1647 + if (d2 & 0x80)
1648 + bit |= 0x04;
1649 + if (d2 & 0x20)
1650 + bit |= 0x02;
1651 + if (d2 & 0x08)
1652 + bit |= 0x01;
1654 + data[byte] ^= (1 << bit);
1656 + return 1; /* Corrected the error */
1659 + if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
1660 + /* Reccoverable error in ecc */
1662 + read_ecc[0] = test_ecc[0];
1663 + read_ecc[1] = test_ecc[1];
1664 + read_ecc[2] = test_ecc[2];
1666 + return 1; /* Corrected the error */
1669 + /* Unrecoverable error */
1671 + return -1;
1676 + * ECCxxxOther does ECC calcs on arbitrary n bytes of data
1677 + */
1678 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1679 + struct yaffs_ecc_other *ecc_other)
1681 + unsigned int i;
1682 + unsigned char col_parity = 0;
1683 + unsigned line_parity = 0;
1684 + unsigned line_parity_prime = 0;
1685 + unsigned char b;
1687 + for (i = 0; i < n_bytes; i++) {
1688 + b = column_parity_table[*data++];
1689 + col_parity ^= b;
1691 + if (b & 0x01) {
1692 + /* odd number of bits in the byte */
1693 + line_parity ^= i;
1694 + line_parity_prime ^= ~i;
1699 + ecc_other->col_parity = (col_parity >> 2) & 0x3f;
1700 + ecc_other->line_parity = line_parity;
1701 + ecc_other->line_parity_prime = line_parity_prime;
1704 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1705 + struct yaffs_ecc_other *read_ecc,
1706 + const struct yaffs_ecc_other *test_ecc)
1708 + unsigned char delta_col; /* column parity delta */
1709 + unsigned delta_line; /* line parity delta */
1710 + unsigned delta_line_prime; /* line parity delta */
1711 + unsigned bit;
1713 + delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
1714 + delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
1715 + delta_line_prime =
1716 + read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
1718 + if ((delta_col | delta_line | delta_line_prime) == 0)
1719 + return 0; /* no error */
1721 + if (delta_line == ~delta_line_prime &&
1722 + (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
1723 + /* Single bit (recoverable) error in data */
1725 + bit = 0;
1727 + if (delta_col & 0x20)
1728 + bit |= 0x04;
1729 + if (delta_col & 0x08)
1730 + bit |= 0x02;
1731 + if (delta_col & 0x02)
1732 + bit |= 0x01;
1734 + if (delta_line >= n_bytes)
1735 + return -1;
1737 + data[delta_line] ^= (1 << bit);
1739 + return 1; /* corrected */
1742 + if ((hweight32(delta_line) +
1743 + hweight32(delta_line_prime) +
1744 + hweight8(delta_col)) == 1) {
1745 + /* Reccoverable error in ecc */
1747 + *read_ecc = *test_ecc;
1748 + return 1; /* corrected */
1751 + /* Unrecoverable error */
1753 + return -1;
1755 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.h linux-3.4.90/fs/yaffs2/yaffs_ecc.h
1756 --- linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
1757 +++ linux-3.4.90/fs/yaffs2/yaffs_ecc.h 2014-05-17 15:08:09.000000000 +0200
1758 @@ -0,0 +1,44 @@
1760 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1762 + * Copyright (C) 2002-2011 Aleph One Ltd.
1763 + * for Toby Churchill Ltd and Brightstar Engineering
1765 + * Created by Charles Manning <charles@aleph1.co.uk>
1767 + * This program is free software; you can redistribute it and/or modify
1768 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1769 + * published by the Free Software Foundation.
1771 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1772 + */
1775 + * This code implements the ECC algorithm used in SmartMedia.
1777 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
1778 + * The two unused bit are set to 1.
1779 + * The ECC can correct single bit errors in a 256-byte page of data.
1780 + * Thus, two such ECC blocks are used on a 512-byte NAND page.
1782 + */
1784 +#ifndef __YAFFS_ECC_H__
1785 +#define __YAFFS_ECC_H__
1787 +struct yaffs_ecc_other {
1788 + unsigned char col_parity;
1789 + unsigned line_parity;
1790 + unsigned line_parity_prime;
1793 +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
1794 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1795 + const unsigned char *test_ecc);
1797 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1798 + struct yaffs_ecc_other *ecc);
1799 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1800 + struct yaffs_ecc_other *read_ecc,
1801 + const struct yaffs_ecc_other *test_ecc);
1802 +#endif
1803 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.4.90/fs/yaffs2/yaffs_getblockinfo.h
1804 --- linux-3.4.90.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
1805 +++ linux-3.4.90/fs/yaffs2/yaffs_getblockinfo.h 2014-05-17 15:08:09.000000000 +0200
1806 @@ -0,0 +1,35 @@
1808 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1810 + * Copyright (C) 2002-2011 Aleph One Ltd.
1811 + * for Toby Churchill Ltd and Brightstar Engineering
1813 + * Created by Charles Manning <charles@aleph1.co.uk>
1815 + * This program is free software; you can redistribute it and/or modify
1816 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1817 + * published by the Free Software Foundation.
1819 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1820 + */
1822 +#ifndef __YAFFS_GETBLOCKINFO_H__
1823 +#define __YAFFS_GETBLOCKINFO_H__
1825 +#include "yaffs_guts.h"
1826 +#include "yaffs_trace.h"
1828 +/* Function to manipulate block info */
1829 +static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
1830 + *dev, int blk)
1832 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
1833 + yaffs_trace(YAFFS_TRACE_ERROR,
1834 + "**>> yaffs: get_block_info block %d is not valid",
1835 + blk);
1836 + BUG();
1838 + return &dev->block_info[blk - dev->internal_start_block];
1841 +#endif
1842 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_guts.c linux-3.4.90/fs/yaffs2/yaffs_guts.c
1843 --- linux-3.4.90.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
1844 +++ linux-3.4.90/fs/yaffs2/yaffs_guts.c 2014-05-17 15:08:09.000000000 +0200
1845 @@ -0,0 +1,5146 @@
1847 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1849 + * Copyright (C) 2002-2011 Aleph One Ltd.
1850 + * for Toby Churchill Ltd and Brightstar Engineering
1852 + * Created by Charles Manning <charles@aleph1.co.uk>
1854 + * This program is free software; you can redistribute it and/or modify
1855 + * it under the terms of the GNU General Public License version 2 as
1856 + * published by the Free Software Foundation.
1857 + */
1859 +#include "yportenv.h"
1860 +#include "yaffs_trace.h"
1862 +#include "yaffs_guts.h"
1863 +#include "yaffs_getblockinfo.h"
1864 +#include "yaffs_tagscompat.h"
1865 +#include "yaffs_tagsmarshall.h"
1866 +#include "yaffs_nand.h"
1867 +#include "yaffs_yaffs1.h"
1868 +#include "yaffs_yaffs2.h"
1869 +#include "yaffs_bitmap.h"
1870 +#include "yaffs_verify.h"
1871 +#include "yaffs_nand.h"
1872 +#include "yaffs_packedtags2.h"
1873 +#include "yaffs_nameval.h"
1874 +#include "yaffs_allocator.h"
1875 +#include "yaffs_attribs.h"
1876 +#include "yaffs_summary.h"
1878 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
1879 +#define YAFFS_GC_GOOD_ENOUGH 2
1880 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
1882 +#include "yaffs_ecc.h"
1884 +/* Forward declarations */
1886 +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
1887 + const u8 *buffer, int n_bytes, int use_reserve);
1889 +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
1890 + int buffer_size);
1892 +/* Function to calculate chunk and offset */
1894 +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
1895 + int *chunk_out, u32 *offset_out)
1897 + int chunk;
1898 + u32 offset;
1900 + chunk = (u32) (addr >> dev->chunk_shift);
1902 + if (dev->chunk_div == 1) {
1903 + /* easy power of 2 case */
1904 + offset = (u32) (addr & dev->chunk_mask);
1905 + } else {
1906 + /* Non power-of-2 case */
1908 + loff_t chunk_base;
1910 + chunk /= dev->chunk_div;
1912 + chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
1913 + offset = (u32) (addr - chunk_base);
1916 + *chunk_out = chunk;
1917 + *offset_out = offset;
1920 +/* Function to return the number of shifts for a power of 2 greater than or
1921 + * equal to the given number
1922 + * Note we don't try to cater for all possible numbers and this does not have to
1923 + * be hellishly efficient.
1924 + */
1926 +static inline u32 calc_shifts_ceiling(u32 x)
1928 + int extra_bits;
1929 + int shifts;
1931 + shifts = extra_bits = 0;
1933 + while (x > 1) {
1934 + if (x & 1)
1935 + extra_bits++;
1936 + x >>= 1;
1937 + shifts++;
1940 + if (extra_bits)
1941 + shifts++;
1943 + return shifts;
1946 +/* Function to return the number of shifts to get a 1 in bit 0
1947 + */
1949 +static inline u32 calc_shifts(u32 x)
1951 + u32 shifts;
1953 + shifts = 0;
1955 + if (!x)
1956 + return 0;
1958 + while (!(x & 1)) {
1959 + x >>= 1;
1960 + shifts++;
1963 + return shifts;
1967 + * Temporary buffer manipulations.
1968 + */
1970 +static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
1972 + int i;
1973 + u8 *buf = (u8 *) 1;
1975 + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
1977 + for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
1978 + dev->temp_buffer[i].in_use = 0;
1979 + buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
1980 + dev->temp_buffer[i].buffer = buf;
1983 + return buf ? YAFFS_OK : YAFFS_FAIL;
1986 +u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
1988 + int i;
1990 + dev->temp_in_use++;
1991 + if (dev->temp_in_use > dev->max_temp)
1992 + dev->max_temp = dev->temp_in_use;
1994 + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
1995 + if (dev->temp_buffer[i].in_use == 0) {
1996 + dev->temp_buffer[i].in_use = 1;
1997 + return dev->temp_buffer[i].buffer;
2001 + yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
2002 + /*
2003 + * If we got here then we have to allocate an unmanaged one
2004 + * This is not good.
2005 + */
2007 + dev->unmanaged_buffer_allocs++;
2008 + return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
2012 +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
2014 + int i;
2016 + dev->temp_in_use--;
2018 + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
2019 + if (dev->temp_buffer[i].buffer == buffer) {
2020 + dev->temp_buffer[i].in_use = 0;
2021 + return;
2025 + if (buffer) {
2026 + /* assume it is an unmanaged one. */
2027 + yaffs_trace(YAFFS_TRACE_BUFFERS,
2028 + "Releasing unmanaged temp buffer");
2029 + kfree(buffer);
2030 + dev->unmanaged_buffer_deallocs++;
2036 + * Functions for robustisizing TODO
2038 + */
2040 +static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
2041 + const u8 *data,
2042 + const struct yaffs_ext_tags *tags)
2044 + (void) dev;
2045 + (void) nand_chunk;
2046 + (void) data;
2047 + (void) tags;
2050 +static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
2051 + const struct yaffs_ext_tags *tags)
2053 + (void) dev;
2054 + (void) nand_chunk;
2055 + (void) tags;
2058 +void yaffs_handle_chunk_error(struct yaffs_dev *dev,
2059 + struct yaffs_block_info *bi)
2061 + if (!bi->gc_prioritise) {
2062 + bi->gc_prioritise = 1;
2063 + dev->has_pending_prioritised_gc = 1;
2064 + bi->chunk_error_strikes++;
2066 + if (bi->chunk_error_strikes > 3) {
2067 + bi->needs_retiring = 1; /* Too many stikes, so retire */
2068 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2069 + "yaffs: Block struck out");
2075 +static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
2076 + int erased_ok)
2078 + int flash_block = nand_chunk / dev->param.chunks_per_block;
2079 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
2081 + yaffs_handle_chunk_error(dev, bi);
2083 + if (erased_ok) {
2084 + /* Was an actual write failure,
2085 + * so mark the block for retirement.*/
2086 + bi->needs_retiring = 1;
2087 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
2088 + "**>> Block %d needs retiring", flash_block);
2091 + /* Delete the chunk */
2092 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
2093 + yaffs_skip_rest_of_block(dev);
2097 + * Verification code
2098 + */
2101 + * Simple hash function. Needs to have a reasonable spread
2102 + */
2104 +static inline int yaffs_hash_fn(int n)
2106 + if (n < 0)
2107 + n = -n;
2108 + return n % YAFFS_NOBJECT_BUCKETS;
2112 + * Access functions to useful fake objects.
2113 + * Note that root might have a presence in NAND if permissions are set.
2114 + */
2116 +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
2118 + return dev->root_dir;
2121 +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
2123 + return dev->lost_n_found;
2127 + * Erased NAND checking functions
2128 + */
2130 +int yaffs_check_ff(u8 *buffer, int n_bytes)
2132 + /* Horrible, slow implementation */
2133 + while (n_bytes--) {
2134 + if (*buffer != 0xff)
2135 + return 0;
2136 + buffer++;
2138 + return 1;
2141 +static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
2143 + int retval = YAFFS_OK;
2144 + u8 *data = yaffs_get_temp_buffer(dev);
2145 + struct yaffs_ext_tags tags;
2146 + int result;
2148 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
2150 + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
2151 + retval = YAFFS_FAIL;
2153 + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
2154 + tags.chunk_used) {
2155 + yaffs_trace(YAFFS_TRACE_NANDACCESS,
2156 + "Chunk %d not erased", nand_chunk);
2157 + retval = YAFFS_FAIL;
2160 + yaffs_release_temp_buffer(dev, data);
2162 + return retval;
2166 +static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
2167 + int nand_chunk,
2168 + const u8 *data,
2169 + struct yaffs_ext_tags *tags)
2171 + int retval = YAFFS_OK;
2172 + struct yaffs_ext_tags temp_tags;
2173 + u8 *buffer = yaffs_get_temp_buffer(dev);
2174 + int result;
2176 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
2177 + if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
2178 + temp_tags.obj_id != tags->obj_id ||
2179 + temp_tags.chunk_id != tags->chunk_id ||
2180 + temp_tags.n_bytes != tags->n_bytes)
2181 + retval = YAFFS_FAIL;
2183 + yaffs_release_temp_buffer(dev, buffer);
2185 + return retval;
2189 +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
2191 + int reserved_chunks;
2192 + int reserved_blocks = dev->param.n_reserved_blocks;
2193 + int checkpt_blocks;
2195 + checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
2197 + reserved_chunks =
2198 + (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
2200 + return (dev->n_free_chunks > (reserved_chunks + n_chunks));
2203 +static int yaffs_find_alloc_block(struct yaffs_dev *dev)
2205 + int i;
2206 + struct yaffs_block_info *bi;
2208 + if (dev->n_erased_blocks < 1) {
2209 + /* Hoosterman we've got a problem.
2210 + * Can't get space to gc
2211 + */
2212 + yaffs_trace(YAFFS_TRACE_ERROR,
2213 + "yaffs tragedy: no more erased blocks");
2215 + return -1;
2218 + /* Find an empty block. */
2220 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
2221 + dev->alloc_block_finder++;
2222 + if (dev->alloc_block_finder < dev->internal_start_block
2223 + || dev->alloc_block_finder > dev->internal_end_block) {
2224 + dev->alloc_block_finder = dev->internal_start_block;
2227 + bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
2229 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
2230 + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
2231 + dev->seq_number++;
2232 + bi->seq_number = dev->seq_number;
2233 + dev->n_erased_blocks--;
2234 + yaffs_trace(YAFFS_TRACE_ALLOCATE,
2235 + "Allocated block %d, seq %d, %d left" ,
2236 + dev->alloc_block_finder, dev->seq_number,
2237 + dev->n_erased_blocks);
2238 + return dev->alloc_block_finder;
2242 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2243 + "yaffs tragedy: no more erased blocks, but there should have been %d",
2244 + dev->n_erased_blocks);
2246 + return -1;
2249 +static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
2250 + struct yaffs_block_info **block_ptr)
2252 + int ret_val;
2253 + struct yaffs_block_info *bi;
2255 + if (dev->alloc_block < 0) {
2256 + /* Get next block to allocate off */
2257 + dev->alloc_block = yaffs_find_alloc_block(dev);
2258 + dev->alloc_page = 0;
2261 + if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
2262 + /* No space unless we're allowed to use the reserve. */
2263 + return -1;
2266 + if (dev->n_erased_blocks < dev->param.n_reserved_blocks
2267 + && dev->alloc_page == 0)
2268 + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
2270 + /* Next page please.... */
2271 + if (dev->alloc_block >= 0) {
2272 + bi = yaffs_get_block_info(dev, dev->alloc_block);
2274 + ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
2275 + dev->alloc_page;
2276 + bi->pages_in_use++;
2277 + yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
2279 + dev->alloc_page++;
2281 + dev->n_free_chunks--;
2283 + /* If the block is full set the state to full */
2284 + if (dev->alloc_page >= dev->param.chunks_per_block) {
2285 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
2286 + dev->alloc_block = -1;
2289 + if (block_ptr)
2290 + *block_ptr = bi;
2292 + return ret_val;
2295 + yaffs_trace(YAFFS_TRACE_ERROR,
2296 + "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
2298 + return -1;
2301 +static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
2303 + int n;
2305 + n = dev->n_erased_blocks * dev->param.chunks_per_block;
2307 + if (dev->alloc_block > 0)
2308 + n += (dev->param.chunks_per_block - dev->alloc_page);
2310 + return n;
2315 + * yaffs_skip_rest_of_block() skips over the rest of the allocation block
2316 + * if we don't want to write to it.
2317 + */
2318 +void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
2320 + struct yaffs_block_info *bi;
2322 + if (dev->alloc_block > 0) {
2323 + bi = yaffs_get_block_info(dev, dev->alloc_block);
2324 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
2325 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
2326 + dev->alloc_block = -1;
2331 +static int yaffs_write_new_chunk(struct yaffs_dev *dev,
2332 + const u8 *data,
2333 + struct yaffs_ext_tags *tags, int use_reserver)
2335 + int attempts = 0;
2336 + int write_ok = 0;
2337 + int chunk;
2339 + yaffs2_checkpt_invalidate(dev);
2341 + do {
2342 + struct yaffs_block_info *bi = 0;
2343 + int erased_ok = 0;
2345 + chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
2346 + if (chunk < 0) {
2347 + /* no space */
2348 + break;
2351 + /* First check this chunk is erased, if it needs
2352 + * checking. The checking policy (unless forced
2353 + * always on) is as follows:
2355 + * Check the first page we try to write in a block.
2356 + * If the check passes then we don't need to check any
2357 + * more. If the check fails, we check again...
2358 + * If the block has been erased, we don't need to check.
2360 + * However, if the block has been prioritised for gc,
2361 + * then we think there might be something odd about
2362 + * this block and stop using it.
2364 + * Rationale: We should only ever see chunks that have
2365 + * not been erased if there was a partially written
2366 + * chunk due to power loss. This checking policy should
2367 + * catch that case with very few checks and thus save a
2368 + * lot of checks that are most likely not needed.
2370 + * Mods to the above
2371 + * If an erase check fails or the write fails we skip the
2372 + * rest of the block.
2373 + */
2375 + /* let's give it a try */
2376 + attempts++;
2378 + if (dev->param.always_check_erased)
2379 + bi->skip_erased_check = 0;
2381 + if (!bi->skip_erased_check) {
2382 + erased_ok = yaffs_check_chunk_erased(dev, chunk);
2383 + if (erased_ok != YAFFS_OK) {
2384 + yaffs_trace(YAFFS_TRACE_ERROR,
2385 + "**>> yaffs chunk %d was not erased",
2386 + chunk);
2388 + /* If not erased, delete this one,
2389 + * skip rest of block and
2390 + * try another chunk */
2391 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
2392 + yaffs_skip_rest_of_block(dev);
2393 + continue;
2397 + write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
2399 + if (!bi->skip_erased_check)
2400 + write_ok =
2401 + yaffs_verify_chunk_written(dev, chunk, data, tags);
2403 + if (write_ok != YAFFS_OK) {
2404 + /* Clean up aborted write, skip to next block and
2405 + * try another chunk */
2406 + yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
2407 + continue;
2410 + bi->skip_erased_check = 1;
2412 + /* Copy the data into the robustification buffer */
2413 + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
2415 + } while (write_ok != YAFFS_OK &&
2416 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
2418 + if (!write_ok)
2419 + chunk = -1;
2421 + if (attempts > 1) {
2422 + yaffs_trace(YAFFS_TRACE_ERROR,
2423 + "**>> yaffs write required %d attempts",
2424 + attempts);
2425 + dev->n_retried_writes += (attempts - 1);
2428 + return chunk;
2432 + * Block retiring for handling a broken block.
2433 + */
2435 +static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
2437 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
2439 + yaffs2_checkpt_invalidate(dev);
2441 + yaffs2_clear_oldest_dirty_seq(dev, bi);
2443 + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
2444 + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
2445 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2446 + "yaffs: Failed to mark bad and erase block %d",
2447 + flash_block);
2448 + } else {
2449 + struct yaffs_ext_tags tags;
2450 + int chunk_id =
2451 + flash_block * dev->param.chunks_per_block;
2453 + u8 *buffer = yaffs_get_temp_buffer(dev);
2455 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
2456 + memset(&tags, 0, sizeof(tags));
2457 + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
2458 + if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
2459 + dev->chunk_offset,
2460 + buffer,
2461 + &tags) != YAFFS_OK)
2462 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2463 + "yaffs: Failed to write bad block marker to block %d",
2464 + flash_block);
2466 + yaffs_release_temp_buffer(dev, buffer);
2470 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
2471 + bi->gc_prioritise = 0;
2472 + bi->needs_retiring = 0;
2474 + dev->n_retired_blocks++;
2477 +/*---------------- Name handling functions ------------*/
2479 +static u16 yaffs_calc_name_sum(const YCHAR *name)
2481 + u16 sum = 0;
2482 + u16 i = 1;
2484 + if (!name)
2485 + return 0;
2487 + while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
2489 + /* 0x1f mask is case insensitive */
2490 + sum += ((*name) & 0x1f) * i;
2491 + i++;
2492 + name++;
2494 + return sum;
2498 +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
2500 + memset(obj->short_name, 0, sizeof(obj->short_name));
2502 + if (name && !name[0]) {
2503 + yaffs_fix_null_name(obj, obj->short_name,
2504 + YAFFS_SHORT_NAME_LENGTH);
2505 + name = obj->short_name;
2506 + } else if (name &&
2507 + strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
2508 + YAFFS_SHORT_NAME_LENGTH) {
2509 + strcpy(obj->short_name, name);
2512 + obj->sum = yaffs_calc_name_sum(name);
2515 +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
2516 + const struct yaffs_obj_hdr *oh)
2518 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
2519 + YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
2520 + memset(tmp_name, 0, sizeof(tmp_name));
2521 + yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
2522 + YAFFS_MAX_NAME_LENGTH + 1);
2523 + yaffs_set_obj_name(obj, tmp_name);
2524 +#else
2525 + yaffs_set_obj_name(obj, oh->name);
2526 +#endif
2529 +loff_t yaffs_max_file_size(struct yaffs_dev *dev)
2531 + if(sizeof(loff_t) < 8)
2532 + return YAFFS_MAX_FILE_SIZE_32;
2533 + else
2534 + return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
2537 +/*-------------------- TNODES -------------------
2539 + * List of spare tnodes
2540 + * The list is hooked together using the first pointer
2541 + * in the tnode.
2542 + */
2544 +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
2546 + struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
2548 + if (tn) {
2549 + memset(tn, 0, dev->tnode_size);
2550 + dev->n_tnodes++;
2553 + dev->checkpoint_blocks_required = 0; /* force recalculation */
2555 + return tn;
2558 +/* FreeTnode frees up a tnode and puts it back on the free list */
2559 +static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
2561 + yaffs_free_raw_tnode(dev, tn);
2562 + dev->n_tnodes--;
2563 + dev->checkpoint_blocks_required = 0; /* force recalculation */
2566 +static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
2568 + yaffs_deinit_raw_tnodes_and_objs(dev);
2569 + dev->n_obj = 0;
2570 + dev->n_tnodes = 0;
2573 +static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
2574 + unsigned pos, unsigned val)
2576 + u32 *map = (u32 *) tn;
2577 + u32 bit_in_map;
2578 + u32 bit_in_word;
2579 + u32 word_in_map;
2580 + u32 mask;
2582 + pos &= YAFFS_TNODES_LEVEL0_MASK;
2583 + val >>= dev->chunk_grp_bits;
2585 + bit_in_map = pos * dev->tnode_width;
2586 + word_in_map = bit_in_map / 32;
2587 + bit_in_word = bit_in_map & (32 - 1);
2589 + mask = dev->tnode_mask << bit_in_word;
2591 + map[word_in_map] &= ~mask;
2592 + map[word_in_map] |= (mask & (val << bit_in_word));
2594 + if (dev->tnode_width > (32 - bit_in_word)) {
2595 + bit_in_word = (32 - bit_in_word);
2596 + word_in_map++;
2597 + mask =
2598 + dev->tnode_mask >> bit_in_word;
2599 + map[word_in_map] &= ~mask;
2600 + map[word_in_map] |= (mask & (val >> bit_in_word));
2604 +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
2605 + unsigned pos)
2607 + u32 *map = (u32 *) tn;
2608 + u32 bit_in_map;
2609 + u32 bit_in_word;
2610 + u32 word_in_map;
2611 + u32 val;
2613 + pos &= YAFFS_TNODES_LEVEL0_MASK;
2615 + bit_in_map = pos * dev->tnode_width;
2616 + word_in_map = bit_in_map / 32;
2617 + bit_in_word = bit_in_map & (32 - 1);
2619 + val = map[word_in_map] >> bit_in_word;
2621 + if (dev->tnode_width > (32 - bit_in_word)) {
2622 + bit_in_word = (32 - bit_in_word);
2623 + word_in_map++;
2624 + val |= (map[word_in_map] << bit_in_word);
2627 + val &= dev->tnode_mask;
2628 + val <<= dev->chunk_grp_bits;
2630 + return val;
2633 +/* ------------------- End of individual tnode manipulation -----------------*/
2635 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
2636 + * The look up tree is represented by the top tnode and the number of top_level
2637 + * in the tree. 0 means only the level 0 tnode is in the tree.
2638 + */
2640 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
2641 +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
2642 + struct yaffs_file_var *file_struct,
2643 + u32 chunk_id)
2645 + struct yaffs_tnode *tn = file_struct->top;
2646 + u32 i;
2647 + int required_depth;
2648 + int level = file_struct->top_level;
2650 + (void) dev;
2652 + /* Check sane level and chunk Id */
2653 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
2654 + return NULL;
2656 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
2657 + return NULL;
2659 + /* First check we're tall enough (ie enough top_level) */
2661 + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
2662 + required_depth = 0;
2663 + while (i) {
2664 + i >>= YAFFS_TNODES_INTERNAL_BITS;
2665 + required_depth++;
2668 + if (required_depth > file_struct->top_level)
2669 + return NULL; /* Not tall enough, so we can't find it */
2671 + /* Traverse down to level 0 */
2672 + while (level > 0 && tn) {
2673 + tn = tn->internal[(chunk_id >>
2674 + (YAFFS_TNODES_LEVEL0_BITS +
2675 + (level - 1) *
2676 + YAFFS_TNODES_INTERNAL_BITS)) &
2677 + YAFFS_TNODES_INTERNAL_MASK];
2678 + level--;
2681 + return tn;
2684 +/* add_find_tnode_0 finds the level 0 tnode if it exists,
2685 + * otherwise first expands the tree.
2686 + * This happens in two steps:
2687 + * 1. If the tree isn't tall enough, then make it taller.
2688 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
2690 + * Used when modifying the tree.
2692 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the
2693 + * specified tn will be plugged into the ttree.
2694 + */
2696 +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
2697 + struct yaffs_file_var *file_struct,
2698 + u32 chunk_id,
2699 + struct yaffs_tnode *passed_tn)
2701 + int required_depth;
2702 + int i;
2703 + int l;
2704 + struct yaffs_tnode *tn;
2705 + u32 x;
2707 + /* Check sane level and page Id */
2708 + if (file_struct->top_level < 0 ||
2709 + file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
2710 + return NULL;
2712 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
2713 + return NULL;
2715 + /* First check we're tall enough (ie enough top_level) */
2717 + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
2718 + required_depth = 0;
2719 + while (x) {
2720 + x >>= YAFFS_TNODES_INTERNAL_BITS;
2721 + required_depth++;
2724 + if (required_depth > file_struct->top_level) {
2725 + /* Not tall enough, gotta make the tree taller */
2726 + for (i = file_struct->top_level; i < required_depth; i++) {
2728 + tn = yaffs_get_tnode(dev);
2730 + if (tn) {
2731 + tn->internal[0] = file_struct->top;
2732 + file_struct->top = tn;
2733 + file_struct->top_level++;
2734 + } else {
2735 + yaffs_trace(YAFFS_TRACE_ERROR,
2736 + "yaffs: no more tnodes");
2737 + return NULL;
2742 + /* Traverse down to level 0, adding anything we need */
2744 + l = file_struct->top_level;
2745 + tn = file_struct->top;
2747 + if (l > 0) {
2748 + while (l > 0 && tn) {
2749 + x = (chunk_id >>
2750 + (YAFFS_TNODES_LEVEL0_BITS +
2751 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
2752 + YAFFS_TNODES_INTERNAL_MASK;
2754 + if ((l > 1) && !tn->internal[x]) {
2755 + /* Add missing non-level-zero tnode */
2756 + tn->internal[x] = yaffs_get_tnode(dev);
2757 + if (!tn->internal[x])
2758 + return NULL;
2759 + } else if (l == 1) {
2760 + /* Looking from level 1 at level 0 */
2761 + if (passed_tn) {
2762 + /* If we already have one, release it */
2763 + if (tn->internal[x])
2764 + yaffs_free_tnode(dev,
2765 + tn->internal[x]);
2766 + tn->internal[x] = passed_tn;
2768 + } else if (!tn->internal[x]) {
2769 + /* Don't have one, none passed in */
2770 + tn->internal[x] = yaffs_get_tnode(dev);
2771 + if (!tn->internal[x])
2772 + return NULL;
2776 + tn = tn->internal[x];
2777 + l--;
2779 + } else {
2780 + /* top is level 0 */
2781 + if (passed_tn) {
2782 + memcpy(tn, passed_tn,
2783 + (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
2784 + yaffs_free_tnode(dev, passed_tn);
2788 + return tn;
2791 +static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
2792 + int chunk_obj)
2794 + return (tags->chunk_id == chunk_obj &&
2795 + tags->obj_id == obj_id &&
2796 + !tags->is_deleted) ? 1 : 0;
2800 +static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
2801 + struct yaffs_ext_tags *tags, int obj_id,
2802 + int inode_chunk)
2804 + int j;
2806 + for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
2807 + if (yaffs_check_chunk_bit
2808 + (dev, the_chunk / dev->param.chunks_per_block,
2809 + the_chunk % dev->param.chunks_per_block)) {
2811 + if (dev->chunk_grp_size == 1)
2812 + return the_chunk;
2813 + else {
2814 + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
2815 + tags);
2816 + if (yaffs_tags_match(tags,
2817 + obj_id, inode_chunk)) {
2818 + /* found it; */
2819 + return the_chunk;
2823 + the_chunk++;
2825 + return -1;
2828 +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
2829 + struct yaffs_ext_tags *tags)
2831 + /*Get the Tnode, then get the level 0 offset chunk offset */
2832 + struct yaffs_tnode *tn;
2833 + int the_chunk = -1;
2834 + struct yaffs_ext_tags local_tags;
2835 + int ret_val = -1;
2836 + struct yaffs_dev *dev = in->my_dev;
2838 + if (!tags) {
2839 + /* Passed a NULL, so use our own tags space */
2840 + tags = &local_tags;
2843 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
2845 + if (!tn)
2846 + return ret_val;
2848 + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
2850 + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
2851 + inode_chunk);
2852 + return ret_val;
2855 +static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
2856 + struct yaffs_ext_tags *tags)
2858 + /* Get the Tnode, then get the level 0 offset chunk offset */
2859 + struct yaffs_tnode *tn;
2860 + int the_chunk = -1;
2861 + struct yaffs_ext_tags local_tags;
2862 + struct yaffs_dev *dev = in->my_dev;
2863 + int ret_val = -1;
2865 + if (!tags) {
2866 + /* Passed a NULL, so use our own tags space */
2867 + tags = &local_tags;
2870 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
2872 + if (!tn)
2873 + return ret_val;
2875 + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
2877 + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
2878 + inode_chunk);
2880 + /* Delete the entry in the filestructure (if found) */
2881 + if (ret_val != -1)
2882 + yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
2884 + return ret_val;
2887 +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
2888 + int nand_chunk, int in_scan)
2890 + /* NB in_scan is zero unless scanning.
2891 + * For forward scanning, in_scan is > 0;
2892 + * for backward scanning in_scan is < 0
2894 + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
2895 + */
2897 + struct yaffs_tnode *tn;
2898 + struct yaffs_dev *dev = in->my_dev;
2899 + int existing_cunk;
2900 + struct yaffs_ext_tags existing_tags;
2901 + struct yaffs_ext_tags new_tags;
2902 + unsigned existing_serial, new_serial;
2904 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
2905 + /* Just ignore an attempt at putting a chunk into a non-file
2906 + * during scanning.
2907 + * If it is not during Scanning then something went wrong!
2908 + */
2909 + if (!in_scan) {
2910 + yaffs_trace(YAFFS_TRACE_ERROR,
2911 + "yaffs tragedy:attempt to put data chunk into a non-file"
2912 + );
2913 + BUG();
2916 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
2917 + return YAFFS_OK;
2920 + tn = yaffs_add_find_tnode_0(dev,
2921 + &in->variant.file_variant,
2922 + inode_chunk, NULL);
2923 + if (!tn)
2924 + return YAFFS_FAIL;
2926 + if (!nand_chunk)
2927 + /* Dummy insert, bail now */
2928 + return YAFFS_OK;
2930 + existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
2932 + if (in_scan != 0) {
2933 + /* If we're scanning then we need to test for duplicates
2934 + * NB This does not need to be efficient since it should only
2935 + * happen when the power fails during a write, then only one
2936 + * chunk should ever be affected.
2938 + * Correction for YAFFS2: This could happen quite a lot and we
2939 + * need to think about efficiency! TODO
2940 + * Update: For backward scanning we don't need to re-read tags
2941 + * so this is quite cheap.
2942 + */
2944 + if (existing_cunk > 0) {
2945 + /* NB Right now existing chunk will not be real
2946 + * chunk_id if the chunk group size > 1
2947 + * thus we have to do a FindChunkInFile to get the
2948 + * real chunk id.
2950 + * We have a duplicate now we need to decide which
2951 + * one to use:
2953 + * Backwards scanning YAFFS2: The old one is what
2954 + * we use, dump the new one.
2955 + * YAFFS1: Get both sets of tags and compare serial
2956 + * numbers.
2957 + */
2959 + if (in_scan > 0) {
2960 + /* Only do this for forward scanning */
2961 + yaffs_rd_chunk_tags_nand(dev,
2962 + nand_chunk,
2963 + NULL, &new_tags);
2965 + /* Do a proper find */
2966 + existing_cunk =
2967 + yaffs_find_chunk_in_file(in, inode_chunk,
2968 + &existing_tags);
2971 + if (existing_cunk <= 0) {
2972 + /*Hoosterman - how did this happen? */
2974 + yaffs_trace(YAFFS_TRACE_ERROR,
2975 + "yaffs tragedy: existing chunk < 0 in scan"
2976 + );
2980 + /* NB The deleted flags should be false, otherwise
2981 + * the chunks will not be loaded during a scan
2982 + */
2984 + if (in_scan > 0) {
2985 + new_serial = new_tags.serial_number;
2986 + existing_serial = existing_tags.serial_number;
2989 + if ((in_scan > 0) &&
2990 + (existing_cunk <= 0 ||
2991 + ((existing_serial + 1) & 3) == new_serial)) {
2992 + /* Forward scanning.
2993 + * Use new
2994 + * Delete the old one and drop through to
2995 + * update the tnode
2996 + */
2997 + yaffs_chunk_del(dev, existing_cunk, 1,
2998 + __LINE__);
2999 + } else {
3000 + /* Backward scanning or we want to use the
3001 + * existing one
3002 + * Delete the new one and return early so that
3003 + * the tnode isn't changed
3004 + */
3005 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
3006 + return YAFFS_OK;
3012 + if (existing_cunk == 0)
3013 + in->n_data_chunks++;
3015 + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
3017 + return YAFFS_OK;
3020 +static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
3022 + struct yaffs_block_info *the_block;
3023 + unsigned block_no;
3025 + yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
3027 + block_no = chunk / dev->param.chunks_per_block;
3028 + the_block = yaffs_get_block_info(dev, block_no);
3029 + if (the_block) {
3030 + the_block->soft_del_pages++;
3031 + dev->n_free_chunks++;
3032 + yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
3036 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
3037 + * the chunks in the file.
3038 + * All soft deleting does is increment the block's softdelete count and pulls
3039 + * the chunk out of the tnode.
3040 + * Thus, essentially this is the same as DeleteWorker except that the chunks
3041 + * are soft deleted.
3042 + */
3044 +static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
3045 + u32 level, int chunk_offset)
3047 + int i;
3048 + int the_chunk;
3049 + int all_done = 1;
3050 + struct yaffs_dev *dev = in->my_dev;
3052 + if (!tn)
3053 + return 1;
3055 + if (level > 0) {
3056 + for (i = YAFFS_NTNODES_INTERNAL - 1;
3057 + all_done && i >= 0;
3058 + i--) {
3059 + if (tn->internal[i]) {
3060 + all_done =
3061 + yaffs_soft_del_worker(in,
3062 + tn->internal[i],
3063 + level - 1,
3064 + (chunk_offset <<
3065 + YAFFS_TNODES_INTERNAL_BITS)
3066 + + i);
3067 + if (all_done) {
3068 + yaffs_free_tnode(dev,
3069 + tn->internal[i]);
3070 + tn->internal[i] = NULL;
3071 + } else {
3072 + /* Can this happen? */
3076 + return (all_done) ? 1 : 0;
3079 + /* level 0 */
3080 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
3081 + the_chunk = yaffs_get_group_base(dev, tn, i);
3082 + if (the_chunk) {
3083 + yaffs_soft_del_chunk(dev, the_chunk);
3084 + yaffs_load_tnode_0(dev, tn, i, 0);
3087 + return 1;
3090 +static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
3092 + struct yaffs_dev *dev = obj->my_dev;
3093 + struct yaffs_obj *parent;
3095 + yaffs_verify_obj_in_dir(obj);
3096 + parent = obj->parent;
3098 + yaffs_verify_dir(parent);
3100 + if (dev && dev->param.remove_obj_fn)
3101 + dev->param.remove_obj_fn(obj);
3103 + list_del_init(&obj->siblings);
3104 + obj->parent = NULL;
3106 + yaffs_verify_dir(parent);
3109 +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
3111 + if (!directory) {
3112 + yaffs_trace(YAFFS_TRACE_ALWAYS,
3113 + "tragedy: Trying to add an object to a null pointer directory"
3114 + );
3115 + BUG();
3116 + return;
3118 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
3119 + yaffs_trace(YAFFS_TRACE_ALWAYS,
3120 + "tragedy: Trying to add an object to a non-directory"
3121 + );
3122 + BUG();
3125 + if (obj->siblings.prev == NULL) {
3126 + /* Not initialised */
3127 + BUG();
3130 + yaffs_verify_dir(directory);
3132 + yaffs_remove_obj_from_dir(obj);
3134 + /* Now add it */
3135 + list_add(&obj->siblings, &directory->variant.dir_variant.children);
3136 + obj->parent = directory;
3138 + if (directory == obj->my_dev->unlinked_dir
3139 + || directory == obj->my_dev->del_dir) {
3140 + obj->unlinked = 1;
3141 + obj->my_dev->n_unlinked_files++;
3142 + obj->rename_allowed = 0;
3145 + yaffs_verify_dir(directory);
3146 + yaffs_verify_obj_in_dir(obj);
3149 +static int yaffs_change_obj_name(struct yaffs_obj *obj,
3150 + struct yaffs_obj *new_dir,
3151 + const YCHAR *new_name, int force, int shadows)
3153 + int unlink_op;
3154 + int del_op;
3155 + struct yaffs_obj *existing_target;
3157 + if (new_dir == NULL)
3158 + new_dir = obj->parent; /* use the old directory */
3160 + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
3161 + yaffs_trace(YAFFS_TRACE_ALWAYS,
3162 + "tragedy: yaffs_change_obj_name: new_dir is not a directory"
3163 + );
3164 + BUG();
3167 + unlink_op = (new_dir == obj->my_dev->unlinked_dir);
3168 + del_op = (new_dir == obj->my_dev->del_dir);
3170 + existing_target = yaffs_find_by_name(new_dir, new_name);
3172 + /* If the object is a file going into the unlinked directory,
3173 + * then it is OK to just stuff it in since duplicate names are OK.
3174 + * else only proceed if the new name does not exist and we're putting
3175 + * it into a directory.
3176 + */
3177 + if (!(unlink_op || del_op || force ||
3178 + shadows > 0 || !existing_target) ||
3179 + new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
3180 + return YAFFS_FAIL;
3182 + yaffs_set_obj_name(obj, new_name);
3183 + obj->dirty = 1;
3184 + yaffs_add_obj_to_dir(new_dir, obj);
3186 + if (unlink_op)
3187 + obj->unlinked = 1;
3189 + /* If it is a deletion then we mark it as a shrink for gc */
3190 + if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
3191 + return YAFFS_OK;
3193 + return YAFFS_FAIL;
3196 +/*------------------------ Short Operations Cache ------------------------------
3197 + * In many situations where there is no high level buffering a lot of
3198 + * reads might be short sequential reads, and a lot of writes may be short
3199 + * sequential writes. eg. scanning/writing a jpeg file.
3200 + * In these cases, a short read/write cache can provide a huge perfomance
3201 + * benefit with dumb-as-a-rock code.
3202 + * In Linux, the page cache provides read buffering and the short op cache
3203 + * provides write buffering.
3205 + * There are a small number (~10) of cache chunks per device so that we don't
3206 + * need a very intelligent search.
3207 + */
3209 +static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
3211 + struct yaffs_dev *dev = obj->my_dev;
3212 + int i;
3213 + struct yaffs_cache *cache;
3214 + int n_caches = obj->my_dev->param.n_caches;
3216 + for (i = 0; i < n_caches; i++) {
3217 + cache = &dev->cache[i];
3218 + if (cache->object == obj && cache->dirty)
3219 + return 1;
3222 + return 0;
3225 +static void yaffs_flush_file_cache(struct yaffs_obj *obj)
3227 + struct yaffs_dev *dev = obj->my_dev;
3228 + int lowest = -99; /* Stop compiler whining. */
3229 + int i;
3230 + struct yaffs_cache *cache;
3231 + int chunk_written = 0;
3232 + int n_caches = obj->my_dev->param.n_caches;
3234 + if (n_caches < 1)
3235 + return;
3236 + do {
3237 + cache = NULL;
3239 + /* Find the lowest dirty chunk for this object */
3240 + for (i = 0; i < n_caches; i++) {
3241 + if (dev->cache[i].object == obj &&
3242 + dev->cache[i].dirty) {
3243 + if (!cache ||
3244 + dev->cache[i].chunk_id < lowest) {
3245 + cache = &dev->cache[i];
3246 + lowest = cache->chunk_id;
3251 + if (cache && !cache->locked) {
3252 + /* Write it out and free it up */
3253 + chunk_written =
3254 + yaffs_wr_data_obj(cache->object,
3255 + cache->chunk_id,
3256 + cache->data,
3257 + cache->n_bytes, 1);
3258 + cache->dirty = 0;
3259 + cache->object = NULL;
3261 + } while (cache && chunk_written > 0);
3263 + if (cache)
3264 + /* Hoosterman, disk full while writing cache out. */
3265 + yaffs_trace(YAFFS_TRACE_ERROR,
3266 + "yaffs tragedy: no space during cache write");
3269 +/*yaffs_flush_whole_cache(dev)
3272 + */
3274 +void yaffs_flush_whole_cache(struct yaffs_dev *dev)
3276 + struct yaffs_obj *obj;
3277 + int n_caches = dev->param.n_caches;
3278 + int i;
3280 + /* Find a dirty object in the cache and flush it...
3281 + * until there are no further dirty objects.
3282 + */
3283 + do {
3284 + obj = NULL;
3285 + for (i = 0; i < n_caches && !obj; i++) {
3286 + if (dev->cache[i].object && dev->cache[i].dirty)
3287 + obj = dev->cache[i].object;
3289 + if (obj)
3290 + yaffs_flush_file_cache(obj);
3291 + } while (obj);
3295 +/* Grab us a cache chunk for use.
3296 + * First look for an empty one.
3297 + * Then look for the least recently used non-dirty one.
3298 + * Then look for the least recently used dirty one...., flush and look again.
3299 + */
3300 +static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
3302 + int i;
3304 + if (dev->param.n_caches > 0) {
3305 + for (i = 0; i < dev->param.n_caches; i++) {
3306 + if (!dev->cache[i].object)
3307 + return &dev->cache[i];
3310 + return NULL;
3313 +static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
3315 + struct yaffs_cache *cache;
3316 + struct yaffs_obj *the_obj;
3317 + int usage;
3318 + int i;
3319 + int pushout;
3321 + if (dev->param.n_caches < 1)
3322 + return NULL;
3324 + /* Try find a non-dirty one... */
3326 + cache = yaffs_grab_chunk_worker(dev);
3328 + if (!cache) {
3329 + /* They were all dirty, find the LRU object and flush
3330 + * its cache, then find again.
3331 + * NB what's here is not very accurate,
3332 + * we actually flush the object with the LRU chunk.
3333 + */
3335 + /* With locking we can't assume we can use entry zero,
3336 + * Set the_obj to a valid pointer for Coverity. */
3337 + the_obj = dev->cache[0].object;
3338 + usage = -1;
3339 + cache = NULL;
3340 + pushout = -1;
3342 + for (i = 0; i < dev->param.n_caches; i++) {
3343 + if (dev->cache[i].object &&
3344 + !dev->cache[i].locked &&
3345 + (dev->cache[i].last_use < usage ||
3346 + !cache)) {
3347 + usage = dev->cache[i].last_use;
3348 + the_obj = dev->cache[i].object;
3349 + cache = &dev->cache[i];
3350 + pushout = i;
3354 + if (!cache || cache->dirty) {
3355 + /* Flush and try again */
3356 + yaffs_flush_file_cache(the_obj);
3357 + cache = yaffs_grab_chunk_worker(dev);
3360 + return cache;
3363 +/* Find a cached chunk */
3364 +static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
3365 + int chunk_id)
3367 + struct yaffs_dev *dev = obj->my_dev;
3368 + int i;
3370 + if (dev->param.n_caches < 1)
3371 + return NULL;
3373 + for (i = 0; i < dev->param.n_caches; i++) {
3374 + if (dev->cache[i].object == obj &&
3375 + dev->cache[i].chunk_id == chunk_id) {
3376 + dev->cache_hits++;
3378 + return &dev->cache[i];
3381 + return NULL;
3384 +/* Mark the chunk for the least recently used algorithym */
3385 +static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
3386 + int is_write)
3388 + int i;
3390 + if (dev->param.n_caches < 1)
3391 + return;
3393 + if (dev->cache_last_use < 0 ||
3394 + dev->cache_last_use > 100000000) {
3395 + /* Reset the cache usages */
3396 + for (i = 1; i < dev->param.n_caches; i++)
3397 + dev->cache[i].last_use = 0;
3399 + dev->cache_last_use = 0;
3401 + dev->cache_last_use++;
3402 + cache->last_use = dev->cache_last_use;
3404 + if (is_write)
3405 + cache->dirty = 1;
3408 +/* Invalidate a single cache page.
3409 + * Do this when a whole page gets written,
3410 + * ie the short cache for this page is no longer valid.
3411 + */
3412 +static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
3414 + struct yaffs_cache *cache;
3416 + if (object->my_dev->param.n_caches > 0) {
3417 + cache = yaffs_find_chunk_cache(object, chunk_id);
3419 + if (cache)
3420 + cache->object = NULL;
3424 +/* Invalidate all the cache pages associated with this object
3425 + * Do this whenever ther file is deleted or resized.
3426 + */
3427 +static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
3429 + int i;
3430 + struct yaffs_dev *dev = in->my_dev;
3432 + if (dev->param.n_caches > 0) {
3433 + /* Invalidate it. */
3434 + for (i = 0; i < dev->param.n_caches; i++) {
3435 + if (dev->cache[i].object == in)
3436 + dev->cache[i].object = NULL;
3441 +static void yaffs_unhash_obj(struct yaffs_obj *obj)
3443 + int bucket;
3444 + struct yaffs_dev *dev = obj->my_dev;
3446 + /* If it is still linked into the bucket list, free from the list */
3447 + if (!list_empty(&obj->hash_link)) {
3448 + list_del_init(&obj->hash_link);
3449 + bucket = yaffs_hash_fn(obj->obj_id);
3450 + dev->obj_bucket[bucket].count--;
3454 +/* FreeObject frees up a Object and puts it back on the free list */
3455 +static void yaffs_free_obj(struct yaffs_obj *obj)
3457 + struct yaffs_dev *dev;
3459 + if (!obj) {
3460 + BUG();
3461 + return;
3463 + dev = obj->my_dev;
3464 + yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
3465 + obj, obj->my_inode);
3466 + if (obj->parent)
3467 + BUG();
3468 + if (!list_empty(&obj->siblings))
3469 + BUG();
3471 + if (obj->my_inode) {
3472 + /* We're still hooked up to a cached inode.
3473 + * Don't delete now, but mark for later deletion
3474 + */
3475 + obj->defered_free = 1;
3476 + return;
3479 + yaffs_unhash_obj(obj);
3481 + yaffs_free_raw_obj(dev, obj);
3482 + dev->n_obj--;
3483 + dev->checkpoint_blocks_required = 0; /* force recalculation */
3486 +void yaffs_handle_defered_free(struct yaffs_obj *obj)
3488 + if (obj->defered_free)
3489 + yaffs_free_obj(obj);
3492 +static int yaffs_generic_obj_del(struct yaffs_obj *in)
3494 + /* Iinvalidate the file's data in the cache, without flushing. */
3495 + yaffs_invalidate_whole_cache(in);
3497 + if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
3498 + /* Move to unlinked directory so we have a deletion record */
3499 + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
3500 + 0);
3503 + yaffs_remove_obj_from_dir(in);
3504 + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
3505 + in->hdr_chunk = 0;
3507 + yaffs_free_obj(in);
3508 + return YAFFS_OK;
3512 +static void yaffs_soft_del_file(struct yaffs_obj *obj)
3514 + if (!obj->deleted ||
3515 + obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
3516 + obj->soft_del)
3517 + return;
3519 + if (obj->n_data_chunks <= 0) {
3520 + /* Empty file with no duplicate object headers,
3521 + * just delete it immediately */
3522 + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
3523 + obj->variant.file_variant.top = NULL;
3524 + yaffs_trace(YAFFS_TRACE_TRACING,
3525 + "yaffs: Deleting empty file %d",
3526 + obj->obj_id);
3527 + yaffs_generic_obj_del(obj);
3528 + } else {
3529 + yaffs_soft_del_worker(obj,
3530 + obj->variant.file_variant.top,
3531 + obj->variant.
3532 + file_variant.top_level, 0);
3533 + obj->soft_del = 1;
3537 +/* Pruning removes any part of the file structure tree that is beyond the
3538 + * bounds of the file (ie that does not point to chunks).
3540 + * A file should only get pruned when its size is reduced.
3542 + * Before pruning, the chunks must be pulled from the tree and the
3543 + * level 0 tnode entries must be zeroed out.
3544 + * Could also use this for file deletion, but that's probably better handled
3545 + * by a special case.
3547 + * This function is recursive. For levels > 0 the function is called again on
3548 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
3549 + * If there is no data in a subtree then it is pruned.
3550 + */
3552 +static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
3553 + struct yaffs_tnode *tn, u32 level,
3554 + int del0)
3556 + int i;
3557 + int has_data;
3559 + if (!tn)
3560 + return tn;
3562 + has_data = 0;
3564 + if (level > 0) {
3565 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
3566 + if (tn->internal[i]) {
3567 + tn->internal[i] =
3568 + yaffs_prune_worker(dev,
3569 + tn->internal[i],
3570 + level - 1,
3571 + (i == 0) ? del0 : 1);
3574 + if (tn->internal[i])
3575 + has_data++;
3577 + } else {
3578 + int tnode_size_u32 = dev->tnode_size / sizeof(u32);
3579 + u32 *map = (u32 *) tn;
3581 + for (i = 0; !has_data && i < tnode_size_u32; i++) {
3582 + if (map[i])
3583 + has_data++;
3587 + if (has_data == 0 && del0) {
3588 + /* Free and return NULL */
3589 + yaffs_free_tnode(dev, tn);
3590 + tn = NULL;
3592 + return tn;
3595 +static int yaffs_prune_tree(struct yaffs_dev *dev,
3596 + struct yaffs_file_var *file_struct)
3598 + int i;
3599 + int has_data;
3600 + int done = 0;
3601 + struct yaffs_tnode *tn;
3603 + if (file_struct->top_level < 1)
3604 + return YAFFS_OK;
3606 + file_struct->top =
3607 + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
3609 + /* Now we have a tree with all the non-zero branches NULL but
3610 + * the height is the same as it was.
3611 + * Let's see if we can trim internal tnodes to shorten the tree.
3612 + * We can do this if only the 0th element in the tnode is in use
3613 + * (ie all the non-zero are NULL)
3614 + */
3616 + while (file_struct->top_level && !done) {
3617 + tn = file_struct->top;
3619 + has_data = 0;
3620 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
3621 + if (tn->internal[i])
3622 + has_data++;
3625 + if (!has_data) {
3626 + file_struct->top = tn->internal[0];
3627 + file_struct->top_level--;
3628 + yaffs_free_tnode(dev, tn);
3629 + } else {
3630 + done = 1;
3634 + return YAFFS_OK;
3637 +/*-------------------- End of File Structure functions.-------------------*/
3639 +/* alloc_empty_obj gets us a clean Object.*/
3640 +static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
3642 + struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
3644 + if (!obj)
3645 + return obj;
3647 + dev->n_obj++;
3649 + /* Now sweeten it up... */
3651 + memset(obj, 0, sizeof(struct yaffs_obj));
3652 + obj->being_created = 1;
3654 + obj->my_dev = dev;
3655 + obj->hdr_chunk = 0;
3656 + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
3657 + INIT_LIST_HEAD(&(obj->hard_links));
3658 + INIT_LIST_HEAD(&(obj->hash_link));
3659 + INIT_LIST_HEAD(&obj->siblings);
3661 + /* Now make the directory sane */
3662 + if (dev->root_dir) {
3663 + obj->parent = dev->root_dir;
3664 + list_add(&(obj->siblings),
3665 + &dev->root_dir->variant.dir_variant.children);
3668 + /* Add it to the lost and found directory.
3669 + * NB Can't put root or lost-n-found in lost-n-found so
3670 + * check if lost-n-found exists first
3671 + */
3672 + if (dev->lost_n_found)
3673 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
3675 + obj->being_created = 0;
3677 + dev->checkpoint_blocks_required = 0; /* force recalculation */
3679 + return obj;
3682 +static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
3684 + int i;
3685 + int l = 999;
3686 + int lowest = 999999;
3688 + /* Search for the shortest list or one that
3689 + * isn't too long.
3690 + */
3692 + for (i = 0; i < 10 && lowest > 4; i++) {
3693 + dev->bucket_finder++;
3694 + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
3695 + if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
3696 + lowest = dev->obj_bucket[dev->bucket_finder].count;
3697 + l = dev->bucket_finder;
3701 + return l;
3704 +static int yaffs_new_obj_id(struct yaffs_dev *dev)
3706 + int bucket = yaffs_find_nice_bucket(dev);
3707 + int found = 0;
3708 + struct list_head *i;
3709 + u32 n = (u32) bucket;
3711 + /* Now find an object value that has not already been taken
3712 + * by scanning the list.
3713 + */
3715 + while (!found) {
3716 + found = 1;
3717 + n += YAFFS_NOBJECT_BUCKETS;
3718 + if (1 || dev->obj_bucket[bucket].count > 0) {
3719 + list_for_each(i, &dev->obj_bucket[bucket].list) {
3720 + /* If there is already one in the list */
3721 + if (i && list_entry(i, struct yaffs_obj,
3722 + hash_link)->obj_id == n) {
3723 + found = 0;
3728 + return n;
3731 +static void yaffs_hash_obj(struct yaffs_obj *in)
3733 + int bucket = yaffs_hash_fn(in->obj_id);
3734 + struct yaffs_dev *dev = in->my_dev;
3736 + list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
3737 + dev->obj_bucket[bucket].count++;
3740 +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
3742 + int bucket = yaffs_hash_fn(number);
3743 + struct list_head *i;
3744 + struct yaffs_obj *in;
3746 + list_for_each(i, &dev->obj_bucket[bucket].list) {
3747 + /* Look if it is in the list */
3748 + in = list_entry(i, struct yaffs_obj, hash_link);
3749 + if (in->obj_id == number) {
3750 + /* Don't show if it is defered free */
3751 + if (in->defered_free)
3752 + return NULL;
3753 + return in;
3757 + return NULL;
3760 +static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
3761 + enum yaffs_obj_type type)
3763 + struct yaffs_obj *the_obj = NULL;
3764 + struct yaffs_tnode *tn = NULL;
3766 + if (number < 0)
3767 + number = yaffs_new_obj_id(dev);
3769 + if (type == YAFFS_OBJECT_TYPE_FILE) {
3770 + tn = yaffs_get_tnode(dev);
3771 + if (!tn)
3772 + return NULL;
3775 + the_obj = yaffs_alloc_empty_obj(dev);
3776 + if (!the_obj) {
3777 + if (tn)
3778 + yaffs_free_tnode(dev, tn);
3779 + return NULL;
3782 + the_obj->fake = 0;
3783 + the_obj->rename_allowed = 1;
3784 + the_obj->unlink_allowed = 1;
3785 + the_obj->obj_id = number;
3786 + yaffs_hash_obj(the_obj);
3787 + the_obj->variant_type = type;
3788 + yaffs_load_current_time(the_obj, 1, 1);
3790 + switch (type) {
3791 + case YAFFS_OBJECT_TYPE_FILE:
3792 + the_obj->variant.file_variant.file_size = 0;
3793 + the_obj->variant.file_variant.scanned_size = 0;
3794 + the_obj->variant.file_variant.shrink_size =
3795 + yaffs_max_file_size(dev);
3796 + the_obj->variant.file_variant.top_level = 0;
3797 + the_obj->variant.file_variant.top = tn;
3798 + break;
3799 + case YAFFS_OBJECT_TYPE_DIRECTORY:
3800 + INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
3801 + INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
3802 + break;
3803 + case YAFFS_OBJECT_TYPE_SYMLINK:
3804 + case YAFFS_OBJECT_TYPE_HARDLINK:
3805 + case YAFFS_OBJECT_TYPE_SPECIAL:
3806 + /* No action required */
3807 + break;
3808 + case YAFFS_OBJECT_TYPE_UNKNOWN:
3809 + /* todo this should not happen */
3810 + break;
3812 + return the_obj;
3815 +static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
3816 + int number, u32 mode)
3819 + struct yaffs_obj *obj =
3820 + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
3822 + if (!obj)
3823 + return NULL;
3825 + obj->fake = 1; /* it is fake so it might not use NAND */
3826 + obj->rename_allowed = 0;
3827 + obj->unlink_allowed = 0;
3828 + obj->deleted = 0;
3829 + obj->unlinked = 0;
3830 + obj->yst_mode = mode;
3831 + obj->my_dev = dev;
3832 + obj->hdr_chunk = 0; /* Not a valid chunk. */
3833 + return obj;
3838 +static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
3840 + int i;
3842 + dev->n_obj = 0;
3843 + dev->n_tnodes = 0;
3844 + yaffs_init_raw_tnodes_and_objs(dev);
3846 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
3847 + INIT_LIST_HEAD(&dev->obj_bucket[i].list);
3848 + dev->obj_bucket[i].count = 0;
3852 +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
3853 + int number,
3854 + enum yaffs_obj_type type)
3856 + struct yaffs_obj *the_obj = NULL;
3858 + if (number > 0)
3859 + the_obj = yaffs_find_by_number(dev, number);
3861 + if (!the_obj)
3862 + the_obj = yaffs_new_obj(dev, number, type);
3864 + return the_obj;
3868 +YCHAR *yaffs_clone_str(const YCHAR *str)
3870 + YCHAR *new_str = NULL;
3871 + int len;
3873 + if (!str)
3874 + str = _Y("");
3876 + len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
3877 + new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
3878 + if (new_str) {
3879 + strncpy(new_str, str, len);
3880 + new_str[len] = 0;
3882 + return new_str;
3886 + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
3887 + * link (ie. name) is created or deleted in the directory.
3889 + * ie.
3890 + * create dir/a : update dir's mtime/ctime
3891 + * rm dir/a: update dir's mtime/ctime
3892 + * modify dir/a: don't update dir's mtimme/ctime
3894 + * This can be handled immediately or defered. Defering helps reduce the number
3895 + * of updates when many files in a directory are changed within a brief period.
3897 + * If the directory updating is defered then yaffs_update_dirty_dirs must be
3898 + * called periodically.
3899 + */
3901 +static void yaffs_update_parent(struct yaffs_obj *obj)
3903 + struct yaffs_dev *dev;
3905 + if (!obj)
3906 + return;
3907 + dev = obj->my_dev;
3908 + obj->dirty = 1;
3909 + yaffs_load_current_time(obj, 0, 1);
3910 + if (dev->param.defered_dir_update) {
3911 + struct list_head *link = &obj->variant.dir_variant.dirty;
3913 + if (list_empty(link)) {
3914 + list_add(link, &dev->dirty_dirs);
3915 + yaffs_trace(YAFFS_TRACE_BACKGROUND,
3916 + "Added object %d to dirty directories",
3917 + obj->obj_id);
3920 + } else {
3921 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
3925 +void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
3927 + struct list_head *link;
3928 + struct yaffs_obj *obj;
3929 + struct yaffs_dir_var *d_s;
3930 + union yaffs_obj_var *o_v;
3932 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
3934 + while (!list_empty(&dev->dirty_dirs)) {
3935 + link = dev->dirty_dirs.next;
3936 + list_del_init(link);
3938 + d_s = list_entry(link, struct yaffs_dir_var, dirty);
3939 + o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
3940 + obj = list_entry(o_v, struct yaffs_obj, variant);
3942 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
3943 + obj->obj_id);
3945 + if (obj->dirty)
3946 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
3951 + * Mknod (create) a new object.
3952 + * equiv_obj only has meaning for a hard link;
3953 + * alias_str only has meaning for a symlink.
3954 + * rdev only has meaning for devices (a subset of special objects)
3955 + */
3957 +static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
3958 + struct yaffs_obj *parent,
3959 + const YCHAR *name,
3960 + u32 mode,
3961 + u32 uid,
3962 + u32 gid,
3963 + struct yaffs_obj *equiv_obj,
3964 + const YCHAR *alias_str, u32 rdev)
3966 + struct yaffs_obj *in;
3967 + YCHAR *str = NULL;
3968 + struct yaffs_dev *dev = parent->my_dev;
3970 + /* Check if the entry exists.
3971 + * If it does then fail the call since we don't want a dup. */
3972 + if (yaffs_find_by_name(parent, name))
3973 + return NULL;
3975 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
3976 + str = yaffs_clone_str(alias_str);
3977 + if (!str)
3978 + return NULL;
3981 + in = yaffs_new_obj(dev, -1, type);
3983 + if (!in) {
3984 + kfree(str);
3985 + return NULL;
3988 + in->hdr_chunk = 0;
3989 + in->valid = 1;
3990 + in->variant_type = type;
3992 + in->yst_mode = mode;
3994 + yaffs_attribs_init(in, gid, uid, rdev);
3996 + in->n_data_chunks = 0;
3998 + yaffs_set_obj_name(in, name);
3999 + in->dirty = 1;
4001 + yaffs_add_obj_to_dir(parent, in);
4003 + in->my_dev = parent->my_dev;
4005 + switch (type) {
4006 + case YAFFS_OBJECT_TYPE_SYMLINK:
4007 + in->variant.symlink_variant.alias = str;
4008 + break;
4009 + case YAFFS_OBJECT_TYPE_HARDLINK:
4010 + in->variant.hardlink_variant.equiv_obj = equiv_obj;
4011 + in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
4012 + list_add(&in->hard_links, &equiv_obj->hard_links);
4013 + break;
4014 + case YAFFS_OBJECT_TYPE_FILE:
4015 + case YAFFS_OBJECT_TYPE_DIRECTORY:
4016 + case YAFFS_OBJECT_TYPE_SPECIAL:
4017 + case YAFFS_OBJECT_TYPE_UNKNOWN:
4018 + /* do nothing */
4019 + break;
4022 + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
4023 + /* Could not create the object header, fail */
4024 + yaffs_del_obj(in);
4025 + in = NULL;
4028 + if (in)
4029 + yaffs_update_parent(parent);
4031 + return in;
4034 +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
4035 + const YCHAR *name, u32 mode, u32 uid,
4036 + u32 gid)
4038 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
4039 + uid, gid, NULL, NULL, 0);
4042 +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
4043 + u32 mode, u32 uid, u32 gid)
4045 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
4046 + mode, uid, gid, NULL, NULL, 0);
4049 +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
4050 + const YCHAR *name, u32 mode, u32 uid,
4051 + u32 gid, u32 rdev)
4053 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
4054 + uid, gid, NULL, NULL, rdev);
4057 +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
4058 + const YCHAR *name, u32 mode, u32 uid,
4059 + u32 gid, const YCHAR *alias)
4061 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
4062 + uid, gid, NULL, alias, 0);
4065 +/* yaffs_link_obj returns the object id of the equivalent object.*/
4066 +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
4067 + struct yaffs_obj *equiv_obj)
4069 + /* Get the real object in case we were fed a hard link obj */
4070 + equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
4072 + if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
4073 + parent, name, 0, 0, 0,
4074 + equiv_obj, NULL, 0))
4075 + return equiv_obj;
4077 + return NULL;
4083 +/*---------------------- Block Management and Page Allocation -------------*/
4085 +static void yaffs_deinit_blocks(struct yaffs_dev *dev)
4087 + if (dev->block_info_alt && dev->block_info)
4088 + vfree(dev->block_info);
4089 + else
4090 + kfree(dev->block_info);
4092 + dev->block_info_alt = 0;
4094 + dev->block_info = NULL;
4096 + if (dev->chunk_bits_alt && dev->chunk_bits)
4097 + vfree(dev->chunk_bits);
4098 + else
4099 + kfree(dev->chunk_bits);
4100 + dev->chunk_bits_alt = 0;
4101 + dev->chunk_bits = NULL;
4104 +static int yaffs_init_blocks(struct yaffs_dev *dev)
4106 + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
4108 + dev->block_info = NULL;
4109 + dev->chunk_bits = NULL;
4110 + dev->alloc_block = -1; /* force it to get a new one */
4112 + /* If the first allocation strategy fails, thry the alternate one */
4113 + dev->block_info =
4114 + kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
4115 + if (!dev->block_info) {
4116 + dev->block_info =
4117 + vmalloc(n_blocks * sizeof(struct yaffs_block_info));
4118 + dev->block_info_alt = 1;
4119 + } else {
4120 + dev->block_info_alt = 0;
4123 + if (!dev->block_info)
4124 + goto alloc_error;
4126 + /* Set up dynamic blockinfo stuff. Round up bytes. */
4127 + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
4128 + dev->chunk_bits =
4129 + kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
4130 + if (!dev->chunk_bits) {
4131 + dev->chunk_bits =
4132 + vmalloc(dev->chunk_bit_stride * n_blocks);
4133 + dev->chunk_bits_alt = 1;
4134 + } else {
4135 + dev->chunk_bits_alt = 0;
4137 + if (!dev->chunk_bits)
4138 + goto alloc_error;
4141 + memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
4142 + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
4143 + return YAFFS_OK;
4145 +alloc_error:
4146 + yaffs_deinit_blocks(dev);
4147 + return YAFFS_FAIL;
4151 +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
4153 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
4154 + int erased_ok = 0;
4155 + int i;
4157 + /* If the block is still healthy erase it and mark as clean.
4158 + * If the block has had a data failure, then retire it.
4159 + */
4161 + yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
4162 + "yaffs_block_became_dirty block %d state %d %s",
4163 + block_no, bi->block_state,
4164 + (bi->needs_retiring) ? "needs retiring" : "");
4166 + yaffs2_clear_oldest_dirty_seq(dev, bi);
4168 + bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
4170 + /* If this is the block being garbage collected then stop gc'ing */
4171 + if (block_no == dev->gc_block)
4172 + dev->gc_block = 0;
4174 + /* If this block is currently the best candidate for gc
4175 + * then drop as a candidate */
4176 + if (block_no == dev->gc_dirtiest) {
4177 + dev->gc_dirtiest = 0;
4178 + dev->gc_pages_in_use = 0;
4181 + if (!bi->needs_retiring) {
4182 + yaffs2_checkpt_invalidate(dev);
4183 + erased_ok = yaffs_erase_block(dev, block_no);
4184 + if (!erased_ok) {
4185 + dev->n_erase_failures++;
4186 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4187 + "**>> Erasure failed %d", block_no);
4191 + /* Verify erasure if needed */
4192 + if (erased_ok &&
4193 + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
4194 + !yaffs_skip_verification(dev))) {
4195 + for (i = 0; i < dev->param.chunks_per_block; i++) {
4196 + if (!yaffs_check_chunk_erased(dev,
4197 + block_no * dev->param.chunks_per_block + i)) {
4198 + yaffs_trace(YAFFS_TRACE_ERROR,
4199 + ">>Block %d erasure supposedly OK, but chunk %d not erased",
4200 + block_no, i);
4205 + if (!erased_ok) {
4206 + /* We lost a block of free space */
4207 + dev->n_free_chunks -= dev->param.chunks_per_block;
4208 + yaffs_retire_block(dev, block_no);
4209 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4210 + "**>> Block %d retired", block_no);
4211 + return;
4214 + /* Clean it up... */
4215 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
4216 + bi->seq_number = 0;
4217 + dev->n_erased_blocks++;
4218 + bi->pages_in_use = 0;
4219 + bi->soft_del_pages = 0;
4220 + bi->has_shrink_hdr = 0;
4221 + bi->skip_erased_check = 1; /* Clean, so no need to check */
4222 + bi->gc_prioritise = 0;
4223 + bi->has_summary = 0;
4225 + yaffs_clear_chunk_bits(dev, block_no);
4227 + yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
4230 +static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
4231 + struct yaffs_block_info *bi,
4232 + int old_chunk, u8 *buffer)
4234 + int new_chunk;
4235 + int mark_flash = 1;
4236 + struct yaffs_ext_tags tags;
4237 + struct yaffs_obj *object;
4238 + int matching_chunk;
4239 + int ret_val = YAFFS_OK;
4241 + memset(&tags, 0, sizeof(tags));
4242 + yaffs_rd_chunk_tags_nand(dev, old_chunk,
4243 + buffer, &tags);
4244 + object = yaffs_find_by_number(dev, tags.obj_id);
4246 + yaffs_trace(YAFFS_TRACE_GC_DETAIL,
4247 + "Collecting chunk in block %d, %d %d %d ",
4248 + dev->gc_chunk, tags.obj_id,
4249 + tags.chunk_id, tags.n_bytes);
4251 + if (object && !yaffs_skip_verification(dev)) {
4252 + if (tags.chunk_id == 0)
4253 + matching_chunk =
4254 + object->hdr_chunk;
4255 + else if (object->soft_del)
4256 + /* Defeat the test */
4257 + matching_chunk = old_chunk;
4258 + else
4259 + matching_chunk =
4260 + yaffs_find_chunk_in_file
4261 + (object, tags.chunk_id,
4262 + NULL);
4264 + if (old_chunk != matching_chunk)
4265 + yaffs_trace(YAFFS_TRACE_ERROR,
4266 + "gc: page in gc mismatch: %d %d %d %d",
4267 + old_chunk,
4268 + matching_chunk,
4269 + tags.obj_id,
4270 + tags.chunk_id);
4273 + if (!object) {
4274 + yaffs_trace(YAFFS_TRACE_ERROR,
4275 + "page %d in gc has no object: %d %d %d ",
4276 + old_chunk,
4277 + tags.obj_id, tags.chunk_id,
4278 + tags.n_bytes);
4281 + if (object &&
4282 + object->deleted &&
4283 + object->soft_del && tags.chunk_id != 0) {
4284 + /* Data chunk in a soft deleted file,
4285 + * throw it away.
4286 + * It's a soft deleted data chunk,
4287 + * No need to copy this, just forget
4288 + * about it and fix up the object.
4289 + */
4291 + /* Free chunks already includes
4292 + * softdeleted chunks, how ever this
4293 + * chunk is going to soon be really
4294 + * deleted which will increment free
4295 + * chunks. We have to decrement free
4296 + * chunks so this works out properly.
4297 + */
4298 + dev->n_free_chunks--;
4299 + bi->soft_del_pages--;
4301 + object->n_data_chunks--;
4302 + if (object->n_data_chunks <= 0) {
4303 + /* remeber to clean up obj */
4304 + dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
4305 + dev->n_clean_ups++;
4307 + mark_flash = 0;
4308 + } else if (object) {
4309 + /* It's either a data chunk in a live
4310 + * file or an ObjectHeader, so we're
4311 + * interested in it.
4312 + * NB Need to keep the ObjectHeaders of
4313 + * deleted files until the whole file
4314 + * has been deleted off
4315 + */
4316 + tags.serial_number++;
4317 + dev->n_gc_copies++;
4319 + if (tags.chunk_id == 0) {
4320 + /* It is an object Id,
4321 + * We need to nuke the
4322 + * shrinkheader flags since its
4323 + * work is done.
4324 + * Also need to clean up
4325 + * shadowing.
4326 + */
4327 + struct yaffs_obj_hdr *oh;
4328 + oh = (struct yaffs_obj_hdr *) buffer;
4330 + oh->is_shrink = 0;
4331 + tags.extra_is_shrink = 0;
4332 + oh->shadows_obj = 0;
4333 + oh->inband_shadowed_obj_id = 0;
4334 + tags.extra_shadows = 0;
4336 + /* Update file size */
4337 + if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
4338 + yaffs_oh_size_load(oh,
4339 + object->variant.file_variant.file_size);
4340 + tags.extra_file_size =
4341 + object->variant.file_variant.file_size;
4344 + yaffs_verify_oh(object, oh, &tags, 1);
4345 + new_chunk =
4346 + yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
4347 + } else {
4348 + new_chunk =
4349 + yaffs_write_new_chunk(dev, buffer, &tags, 1);
4352 + if (new_chunk < 0) {
4353 + ret_val = YAFFS_FAIL;
4354 + } else {
4356 + /* Now fix up the Tnodes etc. */
4358 + if (tags.chunk_id == 0) {
4359 + /* It's a header */
4360 + object->hdr_chunk = new_chunk;
4361 + object->serial = tags.serial_number;
4362 + } else {
4363 + /* It's a data chunk */
4364 + yaffs_put_chunk_in_file(object, tags.chunk_id,
4365 + new_chunk, 0);
4369 + if (ret_val == YAFFS_OK)
4370 + yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
4371 + return ret_val;
4374 +static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
4376 + int old_chunk;
4377 + int ret_val = YAFFS_OK;
4378 + int i;
4379 + int is_checkpt_block;
4380 + int max_copies;
4381 + int chunks_before = yaffs_get_erased_chunks(dev);
4382 + int chunks_after;
4383 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
4385 + is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
4387 + yaffs_trace(YAFFS_TRACE_TRACING,
4388 + "Collecting block %d, in use %d, shrink %d, whole_block %d",
4389 + block, bi->pages_in_use, bi->has_shrink_hdr,
4390 + whole_block);
4392 + /*yaffs_verify_free_chunks(dev); */
4394 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
4395 + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
4397 + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
4399 + dev->gc_disable = 1;
4401 + yaffs_summary_gc(dev, block);
4403 + if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
4404 + yaffs_trace(YAFFS_TRACE_TRACING,
4405 + "Collecting block %d that has no chunks in use",
4406 + block);
4407 + yaffs_block_became_dirty(dev, block);
4408 + } else {
4410 + u8 *buffer = yaffs_get_temp_buffer(dev);
4412 + yaffs_verify_blk(dev, bi, block);
4414 + max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
4415 + old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
4417 + for (/* init already done */ ;
4418 + ret_val == YAFFS_OK &&
4419 + dev->gc_chunk < dev->param.chunks_per_block &&
4420 + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
4421 + max_copies > 0;
4422 + dev->gc_chunk++, old_chunk++) {
4423 + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
4424 + /* Page is in use and might need to be copied */
4425 + max_copies--;
4426 + ret_val = yaffs_gc_process_chunk(dev, bi,
4427 + old_chunk, buffer);
4430 + yaffs_release_temp_buffer(dev, buffer);
4433 + yaffs_verify_collected_blk(dev, bi, block);
4435 + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
4436 + /*
4437 + * The gc did not complete. Set block state back to FULL
4438 + * because checkpointing does not restore gc.
4439 + */
4440 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
4441 + } else {
4442 + /* The gc completed. */
4443 + /* Do any required cleanups */
4444 + for (i = 0; i < dev->n_clean_ups; i++) {
4445 + /* Time to delete the file too */
4446 + struct yaffs_obj *object =
4447 + yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
4448 + if (object) {
4449 + yaffs_free_tnode(dev,
4450 + object->variant.file_variant.top);
4451 + object->variant.file_variant.top = NULL;
4452 + yaffs_trace(YAFFS_TRACE_GC,
4453 + "yaffs: About to finally delete object %d",
4454 + object->obj_id);
4455 + yaffs_generic_obj_del(object);
4456 + object->my_dev->n_deleted_files--;
4460 + chunks_after = yaffs_get_erased_chunks(dev);
4461 + if (chunks_before >= chunks_after)
4462 + yaffs_trace(YAFFS_TRACE_GC,
4463 + "gc did not increase free chunks before %d after %d",
4464 + chunks_before, chunks_after);
4465 + dev->gc_block = 0;
4466 + dev->gc_chunk = 0;
4467 + dev->n_clean_ups = 0;
4470 + dev->gc_disable = 0;
4472 + return ret_val;
4476 + * find_gc_block() selects the dirtiest block (or close enough)
4477 + * for garbage collection.
4478 + */
4480 +static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
4481 + int aggressive, int background)
4483 + int i;
4484 + int iterations;
4485 + unsigned selected = 0;
4486 + int prioritised = 0;
4487 + int prioritised_exist = 0;
4488 + struct yaffs_block_info *bi;
4489 + int threshold;
4491 + /* First let's see if we need to grab a prioritised block */
4492 + if (dev->has_pending_prioritised_gc && !aggressive) {
4493 + dev->gc_dirtiest = 0;
4494 + bi = dev->block_info;
4495 + for (i = dev->internal_start_block;
4496 + i <= dev->internal_end_block && !selected; i++) {
4498 + if (bi->gc_prioritise) {
4499 + prioritised_exist = 1;
4500 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
4501 + yaffs_block_ok_for_gc(dev, bi)) {
4502 + selected = i;
4503 + prioritised = 1;
4506 + bi++;
4509 + /*
4510 + * If there is a prioritised block and none was selected then
4511 + * this happened because there is at least one old dirty block
4512 + * gumming up the works. Let's gc the oldest dirty block.
4513 + */
4515 + if (prioritised_exist &&
4516 + !selected && dev->oldest_dirty_block > 0)
4517 + selected = dev->oldest_dirty_block;
4519 + if (!prioritised_exist) /* None found, so we can clear this */
4520 + dev->has_pending_prioritised_gc = 0;
4523 + /* If we're doing aggressive GC then we are happy to take a less-dirty
4524 + * block, and search harder.
4525 + * else (leasurely gc), then we only bother to do this if the
4526 + * block has only a few pages in use.
4527 + */
4529 + if (!selected) {
4530 + int pages_used;
4531 + int n_blocks =
4532 + dev->internal_end_block - dev->internal_start_block + 1;
4533 + if (aggressive) {
4534 + threshold = dev->param.chunks_per_block;
4535 + iterations = n_blocks;
4536 + } else {
4537 + int max_threshold;
4539 + if (background)
4540 + max_threshold = dev->param.chunks_per_block / 2;
4541 + else
4542 + max_threshold = dev->param.chunks_per_block / 8;
4544 + if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
4545 + max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
4547 + threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
4548 + if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
4549 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
4550 + if (threshold > max_threshold)
4551 + threshold = max_threshold;
4553 + iterations = n_blocks / 16 + 1;
4554 + if (iterations > 100)
4555 + iterations = 100;
4558 + for (i = 0;
4559 + i < iterations &&
4560 + (dev->gc_dirtiest < 1 ||
4561 + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
4562 + i++) {
4563 + dev->gc_block_finder++;
4564 + if (dev->gc_block_finder < dev->internal_start_block ||
4565 + dev->gc_block_finder > dev->internal_end_block)
4566 + dev->gc_block_finder =
4567 + dev->internal_start_block;
4569 + bi = yaffs_get_block_info(dev, dev->gc_block_finder);
4571 + pages_used = bi->pages_in_use - bi->soft_del_pages;
4573 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
4574 + pages_used < dev->param.chunks_per_block &&
4575 + (dev->gc_dirtiest < 1 ||
4576 + pages_used < dev->gc_pages_in_use) &&
4577 + yaffs_block_ok_for_gc(dev, bi)) {
4578 + dev->gc_dirtiest = dev->gc_block_finder;
4579 + dev->gc_pages_in_use = pages_used;
4583 + if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
4584 + selected = dev->gc_dirtiest;
4587 + /*
4588 + * If nothing has been selected for a while, try the oldest dirty
4589 + * because that's gumming up the works.
4590 + */
4592 + if (!selected && dev->param.is_yaffs2 &&
4593 + dev->gc_not_done >= (background ? 10 : 20)) {
4594 + yaffs2_find_oldest_dirty_seq(dev);
4595 + if (dev->oldest_dirty_block > 0) {
4596 + selected = dev->oldest_dirty_block;
4597 + dev->gc_dirtiest = selected;
4598 + dev->oldest_dirty_gc_count++;
4599 + bi = yaffs_get_block_info(dev, selected);
4600 + dev->gc_pages_in_use =
4601 + bi->pages_in_use - bi->soft_del_pages;
4602 + } else {
4603 + dev->gc_not_done = 0;
4607 + if (selected) {
4608 + yaffs_trace(YAFFS_TRACE_GC,
4609 + "GC Selected block %d with %d free, prioritised:%d",
4610 + selected,
4611 + dev->param.chunks_per_block - dev->gc_pages_in_use,
4612 + prioritised);
4614 + dev->n_gc_blocks++;
4615 + if (background)
4616 + dev->bg_gcs++;
4618 + dev->gc_dirtiest = 0;
4619 + dev->gc_pages_in_use = 0;
4620 + dev->gc_not_done = 0;
4621 + if (dev->refresh_skip > 0)
4622 + dev->refresh_skip--;
4623 + } else {
4624 + dev->gc_not_done++;
4625 + yaffs_trace(YAFFS_TRACE_GC,
4626 + "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
4627 + dev->gc_block_finder, dev->gc_not_done, threshold,
4628 + dev->gc_dirtiest, dev->gc_pages_in_use,
4629 + dev->oldest_dirty_block, background ? " bg" : "");
4632 + return selected;
4635 +/* New garbage collector
4636 + * If we're very low on erased blocks then we do aggressive garbage collection
4637 + * otherwise we do "leasurely" garbage collection.
4638 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
4639 + * Passive gc only inspects smaller areas and only accepts more dirty blocks.
4641 + * The idea is to help clear out space in a more spread-out manner.
4642 + * Dunno if it really does anything useful.
4643 + */
4644 +static int yaffs_check_gc(struct yaffs_dev *dev, int background)
4646 + int aggressive = 0;
4647 + int gc_ok = YAFFS_OK;
4648 + int max_tries = 0;
4649 + int min_erased;
4650 + int erased_chunks;
4651 + int checkpt_block_adjust;
4653 + if (dev->param.gc_control_fn &&
4654 + (dev->param.gc_control_fn(dev) & 1) == 0)
4655 + return YAFFS_OK;
4657 + if (dev->gc_disable)
4658 + /* Bail out so we don't get recursive gc */
4659 + return YAFFS_OK;
4661 + /* This loop should pass the first time.
4662 + * Only loops here if the collection does not increase space.
4663 + */
4665 + do {
4666 + max_tries++;
4668 + checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
4670 + min_erased =
4671 + dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
4672 + erased_chunks =
4673 + dev->n_erased_blocks * dev->param.chunks_per_block;
4675 + /* If we need a block soon then do aggressive gc. */
4676 + if (dev->n_erased_blocks < min_erased)
4677 + aggressive = 1;
4678 + else {
4679 + if (!background
4680 + && erased_chunks > (dev->n_free_chunks / 4))
4681 + break;
4683 + if (dev->gc_skip > 20)
4684 + dev->gc_skip = 20;
4685 + if (erased_chunks < dev->n_free_chunks / 2 ||
4686 + dev->gc_skip < 1 || background)
4687 + aggressive = 0;
4688 + else {
4689 + dev->gc_skip--;
4690 + break;
4694 + dev->gc_skip = 5;
4696 + /* If we don't already have a block being gc'd then see if we
4697 + * should start another */
4699 + if (dev->gc_block < 1 && !aggressive) {
4700 + dev->gc_block = yaffs2_find_refresh_block(dev);
4701 + dev->gc_chunk = 0;
4702 + dev->n_clean_ups = 0;
4704 + if (dev->gc_block < 1) {
4705 + dev->gc_block =
4706 + yaffs_find_gc_block(dev, aggressive, background);
4707 + dev->gc_chunk = 0;
4708 + dev->n_clean_ups = 0;
4711 + if (dev->gc_block > 0) {
4712 + dev->all_gcs++;
4713 + if (!aggressive)
4714 + dev->passive_gc_count++;
4716 + yaffs_trace(YAFFS_TRACE_GC,
4717 + "yaffs: GC n_erased_blocks %d aggressive %d",
4718 + dev->n_erased_blocks, aggressive);
4720 + gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
4723 + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
4724 + dev->gc_block > 0) {
4725 + yaffs_trace(YAFFS_TRACE_GC,
4726 + "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
4727 + dev->n_erased_blocks, max_tries,
4728 + dev->gc_block);
4730 + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
4731 + (dev->gc_block > 0) && (max_tries < 2));
4733 + return aggressive ? gc_ok : YAFFS_OK;
4737 + * yaffs_bg_gc()
4738 + * Garbage collects. Intended to be called from a background thread.
4739 + * Returns non-zero if at least half the free chunks are erased.
4740 + */
4741 +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
4743 + int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
4745 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
4747 + yaffs_check_gc(dev, 1);
4748 + return erased_chunks > dev->n_free_chunks / 2;
4751 +/*-------------------- Data file manipulation -----------------*/
4753 +static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
4755 + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
4757 + if (nand_chunk >= 0)
4758 + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
4759 + buffer, NULL);
4760 + else {
4761 + yaffs_trace(YAFFS_TRACE_NANDACCESS,
4762 + "Chunk %d not found zero instead",
4763 + nand_chunk);
4764 + /* get sane (zero) data if you read a hole */
4765 + memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
4766 + return 0;
4771 +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
4772 + int lyn)
4774 + int block;
4775 + int page;
4776 + struct yaffs_ext_tags tags;
4777 + struct yaffs_block_info *bi;
4779 + if (chunk_id <= 0)
4780 + return;
4782 + dev->n_deletions++;
4783 + block = chunk_id / dev->param.chunks_per_block;
4784 + page = chunk_id % dev->param.chunks_per_block;
4786 + if (!yaffs_check_chunk_bit(dev, block, page))
4787 + yaffs_trace(YAFFS_TRACE_VERIFY,
4788 + "Deleting invalid chunk %d", chunk_id);
4790 + bi = yaffs_get_block_info(dev, block);
4792 + yaffs2_update_oldest_dirty_seq(dev, block, bi);
4794 + yaffs_trace(YAFFS_TRACE_DELETION,
4795 + "line %d delete of chunk %d",
4796 + lyn, chunk_id);
4798 + if (!dev->param.is_yaffs2 && mark_flash &&
4799 + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
4801 + memset(&tags, 0, sizeof(tags));
4802 + tags.is_deleted = 1;
4803 + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
4804 + yaffs_handle_chunk_update(dev, chunk_id, &tags);
4805 + } else {
4806 + dev->n_unmarked_deletions++;
4809 + /* Pull out of the management area.
4810 + * If the whole block became dirty, this will kick off an erasure.
4811 + */
4812 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
4813 + bi->block_state == YAFFS_BLOCK_STATE_FULL ||
4814 + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
4815 + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
4816 + dev->n_free_chunks++;
4817 + yaffs_clear_chunk_bit(dev, block, page);
4818 + bi->pages_in_use--;
4820 + if (bi->pages_in_use == 0 &&
4821 + !bi->has_shrink_hdr &&
4822 + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
4823 + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
4824 + yaffs_block_became_dirty(dev, block);
4829 +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
4830 + const u8 *buffer, int n_bytes, int use_reserve)
4832 + /* Find old chunk Need to do this to get serial number
4833 + * Write new one and patch into tree.
4834 + * Invalidate old tags.
4835 + */
4837 + int prev_chunk_id;
4838 + struct yaffs_ext_tags prev_tags;
4839 + int new_chunk_id;
4840 + struct yaffs_ext_tags new_tags;
4841 + struct yaffs_dev *dev = in->my_dev;
4843 + yaffs_check_gc(dev, 0);
4845 + /* Get the previous chunk at this location in the file if it exists.
4846 + * If it does not exist then put a zero into the tree. This creates
4847 + * the tnode now, rather than later when it is harder to clean up.
4848 + */
4849 + prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
4850 + if (prev_chunk_id < 1 &&
4851 + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
4852 + return 0;
4854 + /* Set up new tags */
4855 + memset(&new_tags, 0, sizeof(new_tags));
4857 + new_tags.chunk_id = inode_chunk;
4858 + new_tags.obj_id = in->obj_id;
4859 + new_tags.serial_number =
4860 + (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
4861 + new_tags.n_bytes = n_bytes;
4863 + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
4864 + yaffs_trace(YAFFS_TRACE_ERROR,
4865 + "Writing %d bytes to chunk!!!!!!!!!",
4866 + n_bytes);
4867 + BUG();
4870 + new_chunk_id =
4871 + yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
4873 + if (new_chunk_id > 0) {
4874 + yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
4876 + if (prev_chunk_id > 0)
4877 + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
4879 + yaffs_verify_file_sane(in);
4881 + return new_chunk_id;
4887 +static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
4888 + const YCHAR *name, const void *value, int size,
4889 + int flags)
4891 + struct yaffs_xattr_mod xmod;
4892 + int result;
4894 + xmod.set = set;
4895 + xmod.name = name;
4896 + xmod.data = value;
4897 + xmod.size = size;
4898 + xmod.flags = flags;
4899 + xmod.result = -ENOSPC;
4901 + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
4903 + if (result > 0)
4904 + return xmod.result;
4905 + else
4906 + return -ENOSPC;
4909 +static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
4910 + struct yaffs_xattr_mod *xmod)
4912 + int retval = 0;
4913 + int x_offs = sizeof(struct yaffs_obj_hdr);
4914 + struct yaffs_dev *dev = obj->my_dev;
4915 + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
4916 + char *x_buffer = buffer + x_offs;
4918 + if (xmod->set)
4919 + retval =
4920 + nval_set(x_buffer, x_size, xmod->name, xmod->data,
4921 + xmod->size, xmod->flags);
4922 + else
4923 + retval = nval_del(x_buffer, x_size, xmod->name);
4925 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
4926 + obj->xattr_known = 1;
4927 + xmod->result = retval;
4929 + return retval;
4932 +static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
4933 + void *value, int size)
4935 + char *buffer = NULL;
4936 + int result;
4937 + struct yaffs_ext_tags tags;
4938 + struct yaffs_dev *dev = obj->my_dev;
4939 + int x_offs = sizeof(struct yaffs_obj_hdr);
4940 + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
4941 + char *x_buffer;
4942 + int retval = 0;
4944 + if (obj->hdr_chunk < 1)
4945 + return -ENODATA;
4947 + /* If we know that the object has no xattribs then don't do all the
4948 + * reading and parsing.
4949 + */
4950 + if (obj->xattr_known && !obj->has_xattr) {
4951 + if (name)
4952 + return -ENODATA;
4953 + else
4954 + return 0;
4957 + buffer = (char *)yaffs_get_temp_buffer(dev);
4958 + if (!buffer)
4959 + return -ENOMEM;
4961 + result =
4962 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
4964 + if (result != YAFFS_OK)
4965 + retval = -ENOENT;
4966 + else {
4967 + x_buffer = buffer + x_offs;
4969 + if (!obj->xattr_known) {
4970 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
4971 + obj->xattr_known = 1;
4974 + if (name)
4975 + retval = nval_get(x_buffer, x_size, name, value, size);
4976 + else
4977 + retval = nval_list(x_buffer, x_size, value, size);
4979 + yaffs_release_temp_buffer(dev, (u8 *) buffer);
4980 + return retval;
4983 +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
4984 + const void *value, int size, int flags)
4986 + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
4989 +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
4991 + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
4994 +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
4995 + int size)
4997 + return yaffs_do_xattrib_fetch(obj, name, value, size);
5000 +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
5002 + return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
5005 +static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
5007 + u8 *buf;
5008 + struct yaffs_obj_hdr *oh;
5009 + struct yaffs_dev *dev;
5010 + struct yaffs_ext_tags tags;
5011 + int result;
5012 + int alloc_failed = 0;
5014 + if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
5015 + return;
5017 + dev = in->my_dev;
5018 + in->lazy_loaded = 0;
5019 + buf = yaffs_get_temp_buffer(dev);
5021 + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
5022 + oh = (struct yaffs_obj_hdr *)buf;
5024 + in->yst_mode = oh->yst_mode;
5025 + yaffs_load_attribs(in, oh);
5026 + yaffs_set_obj_name_from_oh(in, oh);
5028 + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
5029 + in->variant.symlink_variant.alias =
5030 + yaffs_clone_str(oh->alias);
5031 + if (!in->variant.symlink_variant.alias)
5032 + alloc_failed = 1; /* Not returned */
5034 + yaffs_release_temp_buffer(dev, buf);
5037 +static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
5038 + const YCHAR *oh_name, int buff_size)
5040 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
5041 + if (dev->param.auto_unicode) {
5042 + if (*oh_name) {
5043 + /* It is an ASCII name, do an ASCII to
5044 + * unicode conversion */
5045 + const char *ascii_oh_name = (const char *)oh_name;
5046 + int n = buff_size - 1;
5047 + while (n > 0 && *ascii_oh_name) {
5048 + *name = *ascii_oh_name;
5049 + name++;
5050 + ascii_oh_name++;
5051 + n--;
5053 + } else {
5054 + strncpy(name, oh_name + 1, buff_size - 1);
5056 + } else {
5057 +#else
5058 + (void) dev;
5060 +#endif
5061 + strncpy(name, oh_name, buff_size - 1);
5065 +static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
5066 + const YCHAR *name)
5068 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
5070 + int is_ascii;
5071 + YCHAR *w;
5073 + if (dev->param.auto_unicode) {
5075 + is_ascii = 1;
5076 + w = name;
5078 + /* Figure out if the name will fit in ascii character set */
5079 + while (is_ascii && *w) {
5080 + if ((*w) & 0xff00)
5081 + is_ascii = 0;
5082 + w++;
5085 + if (is_ascii) {
5086 + /* It is an ASCII name, so convert unicode to ascii */
5087 + char *ascii_oh_name = (char *)oh_name;
5088 + int n = YAFFS_MAX_NAME_LENGTH - 1;
5089 + while (n > 0 && *name) {
5090 + *ascii_oh_name = *name;
5091 + name++;
5092 + ascii_oh_name++;
5093 + n--;
5095 + } else {
5096 + /* Unicode name, so save starting at the second YCHAR */
5097 + *oh_name = 0;
5098 + strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
5100 + } else {
5101 +#else
5102 + dev = dev;
5104 +#endif
5105 + strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
5109 +/* UpdateObjectHeader updates the header on NAND for an object.
5110 + * If name is not NULL, then that new name is used.
5111 + */
5112 +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
5113 + int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
5116 + struct yaffs_block_info *bi;
5117 + struct yaffs_dev *dev = in->my_dev;
5118 + int prev_chunk_id;
5119 + int ret_val = 0;
5120 + int result = 0;
5121 + int new_chunk_id;
5122 + struct yaffs_ext_tags new_tags;
5123 + struct yaffs_ext_tags old_tags;
5124 + const YCHAR *alias = NULL;
5125 + u8 *buffer = NULL;
5126 + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
5127 + struct yaffs_obj_hdr *oh = NULL;
5128 + loff_t file_size = 0;
5130 + strcpy(old_name, _Y("silly old name"));
5132 + if (in->fake && in != dev->root_dir && !force && !xmod)
5133 + return ret_val;
5135 + yaffs_check_gc(dev, 0);
5136 + yaffs_check_obj_details_loaded(in);
5138 + buffer = yaffs_get_temp_buffer(in->my_dev);
5139 + oh = (struct yaffs_obj_hdr *)buffer;
5141 + prev_chunk_id = in->hdr_chunk;
5143 + if (prev_chunk_id > 0) {
5144 + result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
5145 + buffer, &old_tags);
5147 + yaffs_verify_oh(in, oh, &old_tags, 0);
5148 + memcpy(old_name, oh->name, sizeof(oh->name));
5149 + memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
5150 + } else {
5151 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
5154 + oh->type = in->variant_type;
5155 + oh->yst_mode = in->yst_mode;
5156 + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
5158 + yaffs_load_attribs_oh(oh, in);
5160 + if (in->parent)
5161 + oh->parent_obj_id = in->parent->obj_id;
5162 + else
5163 + oh->parent_obj_id = 0;
5165 + if (name && *name) {
5166 + memset(oh->name, 0, sizeof(oh->name));
5167 + yaffs_load_oh_from_name(dev, oh->name, name);
5168 + } else if (prev_chunk_id > 0) {
5169 + memcpy(oh->name, old_name, sizeof(oh->name));
5170 + } else {
5171 + memset(oh->name, 0, sizeof(oh->name));
5174 + oh->is_shrink = is_shrink;
5176 + switch (in->variant_type) {
5177 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5178 + /* Should not happen */
5179 + break;
5180 + case YAFFS_OBJECT_TYPE_FILE:
5181 + if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
5182 + oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
5183 + file_size = in->variant.file_variant.file_size;
5184 + yaffs_oh_size_load(oh, file_size);
5185 + break;
5186 + case YAFFS_OBJECT_TYPE_HARDLINK:
5187 + oh->equiv_id = in->variant.hardlink_variant.equiv_id;
5188 + break;
5189 + case YAFFS_OBJECT_TYPE_SPECIAL:
5190 + /* Do nothing */
5191 + break;
5192 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5193 + /* Do nothing */
5194 + break;
5195 + case YAFFS_OBJECT_TYPE_SYMLINK:
5196 + alias = in->variant.symlink_variant.alias;
5197 + if (!alias)
5198 + alias = _Y("no alias");
5199 + strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
5200 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
5201 + break;
5204 + /* process any xattrib modifications */
5205 + if (xmod)
5206 + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
5208 + /* Tags */
5209 + memset(&new_tags, 0, sizeof(new_tags));
5210 + in->serial++;
5211 + new_tags.chunk_id = 0;
5212 + new_tags.obj_id = in->obj_id;
5213 + new_tags.serial_number = in->serial;
5215 + /* Add extra info for file header */
5216 + new_tags.extra_available = 1;
5217 + new_tags.extra_parent_id = oh->parent_obj_id;
5218 + new_tags.extra_file_size = file_size;
5219 + new_tags.extra_is_shrink = oh->is_shrink;
5220 + new_tags.extra_equiv_id = oh->equiv_id;
5221 + new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
5222 + new_tags.extra_obj_type = in->variant_type;
5223 + yaffs_verify_oh(in, oh, &new_tags, 1);
5225 + /* Create new chunk in NAND */
5226 + new_chunk_id =
5227 + yaffs_write_new_chunk(dev, buffer, &new_tags,
5228 + (prev_chunk_id > 0) ? 1 : 0);
5230 + if (buffer)
5231 + yaffs_release_temp_buffer(dev, buffer);
5233 + if (new_chunk_id < 0)
5234 + return new_chunk_id;
5236 + in->hdr_chunk = new_chunk_id;
5238 + if (prev_chunk_id > 0)
5239 + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
5241 + if (!yaffs_obj_cache_dirty(in))
5242 + in->dirty = 0;
5244 + /* If this was a shrink, then mark the block
5245 + * that the chunk lives on */
5246 + if (is_shrink) {
5247 + bi = yaffs_get_block_info(in->my_dev,
5248 + new_chunk_id /
5249 + in->my_dev->param.chunks_per_block);
5250 + bi->has_shrink_hdr = 1;
5254 + return new_chunk_id;
5257 +/*--------------------- File read/write ------------------------
5258 + * Read and write have very similar structures.
5259 + * In general the read/write has three parts to it
5260 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
5261 + * Some complete chunks
5262 + * An incomplete chunk to end off with
5264 + * Curve-balls: the first chunk might also be the last chunk.
5265 + */
5267 +int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
5269 + int chunk;
5270 + u32 start;
5271 + int n_copy;
5272 + int n = n_bytes;
5273 + int n_done = 0;
5274 + struct yaffs_cache *cache;
5275 + struct yaffs_dev *dev;
5277 + dev = in->my_dev;
5279 + while (n > 0) {
5280 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
5281 + chunk++;
5283 + /* OK now check for the curveball where the start and end are in
5284 + * the same chunk.
5285 + */
5286 + if ((start + n) < dev->data_bytes_per_chunk)
5287 + n_copy = n;
5288 + else
5289 + n_copy = dev->data_bytes_per_chunk - start;
5291 + cache = yaffs_find_chunk_cache(in, chunk);
5293 + /* If the chunk is already in the cache or it is less than
5294 + * a whole chunk or we're using inband tags then use the cache
5295 + * (if there is caching) else bypass the cache.
5296 + */
5297 + if (cache || n_copy != dev->data_bytes_per_chunk ||
5298 + dev->param.inband_tags) {
5299 + if (dev->param.n_caches > 0) {
5301 + /* If we can't find the data in the cache,
5302 + * then load it up. */
5304 + if (!cache) {
5305 + cache =
5306 + yaffs_grab_chunk_cache(in->my_dev);
5307 + cache->object = in;
5308 + cache->chunk_id = chunk;
5309 + cache->dirty = 0;
5310 + cache->locked = 0;
5311 + yaffs_rd_data_obj(in, chunk,
5312 + cache->data);
5313 + cache->n_bytes = 0;
5316 + yaffs_use_cache(dev, cache, 0);
5318 + cache->locked = 1;
5320 + memcpy(buffer, &cache->data[start], n_copy);
5322 + cache->locked = 0;
5323 + } else {
5324 + /* Read into the local buffer then copy.. */
5326 + u8 *local_buffer =
5327 + yaffs_get_temp_buffer(dev);
5328 + yaffs_rd_data_obj(in, chunk, local_buffer);
5330 + memcpy(buffer, &local_buffer[start], n_copy);
5332 + yaffs_release_temp_buffer(dev, local_buffer);
5334 + } else {
5335 + /* A full chunk. Read directly into the buffer. */
5336 + yaffs_rd_data_obj(in, chunk, buffer);
5338 + n -= n_copy;
5339 + offset += n_copy;
5340 + buffer += n_copy;
5341 + n_done += n_copy;
5343 + return n_done;
5346 +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
5347 + int n_bytes, int write_through)
5350 + int chunk;
5351 + u32 start;
5352 + int n_copy;
5353 + int n = n_bytes;
5354 + int n_done = 0;
5355 + int n_writeback;
5356 + loff_t start_write = offset;
5357 + int chunk_written = 0;
5358 + u32 n_bytes_read;
5359 + loff_t chunk_start;
5360 + struct yaffs_dev *dev;
5362 + dev = in->my_dev;
5364 + while (n > 0 && chunk_written >= 0) {
5365 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
5367 + if (((loff_t)chunk) *
5368 + dev->data_bytes_per_chunk + start != offset ||
5369 + start >= dev->data_bytes_per_chunk) {
5370 + yaffs_trace(YAFFS_TRACE_ERROR,
5371 + "AddrToChunk of offset %lld gives chunk %d start %d",
5372 + offset, chunk, start);
5374 + chunk++; /* File pos to chunk in file offset */
5376 + /* OK now check for the curveball where the start and end are in
5377 + * the same chunk.
5378 + */
5380 + if ((start + n) < dev->data_bytes_per_chunk) {
5381 + n_copy = n;
5383 + /* Now calculate how many bytes to write back....
5384 + * If we're overwriting and not writing to then end of
5385 + * file then we need to write back as much as was there
5386 + * before.
5387 + */
5389 + chunk_start = (((loff_t)(chunk - 1)) *
5390 + dev->data_bytes_per_chunk);
5392 + if (chunk_start > in->variant.file_variant.file_size)
5393 + n_bytes_read = 0; /* Past end of file */
5394 + else
5395 + n_bytes_read =
5396 + in->variant.file_variant.file_size -
5397 + chunk_start;
5399 + if (n_bytes_read > dev->data_bytes_per_chunk)
5400 + n_bytes_read = dev->data_bytes_per_chunk;
5402 + n_writeback =
5403 + (n_bytes_read >
5404 + (start + n)) ? n_bytes_read : (start + n);
5406 + if (n_writeback < 0 ||
5407 + n_writeback > dev->data_bytes_per_chunk)
5408 + BUG();
5410 + } else {
5411 + n_copy = dev->data_bytes_per_chunk - start;
5412 + n_writeback = dev->data_bytes_per_chunk;
5415 + if (n_copy != dev->data_bytes_per_chunk ||
5416 + !dev->param.cache_bypass_aligned ||
5417 + dev->param.inband_tags) {
5418 + /* An incomplete start or end chunk (or maybe both
5419 + * start and end chunk), or we're using inband tags,
5420 + * or we're forcing writes through the cache,
5421 + * so we want to use the cache buffers.
5422 + */
5423 + if (dev->param.n_caches > 0) {
5424 + struct yaffs_cache *cache;
5426 + /* If we can't find the data in the cache, then
5427 + * load the cache */
5428 + cache = yaffs_find_chunk_cache(in, chunk);
5430 + if (!cache &&
5431 + yaffs_check_alloc_available(dev, 1)) {
5432 + cache = yaffs_grab_chunk_cache(dev);
5433 + cache->object = in;
5434 + cache->chunk_id = chunk;
5435 + cache->dirty = 0;
5436 + cache->locked = 0;
5437 + yaffs_rd_data_obj(in, chunk,
5438 + cache->data);
5439 + } else if (cache &&
5440 + !cache->dirty &&
5441 + !yaffs_check_alloc_available(dev,
5442 + 1)) {
5443 + /* Drop the cache if it was a read cache
5444 + * item and no space check has been made
5445 + * for it.
5446 + */
5447 + cache = NULL;
5450 + if (cache) {
5451 + yaffs_use_cache(dev, cache, 1);
5452 + cache->locked = 1;
5454 + memcpy(&cache->data[start], buffer,
5455 + n_copy);
5457 + cache->locked = 0;
5458 + cache->n_bytes = n_writeback;
5460 + if (write_through) {
5461 + chunk_written =
5462 + yaffs_wr_data_obj
5463 + (cache->object,
5464 + cache->chunk_id,
5465 + cache->data,
5466 + cache->n_bytes, 1);
5467 + cache->dirty = 0;
5469 + } else {
5470 + chunk_written = -1; /* fail write */
5472 + } else {
5473 + /* An incomplete start or end chunk (or maybe
5474 + * both start and end chunk). Read into the
5475 + * local buffer then copy over and write back.
5476 + */
5478 + u8 *local_buffer = yaffs_get_temp_buffer(dev);
5480 + yaffs_rd_data_obj(in, chunk, local_buffer);
5481 + memcpy(&local_buffer[start], buffer, n_copy);
5483 + chunk_written =
5484 + yaffs_wr_data_obj(in, chunk,
5485 + local_buffer,
5486 + n_writeback, 0);
5488 + yaffs_release_temp_buffer(dev, local_buffer);
5490 + } else {
5491 + /* A full chunk. Write directly from the buffer. */
5493 + chunk_written =
5494 + yaffs_wr_data_obj(in, chunk, buffer,
5495 + dev->data_bytes_per_chunk, 0);
5497 + /* Since we've overwritten the cached data,
5498 + * we better invalidate it. */
5499 + yaffs_invalidate_chunk_cache(in, chunk);
5502 + if (chunk_written >= 0) {
5503 + n -= n_copy;
5504 + offset += n_copy;
5505 + buffer += n_copy;
5506 + n_done += n_copy;
5510 + /* Update file object */
5512 + if ((start_write + n_done) > in->variant.file_variant.file_size)
5513 + in->variant.file_variant.file_size = (start_write + n_done);
5515 + in->dirty = 1;
5516 + return n_done;
5519 +int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
5520 + int n_bytes, int write_through)
5522 + yaffs2_handle_hole(in, offset);
5523 + return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
5526 +/* ---------------------- File resizing stuff ------------------ */
5528 +static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
5531 + struct yaffs_dev *dev = in->my_dev;
5532 + loff_t old_size = in->variant.file_variant.file_size;
5533 + int i;
5534 + int chunk_id;
5535 + u32 dummy;
5536 + int last_del;
5537 + int start_del;
5539 + if (old_size > 0)
5540 + yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
5541 + else
5542 + last_del = 0;
5544 + yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
5545 + &start_del, &dummy);
5546 + last_del++;
5547 + start_del++;
5549 + /* Delete backwards so that we don't end up with holes if
5550 + * power is lost part-way through the operation.
5551 + */
5552 + for (i = last_del; i >= start_del; i--) {
5553 + /* NB this could be optimised somewhat,
5554 + * eg. could retrieve the tags and write them without
5555 + * using yaffs_chunk_del
5556 + */
5558 + chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
5560 + if (chunk_id < 1)
5561 + continue;
5563 + if (chunk_id <
5564 + (dev->internal_start_block * dev->param.chunks_per_block) ||
5565 + chunk_id >=
5566 + ((dev->internal_end_block + 1) *
5567 + dev->param.chunks_per_block)) {
5568 + yaffs_trace(YAFFS_TRACE_ALWAYS,
5569 + "Found daft chunk_id %d for %d",
5570 + chunk_id, i);
5571 + } else {
5572 + in->n_data_chunks--;
5573 + yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
5578 +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
5580 + int new_full;
5581 + u32 new_partial;
5582 + struct yaffs_dev *dev = obj->my_dev;
5584 + yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
5586 + yaffs_prune_chunks(obj, new_size);
5588 + if (new_partial != 0) {
5589 + int last_chunk = 1 + new_full;
5590 + u8 *local_buffer = yaffs_get_temp_buffer(dev);
5592 + /* Rewrite the last chunk with its new size and zero pad */
5593 + yaffs_rd_data_obj(obj, last_chunk, local_buffer);
5594 + memset(local_buffer + new_partial, 0,
5595 + dev->data_bytes_per_chunk - new_partial);
5597 + yaffs_wr_data_obj(obj, last_chunk, local_buffer,
5598 + new_partial, 1);
5600 + yaffs_release_temp_buffer(dev, local_buffer);
5603 + obj->variant.file_variant.file_size = new_size;
5605 + yaffs_prune_tree(dev, &obj->variant.file_variant);
5608 +int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
5610 + struct yaffs_dev *dev = in->my_dev;
5611 + loff_t old_size = in->variant.file_variant.file_size;
5613 + yaffs_flush_file_cache(in);
5614 + yaffs_invalidate_whole_cache(in);
5616 + yaffs_check_gc(dev, 0);
5618 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
5619 + return YAFFS_FAIL;
5621 + if (new_size == old_size)
5622 + return YAFFS_OK;
5624 + if (new_size > old_size) {
5625 + yaffs2_handle_hole(in, new_size);
5626 + in->variant.file_variant.file_size = new_size;
5627 + } else {
5628 + /* new_size < old_size */
5629 + yaffs_resize_file_down(in, new_size);
5632 + /* Write a new object header to reflect the resize.
5633 + * show we've shrunk the file, if need be
5634 + * Do this only if the file is not in the deleted directories
5635 + * and is not shadowed.
5636 + */
5637 + if (in->parent &&
5638 + !in->is_shadowed &&
5639 + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
5640 + in->parent->obj_id != YAFFS_OBJECTID_DELETED)
5641 + yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
5643 + return YAFFS_OK;
5646 +int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
5648 + if (!in->dirty)
5649 + return YAFFS_OK;
5651 + yaffs_flush_file_cache(in);
5653 + if (data_sync)
5654 + return YAFFS_OK;
5656 + if (update_time)
5657 + yaffs_load_current_time(in, 0, 0);
5659 + return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
5660 + YAFFS_OK : YAFFS_FAIL;
5664 +/* yaffs_del_file deletes the whole file data
5665 + * and the inode associated with the file.
5666 + * It does not delete the links associated with the file.
5667 + */
5668 +static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
5670 + int ret_val;
5671 + int del_now = 0;
5672 + struct yaffs_dev *dev = in->my_dev;
5674 + if (!in->my_inode)
5675 + del_now = 1;
5677 + if (del_now) {
5678 + ret_val =
5679 + yaffs_change_obj_name(in, in->my_dev->del_dir,
5680 + _Y("deleted"), 0, 0);
5681 + yaffs_trace(YAFFS_TRACE_TRACING,
5682 + "yaffs: immediate deletion of file %d",
5683 + in->obj_id);
5684 + in->deleted = 1;
5685 + in->my_dev->n_deleted_files++;
5686 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
5687 + yaffs_resize_file(in, 0);
5688 + yaffs_soft_del_file(in);
5689 + } else {
5690 + ret_val =
5691 + yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
5692 + _Y("unlinked"), 0, 0);
5694 + return ret_val;
5697 +static int yaffs_del_file(struct yaffs_obj *in)
5699 + int ret_val = YAFFS_OK;
5700 + int deleted; /* Need to cache value on stack if in is freed */
5701 + struct yaffs_dev *dev = in->my_dev;
5703 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
5704 + yaffs_resize_file(in, 0);
5706 + if (in->n_data_chunks > 0) {
5707 + /* Use soft deletion if there is data in the file.
5708 + * That won't be the case if it has been resized to zero.
5709 + */
5710 + if (!in->unlinked)
5711 + ret_val = yaffs_unlink_file_if_needed(in);
5713 + deleted = in->deleted;
5715 + if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
5716 + in->deleted = 1;
5717 + deleted = 1;
5718 + in->my_dev->n_deleted_files++;
5719 + yaffs_soft_del_file(in);
5721 + return deleted ? YAFFS_OK : YAFFS_FAIL;
5722 + } else {
5723 + /* The file has no data chunks so we toss it immediately */
5724 + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
5725 + in->variant.file_variant.top = NULL;
5726 + yaffs_generic_obj_del(in);
5728 + return YAFFS_OK;
5732 +int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
5734 + return (obj &&
5735 + obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
5736 + !(list_empty(&obj->variant.dir_variant.children));
5739 +static int yaffs_del_dir(struct yaffs_obj *obj)
5741 + /* First check that the directory is empty. */
5742 + if (yaffs_is_non_empty_dir(obj))
5743 + return YAFFS_FAIL;
5745 + return yaffs_generic_obj_del(obj);
5748 +static int yaffs_del_symlink(struct yaffs_obj *in)
5750 + kfree(in->variant.symlink_variant.alias);
5751 + in->variant.symlink_variant.alias = NULL;
5753 + return yaffs_generic_obj_del(in);
5756 +static int yaffs_del_link(struct yaffs_obj *in)
5758 + /* remove this hardlink from the list associated with the equivalent
5759 + * object
5760 + */
5761 + list_del_init(&in->hard_links);
5762 + return yaffs_generic_obj_del(in);
5765 +int yaffs_del_obj(struct yaffs_obj *obj)
5767 + int ret_val = -1;
5769 + switch (obj->variant_type) {
5770 + case YAFFS_OBJECT_TYPE_FILE:
5771 + ret_val = yaffs_del_file(obj);
5772 + break;
5773 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5774 + if (!list_empty(&obj->variant.dir_variant.dirty)) {
5775 + yaffs_trace(YAFFS_TRACE_BACKGROUND,
5776 + "Remove object %d from dirty directories",
5777 + obj->obj_id);
5778 + list_del_init(&obj->variant.dir_variant.dirty);
5780 + return yaffs_del_dir(obj);
5781 + break;
5782 + case YAFFS_OBJECT_TYPE_SYMLINK:
5783 + ret_val = yaffs_del_symlink(obj);
5784 + break;
5785 + case YAFFS_OBJECT_TYPE_HARDLINK:
5786 + ret_val = yaffs_del_link(obj);
5787 + break;
5788 + case YAFFS_OBJECT_TYPE_SPECIAL:
5789 + ret_val = yaffs_generic_obj_del(obj);
5790 + break;
5791 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5792 + ret_val = 0;
5793 + break; /* should not happen. */
5795 + return ret_val;
5799 +static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
5800 + struct yaffs_obj *to_dir)
5802 + struct yaffs_obj *obj;
5803 + struct list_head *lh;
5804 + struct list_head *n;
5806 + list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
5807 + obj = list_entry(lh, struct yaffs_obj, siblings);
5808 + yaffs_add_obj_to_dir(to_dir, obj);
5812 +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
5813 + enum yaffs_obj_type type)
5815 + /* Tear down the old variant */
5816 + switch (obj->variant_type) {
5817 + case YAFFS_OBJECT_TYPE_FILE:
5818 + /* Nuke file data */
5819 + yaffs_resize_file(obj, 0);
5820 + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
5821 + obj->variant.file_variant.top = NULL;
5822 + break;
5823 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5824 + /* Put the children in lost and found. */
5825 + yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
5826 + if (!list_empty(&obj->variant.dir_variant.dirty))
5827 + list_del_init(&obj->variant.dir_variant.dirty);
5828 + break;
5829 + case YAFFS_OBJECT_TYPE_SYMLINK:
5830 + /* Nuke symplink data */
5831 + kfree(obj->variant.symlink_variant.alias);
5832 + obj->variant.symlink_variant.alias = NULL;
5833 + break;
5834 + case YAFFS_OBJECT_TYPE_HARDLINK:
5835 + list_del_init(&obj->hard_links);
5836 + break;
5837 + default:
5838 + break;
5841 + memset(&obj->variant, 0, sizeof(obj->variant));
5843 + /*Set up new variant if the memset is not enough. */
5844 + switch (type) {
5845 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5846 + INIT_LIST_HEAD(&obj->variant.dir_variant.children);
5847 + INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
5848 + break;
5849 + case YAFFS_OBJECT_TYPE_FILE:
5850 + case YAFFS_OBJECT_TYPE_SYMLINK:
5851 + case YAFFS_OBJECT_TYPE_HARDLINK:
5852 + default:
5853 + break;
5856 + obj->variant_type = type;
5858 + return obj;
5862 +static int yaffs_unlink_worker(struct yaffs_obj *obj)
5864 + int del_now = 0;
5866 + if (!obj)
5867 + return YAFFS_FAIL;
5869 + if (!obj->my_inode)
5870 + del_now = 1;
5872 + yaffs_update_parent(obj->parent);
5874 + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
5875 + return yaffs_del_link(obj);
5876 + } else if (!list_empty(&obj->hard_links)) {
5877 + /* Curve ball: We're unlinking an object that has a hardlink.
5879 + * This problem arises because we are not strictly following
5880 + * The Linux link/inode model.
5882 + * We can't really delete the object.
5883 + * Instead, we do the following:
5884 + * - Select a hardlink.
5885 + * - Unhook it from the hard links
5886 + * - Move it from its parent directory so that the rename works.
5887 + * - Rename the object to the hardlink's name.
5888 + * - Delete the hardlink
5889 + */
5891 + struct yaffs_obj *hl;
5892 + struct yaffs_obj *parent;
5893 + int ret_val;
5894 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
5896 + hl = list_entry(obj->hard_links.next, struct yaffs_obj,
5897 + hard_links);
5899 + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
5900 + parent = hl->parent;
5902 + list_del_init(&hl->hard_links);
5904 + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
5906 + ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
5908 + if (ret_val == YAFFS_OK)
5909 + ret_val = yaffs_generic_obj_del(hl);
5911 + return ret_val;
5913 + } else if (del_now) {
5914 + switch (obj->variant_type) {
5915 + case YAFFS_OBJECT_TYPE_FILE:
5916 + return yaffs_del_file(obj);
5917 + break;
5918 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5919 + list_del_init(&obj->variant.dir_variant.dirty);
5920 + return yaffs_del_dir(obj);
5921 + break;
5922 + case YAFFS_OBJECT_TYPE_SYMLINK:
5923 + return yaffs_del_symlink(obj);
5924 + break;
5925 + case YAFFS_OBJECT_TYPE_SPECIAL:
5926 + return yaffs_generic_obj_del(obj);
5927 + break;
5928 + case YAFFS_OBJECT_TYPE_HARDLINK:
5929 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5930 + default:
5931 + return YAFFS_FAIL;
5933 + } else if (yaffs_is_non_empty_dir(obj)) {
5934 + return YAFFS_FAIL;
5935 + } else {
5936 + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
5937 + _Y("unlinked"), 0, 0);
5941 +static int yaffs_unlink_obj(struct yaffs_obj *obj)
5943 + if (obj && obj->unlink_allowed)
5944 + return yaffs_unlink_worker(obj);
5946 + return YAFFS_FAIL;
5949 +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
5951 + struct yaffs_obj *obj;
5953 + obj = yaffs_find_by_name(dir, name);
5954 + return yaffs_unlink_obj(obj);
5957 +/* Note:
5958 + * If old_name is NULL then we take old_dir as the object to be renamed.
5959 + */
5960 +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
5961 + struct yaffs_obj *new_dir, const YCHAR *new_name)
5963 + struct yaffs_obj *obj = NULL;
5964 + struct yaffs_obj *existing_target = NULL;
5965 + int force = 0;
5966 + int result;
5967 + struct yaffs_dev *dev;
5969 + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
5970 + BUG();
5971 + return YAFFS_FAIL;
5973 + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
5974 + BUG();
5975 + return YAFFS_FAIL;
5978 + dev = old_dir->my_dev;
5980 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5981 + /* Special case for case insemsitive systems.
5982 + * While look-up is case insensitive, the name isn't.
5983 + * Therefore we might want to change x.txt to X.txt
5984 + */
5985 + if (old_dir == new_dir &&
5986 + old_name && new_name &&
5987 + strcmp(old_name, new_name) == 0)
5988 + force = 1;
5989 +#endif
5991 + if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
5992 + YAFFS_MAX_NAME_LENGTH)
5993 + /* ENAMETOOLONG */
5994 + return YAFFS_FAIL;
5996 + if (old_name)
5997 + obj = yaffs_find_by_name(old_dir, old_name);
5998 + else{
5999 + obj = old_dir;
6000 + old_dir = obj->parent;
6003 + if (obj && obj->rename_allowed) {
6004 + /* Now handle an existing target, if there is one */
6005 + existing_target = yaffs_find_by_name(new_dir, new_name);
6006 + if (yaffs_is_non_empty_dir(existing_target)) {
6007 + return YAFFS_FAIL; /* ENOTEMPTY */
6008 + } else if (existing_target && existing_target != obj) {
6009 + /* Nuke the target first, using shadowing,
6010 + * but only if it isn't the same object.
6012 + * Note we must disable gc here otherwise it can mess
6013 + * up the shadowing.
6015 + */
6016 + dev->gc_disable = 1;
6017 + yaffs_change_obj_name(obj, new_dir, new_name, force,
6018 + existing_target->obj_id);
6019 + existing_target->is_shadowed = 1;
6020 + yaffs_unlink_obj(existing_target);
6021 + dev->gc_disable = 0;
6024 + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
6026 + yaffs_update_parent(old_dir);
6027 + if (new_dir != old_dir)
6028 + yaffs_update_parent(new_dir);
6030 + return result;
6032 + return YAFFS_FAIL;
6035 +/*----------------------- Initialisation Scanning ---------------------- */
6037 +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
6038 + int backward_scanning)
6040 + struct yaffs_obj *obj;
6042 + if (backward_scanning) {
6043 + /* Handle YAFFS2 case (backward scanning)
6044 + * If the shadowed object exists then ignore.
6045 + */
6046 + obj = yaffs_find_by_number(dev, obj_id);
6047 + if (obj)
6048 + return;
6051 + /* Let's create it (if it does not exist) assuming it is a file so that
6052 + * it can do shrinking etc.
6053 + * We put it in unlinked dir to be cleaned up after the scanning
6054 + */
6055 + obj =
6056 + yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
6057 + if (!obj)
6058 + return;
6059 + obj->is_shadowed = 1;
6060 + yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
6061 + obj->variant.file_variant.shrink_size = 0;
6062 + obj->valid = 1; /* So that we don't read any other info. */
6065 +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
6067 + struct list_head *lh;
6068 + struct list_head *save;
6069 + struct yaffs_obj *hl;
6070 + struct yaffs_obj *in;
6072 + list_for_each_safe(lh, save, hard_list) {
6073 + hl = list_entry(lh, struct yaffs_obj, hard_links);
6074 + in = yaffs_find_by_number(dev,
6075 + hl->variant.hardlink_variant.equiv_id);
6077 + if (in) {
6078 + /* Add the hardlink pointers */
6079 + hl->variant.hardlink_variant.equiv_obj = in;
6080 + list_add(&hl->hard_links, &in->hard_links);
6081 + } else {
6082 + /* Todo Need to report/handle this better.
6083 + * Got a problem... hardlink to a non-existant object
6084 + */
6085 + hl->variant.hardlink_variant.equiv_obj = NULL;
6086 + INIT_LIST_HEAD(&hl->hard_links);
6091 +static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
6093 + /*
6094 + * Sort out state of unlinked and deleted objects after scanning.
6095 + */
6096 + struct list_head *i;
6097 + struct list_head *n;
6098 + struct yaffs_obj *l;
6100 + if (dev->read_only)
6101 + return;
6103 + /* Soft delete all the unlinked files */
6104 + list_for_each_safe(i, n,
6105 + &dev->unlinked_dir->variant.dir_variant.children) {
6106 + l = list_entry(i, struct yaffs_obj, siblings);
6107 + yaffs_del_obj(l);
6110 + list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
6111 + l = list_entry(i, struct yaffs_obj, siblings);
6112 + yaffs_del_obj(l);
6117 + * This code iterates through all the objects making sure that they are rooted.
6118 + * Any unrooted objects are re-rooted in lost+found.
6119 + * An object needs to be in one of:
6120 + * - Directly under deleted, unlinked
6121 + * - Directly or indirectly under root.
6123 + * Note:
6124 + * This code assumes that we don't ever change the current relationships
6125 + * between directories:
6126 + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
6127 + * lost-n-found->parent == root_dir
6129 + * This fixes the problem where directories might have inadvertently been
6130 + * deleted leaving the object "hanging" without being rooted in the
6131 + * directory tree.
6132 + */
6134 +static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
6136 + return (obj == dev->del_dir ||
6137 + obj == dev->unlinked_dir || obj == dev->root_dir);
6140 +static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
6142 + struct yaffs_obj *obj;
6143 + struct yaffs_obj *parent;
6144 + int i;
6145 + struct list_head *lh;
6146 + struct list_head *n;
6147 + int depth_limit;
6148 + int hanging;
6150 + if (dev->read_only)
6151 + return;
6153 + /* Iterate through the objects in each hash entry,
6154 + * looking at each object.
6155 + * Make sure it is rooted.
6156 + */
6158 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6159 + list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
6160 + obj = list_entry(lh, struct yaffs_obj, hash_link);
6161 + parent = obj->parent;
6163 + if (yaffs_has_null_parent(dev, obj)) {
6164 + /* These directories are not hanging */
6165 + hanging = 0;
6166 + } else if (!parent ||
6167 + parent->variant_type !=
6168 + YAFFS_OBJECT_TYPE_DIRECTORY) {
6169 + hanging = 1;
6170 + } else if (yaffs_has_null_parent(dev, parent)) {
6171 + hanging = 0;
6172 + } else {
6173 + /*
6174 + * Need to follow the parent chain to
6175 + * see if it is hanging.
6176 + */
6177 + hanging = 0;
6178 + depth_limit = 100;
6180 + while (parent != dev->root_dir &&
6181 + parent->parent &&
6182 + parent->parent->variant_type ==
6183 + YAFFS_OBJECT_TYPE_DIRECTORY &&
6184 + depth_limit > 0) {
6185 + parent = parent->parent;
6186 + depth_limit--;
6188 + if (parent != dev->root_dir)
6189 + hanging = 1;
6191 + if (hanging) {
6192 + yaffs_trace(YAFFS_TRACE_SCAN,
6193 + "Hanging object %d moved to lost and found",
6194 + obj->obj_id);
6195 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
6202 + * Delete directory contents for cleaning up lost and found.
6203 + */
6204 +static void yaffs_del_dir_contents(struct yaffs_obj *dir)
6206 + struct yaffs_obj *obj;
6207 + struct list_head *lh;
6208 + struct list_head *n;
6210 + if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
6211 + BUG();
6213 + list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
6214 + obj = list_entry(lh, struct yaffs_obj, siblings);
6215 + if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
6216 + yaffs_del_dir_contents(obj);
6217 + yaffs_trace(YAFFS_TRACE_SCAN,
6218 + "Deleting lost_found object %d",
6219 + obj->obj_id);
6220 + yaffs_unlink_obj(obj);
6224 +static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
6226 + yaffs_del_dir_contents(dev->lost_n_found);
6230 +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
6231 + const YCHAR *name)
6233 + int sum;
6234 + struct list_head *i;
6235 + YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
6236 + struct yaffs_obj *l;
6238 + if (!name)
6239 + return NULL;
6241 + if (!directory) {
6242 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6243 + "tragedy: yaffs_find_by_name: null pointer directory"
6244 + );
6245 + BUG();
6246 + return NULL;
6248 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
6249 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6250 + "tragedy: yaffs_find_by_name: non-directory"
6251 + );
6252 + BUG();
6255 + sum = yaffs_calc_name_sum(name);
6257 + list_for_each(i, &directory->variant.dir_variant.children) {
6258 + l = list_entry(i, struct yaffs_obj, siblings);
6260 + if (l->parent != directory)
6261 + BUG();
6263 + yaffs_check_obj_details_loaded(l);
6265 + /* Special case for lost-n-found */
6266 + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
6267 + if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
6268 + return l;
6269 + } else if (l->sum == sum || l->hdr_chunk <= 0) {
6270 + /* LostnFound chunk called Objxxx
6271 + * Do a real check
6272 + */
6273 + yaffs_get_obj_name(l, buffer,
6274 + YAFFS_MAX_NAME_LENGTH + 1);
6275 + if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
6276 + return l;
6279 + return NULL;
6282 +/* GetEquivalentObject dereferences any hard links to get to the
6283 + * actual object.
6284 + */
6286 +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
6288 + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
6289 + obj = obj->variant.hardlink_variant.equiv_obj;
6290 + yaffs_check_obj_details_loaded(obj);
6292 + return obj;
6296 + * A note or two on object names.
6297 + * * If the object name is missing, we then make one up in the form objnnn
6299 + * * ASCII names are stored in the object header's name field from byte zero
6300 + * * Unicode names are historically stored starting from byte zero.
6302 + * Then there are automatic Unicode names...
6303 + * The purpose of these is to save names in a way that can be read as
6304 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
6305 + * system to share files.
6307 + * These automatic unicode are stored slightly differently...
6308 + * - If the name can fit in the ASCII character space then they are saved as
6309 + * ascii names as per above.
6310 + * - If the name needs Unicode then the name is saved in Unicode
6311 + * starting at oh->name[1].
6313 + */
6314 +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
6315 + int buffer_size)
6317 + /* Create an object name if we could not find one. */
6318 + if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
6319 + YCHAR local_name[20];
6320 + YCHAR num_string[20];
6321 + YCHAR *x = &num_string[19];
6322 + unsigned v = obj->obj_id;
6323 + num_string[19] = 0;
6324 + while (v > 0) {
6325 + x--;
6326 + *x = '0' + (v % 10);
6327 + v /= 10;
6329 + /* make up a name */
6330 + strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
6331 + strcat(local_name, x);
6332 + strncpy(name, local_name, buffer_size - 1);
6336 +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
6338 + memset(name, 0, buffer_size * sizeof(YCHAR));
6339 + yaffs_check_obj_details_loaded(obj);
6340 + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
6341 + strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
6342 + } else if (obj->short_name[0]) {
6343 + strcpy(name, obj->short_name);
6344 + } else if (obj->hdr_chunk > 0) {
6345 + int result;
6346 + u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
6348 + struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
6350 + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
6352 + if (obj->hdr_chunk > 0) {
6353 + result = yaffs_rd_chunk_tags_nand(obj->my_dev,
6354 + obj->hdr_chunk,
6355 + buffer, NULL);
6357 + yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
6358 + buffer_size);
6360 + yaffs_release_temp_buffer(obj->my_dev, buffer);
6363 + yaffs_fix_null_name(obj, name, buffer_size);
6365 + return strnlen(name, YAFFS_MAX_NAME_LENGTH);
6368 +loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
6370 + /* Dereference any hard linking */
6371 + obj = yaffs_get_equivalent_obj(obj);
6373 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
6374 + return obj->variant.file_variant.file_size;
6375 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
6376 + if (!obj->variant.symlink_variant.alias)
6377 + return 0;
6378 + return strnlen(obj->variant.symlink_variant.alias,
6379 + YAFFS_MAX_ALIAS_LENGTH);
6380 + } else {
6381 + /* Only a directory should drop through to here */
6382 + return obj->my_dev->data_bytes_per_chunk;
6386 +int yaffs_get_obj_link_count(struct yaffs_obj *obj)
6388 + int count = 0;
6389 + struct list_head *i;
6391 + if (!obj->unlinked)
6392 + count++; /* the object itself */
6394 + list_for_each(i, &obj->hard_links)
6395 + count++; /* add the hard links; */
6397 + return count;
6400 +int yaffs_get_obj_inode(struct yaffs_obj *obj)
6402 + obj = yaffs_get_equivalent_obj(obj);
6404 + return obj->obj_id;
6407 +unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
6409 + obj = yaffs_get_equivalent_obj(obj);
6411 + switch (obj->variant_type) {
6412 + case YAFFS_OBJECT_TYPE_FILE:
6413 + return DT_REG;
6414 + break;
6415 + case YAFFS_OBJECT_TYPE_DIRECTORY:
6416 + return DT_DIR;
6417 + break;
6418 + case YAFFS_OBJECT_TYPE_SYMLINK:
6419 + return DT_LNK;
6420 + break;
6421 + case YAFFS_OBJECT_TYPE_HARDLINK:
6422 + return DT_REG;
6423 + break;
6424 + case YAFFS_OBJECT_TYPE_SPECIAL:
6425 + if (S_ISFIFO(obj->yst_mode))
6426 + return DT_FIFO;
6427 + if (S_ISCHR(obj->yst_mode))
6428 + return DT_CHR;
6429 + if (S_ISBLK(obj->yst_mode))
6430 + return DT_BLK;
6431 + if (S_ISSOCK(obj->yst_mode))
6432 + return DT_SOCK;
6433 + return DT_REG;
6434 + break;
6435 + default:
6436 + return DT_REG;
6437 + break;
6441 +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
6443 + obj = yaffs_get_equivalent_obj(obj);
6444 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
6445 + return yaffs_clone_str(obj->variant.symlink_variant.alias);
6446 + else
6447 + return yaffs_clone_str(_Y(""));
6450 +/*--------------------------- Initialisation code -------------------------- */
6452 +static int yaffs_check_dev_fns(struct yaffs_dev *dev)
6454 + struct yaffs_driver *drv = &dev->drv;
6455 + struct yaffs_tags_handler *tagger = &dev->tagger;
6457 + /* Common functions, gotta have */
6458 + if (!drv->drv_read_chunk_fn ||
6459 + !drv->drv_write_chunk_fn ||
6460 + !drv->drv_erase_fn)
6461 + return 0;
6463 + if (dev->param.is_yaffs2 &&
6464 + (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
6465 + return 0;
6467 + /* Install the default tags marshalling functions if needed. */
6468 + yaffs_tags_compat_install(dev);
6469 + yaffs_tags_marshall_install(dev);
6471 + /* Check we now have the marshalling functions required. */
6472 + if (!tagger->write_chunk_tags_fn ||
6473 + !tagger->read_chunk_tags_fn ||
6474 + !tagger->query_block_fn ||
6475 + !tagger->mark_bad_fn)
6476 + return 0;
6478 + return 1;
6481 +static int yaffs_create_initial_dir(struct yaffs_dev *dev)
6483 + /* Initialise the unlinked, deleted, root and lost+found directories */
6484 + dev->lost_n_found = dev->root_dir = NULL;
6485 + dev->unlinked_dir = dev->del_dir = NULL;
6486 + dev->unlinked_dir =
6487 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
6488 + dev->del_dir =
6489 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
6490 + dev->root_dir =
6491 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
6492 + YAFFS_ROOT_MODE | S_IFDIR);
6493 + dev->lost_n_found =
6494 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
6495 + YAFFS_LOSTNFOUND_MODE | S_IFDIR);
6497 + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
6498 + && dev->del_dir) {
6499 + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
6500 + return YAFFS_OK;
6502 + return YAFFS_FAIL;
6505 +/* Low level init.
6506 + * Typically only used by yaffs_guts_initialise, but also used by the
6507 + * Low level yaffs driver tests.
6508 + */
6510 +int yaffs_guts_ll_init(struct yaffs_dev *dev)
6514 + yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
6516 + if (!dev) {
6517 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6518 + "yaffs: Need a device"
6519 + );
6520 + return YAFFS_FAIL;
6523 + if (dev->ll_init)
6524 + return YAFFS_OK;
6526 + dev->internal_start_block = dev->param.start_block;
6527 + dev->internal_end_block = dev->param.end_block;
6528 + dev->block_offset = 0;
6529 + dev->chunk_offset = 0;
6530 + dev->n_free_chunks = 0;
6532 + dev->gc_block = 0;
6534 + if (dev->param.start_block == 0) {
6535 + dev->internal_start_block = dev->param.start_block + 1;
6536 + dev->internal_end_block = dev->param.end_block + 1;
6537 + dev->block_offset = 1;
6538 + dev->chunk_offset = dev->param.chunks_per_block;
6541 + /* Check geometry parameters. */
6543 + if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
6544 + dev->param.total_bytes_per_chunk < 1024) ||
6545 + (!dev->param.is_yaffs2 &&
6546 + dev->param.total_bytes_per_chunk < 512) ||
6547 + (dev->param.inband_tags && !dev->param.is_yaffs2) ||
6548 + dev->param.chunks_per_block < 2 ||
6549 + dev->param.n_reserved_blocks < 2 ||
6550 + dev->internal_start_block <= 0 ||
6551 + dev->internal_end_block <= 0 ||
6552 + dev->internal_end_block <=
6553 + (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
6554 + ) {
6555 + /* otherwise it is too small */
6556 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6557 + "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
6558 + dev->param.total_bytes_per_chunk,
6559 + dev->param.is_yaffs2 ? "2" : "",
6560 + dev->param.inband_tags);
6561 + return YAFFS_FAIL;
6564 + /* Sort out space for inband tags, if required */
6565 + if (dev->param.inband_tags)
6566 + dev->data_bytes_per_chunk =
6567 + dev->param.total_bytes_per_chunk -
6568 + sizeof(struct yaffs_packed_tags2_tags_only);
6569 + else
6570 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
6572 + /* Got the right mix of functions? */
6573 + if (!yaffs_check_dev_fns(dev)) {
6574 + /* Function missing */
6575 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6576 + "device function(s) missing or wrong");
6578 + return YAFFS_FAIL;
6581 + if (yaffs_init_nand(dev) != YAFFS_OK) {
6582 + yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
6583 + return YAFFS_FAIL;
6586 + return YAFFS_OK;
6590 +int yaffs_guts_format_dev(struct yaffs_dev *dev)
6592 + int i;
6593 + enum yaffs_block_state state;
6594 + u32 dummy;
6596 + if(yaffs_guts_ll_init(dev) != YAFFS_OK)
6597 + return YAFFS_FAIL;
6599 + if(dev->is_mounted)
6600 + return YAFFS_FAIL;
6602 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
6603 + yaffs_query_init_block_state(dev, i, &state, &dummy);
6604 + if (state != YAFFS_BLOCK_STATE_DEAD)
6605 + yaffs_erase_block(dev, i);
6608 + return YAFFS_OK;
6612 +int yaffs_guts_initialise(struct yaffs_dev *dev)
6614 + int init_failed = 0;
6615 + unsigned x;
6616 + int bits;
6618 + if(yaffs_guts_ll_init(dev) != YAFFS_OK)
6619 + return YAFFS_FAIL;
6621 + if (dev->is_mounted) {
6622 + yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
6623 + return YAFFS_FAIL;
6626 + dev->is_mounted = 1;
6628 + /* OK now calculate a few things for the device */
6630 + /*
6631 + * Calculate all the chunk size manipulation numbers:
6632 + */
6633 + x = dev->data_bytes_per_chunk;
6634 + /* We always use dev->chunk_shift and dev->chunk_div */
6635 + dev->chunk_shift = calc_shifts(x);
6636 + x >>= dev->chunk_shift;
6637 + dev->chunk_div = x;
6638 + /* We only use chunk mask if chunk_div is 1 */
6639 + dev->chunk_mask = (1 << dev->chunk_shift) - 1;
6641 + /*
6642 + * Calculate chunk_grp_bits.
6643 + * We need to find the next power of 2 > than internal_end_block
6644 + */
6646 + x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
6648 + bits = calc_shifts_ceiling(x);
6650 + /* Set up tnode width if wide tnodes are enabled. */
6651 + if (!dev->param.wide_tnodes_disabled) {
6652 + /* bits must be even so that we end up with 32-bit words */
6653 + if (bits & 1)
6654 + bits++;
6655 + if (bits < 16)
6656 + dev->tnode_width = 16;
6657 + else
6658 + dev->tnode_width = bits;
6659 + } else {
6660 + dev->tnode_width = 16;
6663 + dev->tnode_mask = (1 << dev->tnode_width) - 1;
6665 + /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
6666 + * so if the bitwidth of the
6667 + * chunk range we're using is greater than 16 we need
6668 + * to figure out chunk shift and chunk_grp_size
6669 + */
6671 + if (bits <= dev->tnode_width)
6672 + dev->chunk_grp_bits = 0;
6673 + else
6674 + dev->chunk_grp_bits = bits - dev->tnode_width;
6676 + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
6677 + if (dev->tnode_size < sizeof(struct yaffs_tnode))
6678 + dev->tnode_size = sizeof(struct yaffs_tnode);
6680 + dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
6682 + if (dev->param.chunks_per_block < dev->chunk_grp_size) {
6683 + /* We have a problem because the soft delete won't work if
6684 + * the chunk group size > chunks per block.
6685 + * This can be remedied by using larger "virtual blocks".
6686 + */
6687 + yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
6689 + return YAFFS_FAIL;
6692 + /* Finished verifying the device, continue with initialisation */
6694 + /* More device initialisation */
6695 + dev->all_gcs = 0;
6696 + dev->passive_gc_count = 0;
6697 + dev->oldest_dirty_gc_count = 0;
6698 + dev->bg_gcs = 0;
6699 + dev->gc_block_finder = 0;
6700 + dev->buffered_block = -1;
6701 + dev->doing_buffered_block_rewrite = 0;
6702 + dev->n_deleted_files = 0;
6703 + dev->n_bg_deletions = 0;
6704 + dev->n_unlinked_files = 0;
6705 + dev->n_ecc_fixed = 0;
6706 + dev->n_ecc_unfixed = 0;
6707 + dev->n_tags_ecc_fixed = 0;
6708 + dev->n_tags_ecc_unfixed = 0;
6709 + dev->n_erase_failures = 0;
6710 + dev->n_erased_blocks = 0;
6711 + dev->gc_disable = 0;
6712 + dev->has_pending_prioritised_gc = 1;
6713 + /* Assume the worst for now, will get fixed on first GC */
6714 + INIT_LIST_HEAD(&dev->dirty_dirs);
6715 + dev->oldest_dirty_seq = 0;
6716 + dev->oldest_dirty_block = 0;
6718 + /* Initialise temporary buffers and caches. */
6719 + if (!yaffs_init_tmp_buffers(dev))
6720 + init_failed = 1;
6722 + dev->cache = NULL;
6723 + dev->gc_cleanup_list = NULL;
6725 + if (!init_failed && dev->param.n_caches > 0) {
6726 + int i;
6727 + void *buf;
6728 + int cache_bytes =
6729 + dev->param.n_caches * sizeof(struct yaffs_cache);
6731 + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
6732 + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
6734 + dev->cache = kmalloc(cache_bytes, GFP_NOFS);
6736 + buf = (u8 *) dev->cache;
6738 + if (dev->cache)
6739 + memset(dev->cache, 0, cache_bytes);
6741 + for (i = 0; i < dev->param.n_caches && buf; i++) {
6742 + dev->cache[i].object = NULL;
6743 + dev->cache[i].last_use = 0;
6744 + dev->cache[i].dirty = 0;
6745 + dev->cache[i].data = buf =
6746 + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
6748 + if (!buf)
6749 + init_failed = 1;
6751 + dev->cache_last_use = 0;
6754 + dev->cache_hits = 0;
6756 + if (!init_failed) {
6757 + dev->gc_cleanup_list =
6758 + kmalloc(dev->param.chunks_per_block * sizeof(u32),
6759 + GFP_NOFS);
6760 + if (!dev->gc_cleanup_list)
6761 + init_failed = 1;
6764 + if (dev->param.is_yaffs2)
6765 + dev->param.use_header_file_size = 1;
6767 + if (!init_failed && !yaffs_init_blocks(dev))
6768 + init_failed = 1;
6770 + yaffs_init_tnodes_and_objs(dev);
6772 + if (!init_failed && !yaffs_create_initial_dir(dev))
6773 + init_failed = 1;
6775 + if (!init_failed && dev->param.is_yaffs2 &&
6776 + !dev->param.disable_summary &&
6777 + !yaffs_summary_init(dev))
6778 + init_failed = 1;
6780 + if (!init_failed) {
6781 + /* Now scan the flash. */
6782 + if (dev->param.is_yaffs2) {
6783 + if (yaffs2_checkpt_restore(dev)) {
6784 + yaffs_check_obj_details_loaded(dev->root_dir);
6785 + yaffs_trace(YAFFS_TRACE_CHECKPOINT |
6786 + YAFFS_TRACE_MOUNT,
6787 + "yaffs: restored from checkpoint"
6788 + );
6789 + } else {
6791 + /* Clean up the mess caused by an aborted
6792 + * checkpoint load then scan backwards.
6793 + */
6794 + yaffs_deinit_blocks(dev);
6796 + yaffs_deinit_tnodes_and_objs(dev);
6798 + dev->n_erased_blocks = 0;
6799 + dev->n_free_chunks = 0;
6800 + dev->alloc_block = -1;
6801 + dev->alloc_page = -1;
6802 + dev->n_deleted_files = 0;
6803 + dev->n_unlinked_files = 0;
6804 + dev->n_bg_deletions = 0;
6806 + if (!init_failed && !yaffs_init_blocks(dev))
6807 + init_failed = 1;
6809 + yaffs_init_tnodes_and_objs(dev);
6811 + if (!init_failed
6812 + && !yaffs_create_initial_dir(dev))
6813 + init_failed = 1;
6815 + if (!init_failed && !yaffs2_scan_backwards(dev))
6816 + init_failed = 1;
6818 + } else if (!yaffs1_scan(dev)) {
6819 + init_failed = 1;
6822 + yaffs_strip_deleted_objs(dev);
6823 + yaffs_fix_hanging_objs(dev);
6824 + if (dev->param.empty_lost_n_found)
6825 + yaffs_empty_l_n_f(dev);
6828 + if (init_failed) {
6829 + /* Clean up the mess */
6830 + yaffs_trace(YAFFS_TRACE_TRACING,
6831 + "yaffs: yaffs_guts_initialise() aborted.");
6833 + yaffs_deinitialise(dev);
6834 + return YAFFS_FAIL;
6837 + /* Zero out stats */
6838 + dev->n_page_reads = 0;
6839 + dev->n_page_writes = 0;
6840 + dev->n_erasures = 0;
6841 + dev->n_gc_copies = 0;
6842 + dev->n_retried_writes = 0;
6844 + dev->n_retired_blocks = 0;
6846 + yaffs_verify_free_chunks(dev);
6847 + yaffs_verify_blocks(dev);
6849 + /* Clean up any aborted checkpoint data */
6850 + if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
6851 + yaffs2_checkpt_invalidate(dev);
6853 + yaffs_trace(YAFFS_TRACE_TRACING,
6854 + "yaffs: yaffs_guts_initialise() done.");
6855 + return YAFFS_OK;
6858 +void yaffs_deinitialise(struct yaffs_dev *dev)
6860 + if (dev->is_mounted) {
6861 + int i;
6863 + yaffs_deinit_blocks(dev);
6864 + yaffs_deinit_tnodes_and_objs(dev);
6865 + yaffs_summary_deinit(dev);
6867 + if (dev->param.n_caches > 0 && dev->cache) {
6869 + for (i = 0; i < dev->param.n_caches; i++) {
6870 + kfree(dev->cache[i].data);
6871 + dev->cache[i].data = NULL;
6874 + kfree(dev->cache);
6875 + dev->cache = NULL;
6878 + kfree(dev->gc_cleanup_list);
6880 + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
6881 + kfree(dev->temp_buffer[i].buffer);
6883 + dev->is_mounted = 0;
6885 + yaffs_deinit_nand(dev);
6889 +int yaffs_count_free_chunks(struct yaffs_dev *dev)
6891 + int n_free = 0;
6892 + int b;
6893 + struct yaffs_block_info *blk;
6895 + blk = dev->block_info;
6896 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
6897 + switch (blk->block_state) {
6898 + case YAFFS_BLOCK_STATE_EMPTY:
6899 + case YAFFS_BLOCK_STATE_ALLOCATING:
6900 + case YAFFS_BLOCK_STATE_COLLECTING:
6901 + case YAFFS_BLOCK_STATE_FULL:
6902 + n_free +=
6903 + (dev->param.chunks_per_block - blk->pages_in_use +
6904 + blk->soft_del_pages);
6905 + break;
6906 + default:
6907 + break;
6909 + blk++;
6911 + return n_free;
6914 +int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
6916 + /* This is what we report to the outside world */
6917 + int n_free;
6918 + int n_dirty_caches;
6919 + int blocks_for_checkpt;
6920 + int i;
6922 + n_free = dev->n_free_chunks;
6923 + n_free += dev->n_deleted_files;
6925 + /* Now count and subtract the number of dirty chunks in the cache. */
6927 + for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
6928 + if (dev->cache[i].dirty)
6929 + n_dirty_caches++;
6932 + n_free -= n_dirty_caches;
6934 + n_free -=
6935 + ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
6937 + /* Now figure checkpoint space and report that... */
6938 + blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
6940 + n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
6942 + if (n_free < 0)
6943 + n_free = 0;
6945 + return n_free;
6951 + * Marshalling functions to get loff_t file sizes into and out of
6952 + * object headers.
6953 + */
6954 +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
6956 + oh->file_size_low = (fsize & 0xFFFFFFFF);
6957 + oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
6960 +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
6962 + loff_t retval;
6964 + if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
6965 + retval = (((loff_t) oh->file_size_high) << 32) |
6966 + (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
6967 + else
6968 + retval = (loff_t) oh->file_size_low;
6970 + return retval;
6974 +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
6976 + int i;
6977 + struct yaffs_block_info *bi;
6978 + int s;
6980 + for(i = 0; i < 10; i++)
6981 + bs[i] = 0;
6983 + for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
6984 + bi = yaffs_get_block_info(dev, i);
6985 + s = bi->block_state;
6986 + if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
6987 + bs[0]++;
6988 + else
6989 + bs[s]++;
6992 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_guts.h linux-3.4.90/fs/yaffs2/yaffs_guts.h
6993 --- linux-3.4.90.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
6994 +++ linux-3.4.90/fs/yaffs2/yaffs_guts.h 2014-05-17 15:08:09.000000000 +0200
6995 @@ -0,0 +1,1007 @@
6997 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
6999 + * Copyright (C) 2002-2011 Aleph One Ltd.
7000 + * for Toby Churchill Ltd and Brightstar Engineering
7002 + * Created by Charles Manning <charles@aleph1.co.uk>
7004 + * This program is free software; you can redistribute it and/or modify
7005 + * it under the terms of the GNU Lesser General Public License version 2.1 as
7006 + * published by the Free Software Foundation.
7008 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
7009 + */
7011 +#ifndef __YAFFS_GUTS_H__
7012 +#define __YAFFS_GUTS_H__
7014 +#include "yportenv.h"
7016 +#define YAFFS_OK 1
7017 +#define YAFFS_FAIL 0
7019 +/* Give us a Y=0x59,
7020 + * Give us an A=0x41,
7021 + * Give us an FF=0xff
7022 + * Give us an S=0x53
7023 + * And what have we got...
7024 + */
7025 +#define YAFFS_MAGIC 0x5941ff53
7028 + * Tnodes form a tree with the tnodes in "levels"
7029 + * Levels greater than 0 hold 8 slots which point to other tnodes.
7030 + * Those at level 0 hold 16 slots which point to chunks in NAND.
7032 + * A maximum level of 8 thust supports files of size up to:
7034 + * 2^(3*MAX_LEVEL+4)
7036 + * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
7037 + * a maximum file size of around 512Gbytees with 2k chunks.
7038 + */
7039 +#define YAFFS_NTNODES_LEVEL0 16
7040 +#define YAFFS_TNODES_LEVEL0_BITS 4
7041 +#define YAFFS_TNODES_LEVEL0_MASK 0xf
7043 +#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
7044 +#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
7045 +#define YAFFS_TNODES_INTERNAL_MASK 0x7
7046 +#define YAFFS_TNODES_MAX_LEVEL 8
7047 +#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
7048 + YAFFS_TNODES_INTERNAL_BITS * \
7049 + YAFFS_TNODES_MAX_LEVEL)
7050 +#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
7052 +#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
7054 +/* Constants for YAFFS1 mode */
7055 +#define YAFFS_BYTES_PER_SPARE 16
7056 +#define YAFFS_BYTES_PER_CHUNK 512
7057 +#define YAFFS_CHUNK_SIZE_SHIFT 9
7058 +#define YAFFS_CHUNKS_PER_BLOCK 32
7059 +#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
7061 +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
7062 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
7066 +#define YAFFS_ALLOCATION_NOBJECTS 100
7067 +#define YAFFS_ALLOCATION_NTNODES 100
7068 +#define YAFFS_ALLOCATION_NLINKS 100
7070 +#define YAFFS_NOBJECT_BUCKETS 256
7072 +#define YAFFS_OBJECT_SPACE 0x40000
7073 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
7075 +/* Binary data version stamps */
7076 +#define YAFFS_SUMMARY_VERSION 1
7077 +#define YAFFS_CHECKPOINT_VERSION 7
7079 +#ifdef CONFIG_YAFFS_UNICODE
7080 +#define YAFFS_MAX_NAME_LENGTH 127
7081 +#define YAFFS_MAX_ALIAS_LENGTH 79
7082 +#else
7083 +#define YAFFS_MAX_NAME_LENGTH 255
7084 +#define YAFFS_MAX_ALIAS_LENGTH 159
7085 +#endif
7087 +#define YAFFS_SHORT_NAME_LENGTH 15
7089 +/* Some special object ids for pseudo objects */
7090 +#define YAFFS_OBJECTID_ROOT 1
7091 +#define YAFFS_OBJECTID_LOSTNFOUND 2
7092 +#define YAFFS_OBJECTID_UNLINKED 3
7093 +#define YAFFS_OBJECTID_DELETED 4
7095 +/* Fake object Id for summary data */
7096 +#define YAFFS_OBJECTID_SUMMARY 0x10
7098 +/* Pseudo object ids for checkpointing */
7099 +#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
7100 +#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
7102 +#define YAFFS_MAX_SHORT_OP_CACHES 20
7104 +#define YAFFS_N_TEMP_BUFFERS 6
7106 +/* We limit the number attempts at sucessfully saving a chunk of data.
7107 + * Small-page devices have 32 pages per block; large-page devices have 64.
7108 + * Default to something in the order of 5 to 10 blocks worth of chunks.
7109 + */
7110 +#define YAFFS_WR_ATTEMPTS (5*64)
7112 +/* Sequence numbers are used in YAFFS2 to determine block allocation order.
7113 + * The range is limited slightly to help distinguish bad numbers from good.
7114 + * This also allows us to perhaps in the future use special numbers for
7115 + * special purposes.
7116 + * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
7117 + * and is a larger number than the lifetime of a 2GB device.
7118 + */
7119 +#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
7120 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
7122 +/* Special sequence number for bad block that failed to be marked bad */
7123 +#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
7125 +/* ChunkCache is used for short read/write operations.*/
7126 +struct yaffs_cache {
7127 + struct yaffs_obj *object;
7128 + int chunk_id;
7129 + int last_use;
7130 + int dirty;
7131 + int n_bytes; /* Only valid if the cache is dirty */
7132 + int locked; /* Can't push out or flush while locked. */
7133 + u8 *data;
7136 +/* yaffs1 tags structures in RAM
7137 + * NB This uses bitfield. Bitfields should not straddle a u32 boundary
7138 + * otherwise the structure size will get blown out.
7139 + */
7141 +struct yaffs_tags {
7142 + u32 chunk_id:20;
7143 + u32 serial_number:2;
7144 + u32 n_bytes_lsb:10;
7145 + u32 obj_id:18;
7146 + u32 ecc:12;
7147 + u32 n_bytes_msb:2;
7150 +union yaffs_tags_union {
7151 + struct yaffs_tags as_tags;
7152 + u8 as_bytes[8];
7156 +/* Stuff used for extended tags in YAFFS2 */
7158 +enum yaffs_ecc_result {
7159 + YAFFS_ECC_RESULT_UNKNOWN,
7160 + YAFFS_ECC_RESULT_NO_ERROR,
7161 + YAFFS_ECC_RESULT_FIXED,
7162 + YAFFS_ECC_RESULT_UNFIXED
7165 +enum yaffs_obj_type {
7166 + YAFFS_OBJECT_TYPE_UNKNOWN,
7167 + YAFFS_OBJECT_TYPE_FILE,
7168 + YAFFS_OBJECT_TYPE_SYMLINK,
7169 + YAFFS_OBJECT_TYPE_DIRECTORY,
7170 + YAFFS_OBJECT_TYPE_HARDLINK,
7171 + YAFFS_OBJECT_TYPE_SPECIAL
7174 +#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
7176 +struct yaffs_ext_tags {
7177 + unsigned chunk_used; /* Status of the chunk: used or unused */
7178 + unsigned obj_id; /* If 0 this is not used */
7179 + unsigned chunk_id; /* If 0 this is a header, else a data chunk */
7180 + unsigned n_bytes; /* Only valid for data chunks */
7182 + /* The following stuff only has meaning when we read */
7183 + enum yaffs_ecc_result ecc_result;
7184 + unsigned block_bad;
7186 + /* YAFFS 1 stuff */
7187 + unsigned is_deleted; /* The chunk is marked deleted */
7188 + unsigned serial_number; /* Yaffs1 2-bit serial number */
7190 + /* YAFFS2 stuff */
7191 + unsigned seq_number; /* The sequence number of this block */
7193 + /* Extra info if this is an object header (YAFFS2 only) */
7195 + unsigned extra_available; /* Extra info available if not zero */
7196 + unsigned extra_parent_id; /* The parent object */
7197 + unsigned extra_is_shrink; /* Is it a shrink header? */
7198 + unsigned extra_shadows; /* Does this shadow another object? */
7200 + enum yaffs_obj_type extra_obj_type; /* What object type? */
7202 + loff_t extra_file_size; /* Length if it is a file */
7203 + unsigned extra_equiv_id; /* Equivalent object for a hard link */
7206 +/* Spare structure for YAFFS1 */
7207 +struct yaffs_spare {
7208 + u8 tb0;
7209 + u8 tb1;
7210 + u8 tb2;
7211 + u8 tb3;
7212 + u8 page_status; /* set to 0 to delete the chunk */
7213 + u8 block_status;
7214 + u8 tb4;
7215 + u8 tb5;
7216 + u8 ecc1[3];
7217 + u8 tb6;
7218 + u8 tb7;
7219 + u8 ecc2[3];
7222 +/*Special structure for passing through to mtd */
7223 +struct yaffs_nand_spare {
7224 + struct yaffs_spare spare;
7225 + int eccres1;
7226 + int eccres2;
7229 +/* Block data in RAM */
7231 +enum yaffs_block_state {
7232 + YAFFS_BLOCK_STATE_UNKNOWN = 0,
7234 + YAFFS_BLOCK_STATE_SCANNING,
7235 + /* Being scanned */
7237 + YAFFS_BLOCK_STATE_NEEDS_SCAN,
7238 + /* The block might have something on it (ie it is allocating or full,
7239 + * perhaps empty) but it needs to be scanned to determine its true
7240 + * state.
7241 + * This state is only valid during scanning.
7242 + * NB We tolerate empty because the pre-scanner might be incapable of
7243 + * deciding
7244 + * However, if this state is returned on a YAFFS2 device,
7245 + * then we expect a sequence number
7246 + */
7248 + YAFFS_BLOCK_STATE_EMPTY,
7249 + /* This block is empty */
7251 + YAFFS_BLOCK_STATE_ALLOCATING,
7252 + /* This block is partially allocated.
7253 + * At least one page holds valid data.
7254 + * This is the one currently being used for page
7255 + * allocation. Should never be more than one of these.
7256 + * If a block is only partially allocated at mount it is treated as
7257 + * full.
7258 + */
7260 + YAFFS_BLOCK_STATE_FULL,
7261 + /* All the pages in this block have been allocated.
7262 + * If a block was only partially allocated when mounted we treat
7263 + * it as fully allocated.
7264 + */
7266 + YAFFS_BLOCK_STATE_DIRTY,
7267 + /* The block was full and now all chunks have been deleted.
7268 + * Erase me, reuse me.
7269 + */
7271 + YAFFS_BLOCK_STATE_CHECKPOINT,
7272 + /* This block is assigned to holding checkpoint data. */
7274 + YAFFS_BLOCK_STATE_COLLECTING,
7275 + /* This block is being garbage collected */
7277 + YAFFS_BLOCK_STATE_DEAD
7278 + /* This block has failed and is not in use */
7281 +#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
7283 +struct yaffs_block_info {
7285 + s32 soft_del_pages:10; /* number of soft deleted pages */
7286 + s32 pages_in_use:10; /* number of pages in use */
7287 + u32 block_state:4; /* One of the above block states. */
7288 + /* NB use unsigned because enum is sometimes
7289 + * an int */
7290 + u32 needs_retiring:1; /* Data has failed on this block, */
7291 + /*need to get valid data off and retire*/
7292 + u32 skip_erased_check:1;/* Skip the erased check on this block */
7293 + u32 gc_prioritise:1; /* An ECC check or blank check has failed.
7294 + Block should be prioritised for GC */
7295 + u32 chunk_error_strikes:3; /* How many times we've had ecc etc
7296 + failures on this block and tried to reuse it */
7297 + u32 has_summary:1; /* The block has a summary */
7299 + u32 has_shrink_hdr:1; /* This block has at least one shrink header */
7300 + u32 seq_number; /* block sequence number for yaffs2 */
7304 +/* -------------------------- Object structure -------------------------------*/
7305 +/* This is the object structure as stored on NAND */
7307 +struct yaffs_obj_hdr {
7308 + enum yaffs_obj_type type;
7310 + /* Apply to everything */
7311 + int parent_obj_id;
7312 + u16 sum_no_longer_used; /* checksum of name. No longer used */
7313 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
7315 + /* The following apply to all object types except for hard links */
7316 + u32 yst_mode; /* protection */
7318 + u32 yst_uid;
7319 + u32 yst_gid;
7320 + u32 yst_atime;
7321 + u32 yst_mtime;
7322 + u32 yst_ctime;
7324 + /* File size applies to files only */
7325 + u32 file_size_low;
7327 + /* Equivalent object id applies to hard links only. */
7328 + int equiv_id;
7330 + /* Alias is for symlinks only. */
7331 + YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
7333 + u32 yst_rdev; /* stuff for block and char devices (major/min) */
7335 + u32 win_ctime[2];
7336 + u32 win_atime[2];
7337 + u32 win_mtime[2];
7339 + u32 inband_shadowed_obj_id;
7340 + u32 inband_is_shrink;
7342 + u32 file_size_high;
7343 + u32 reserved[1];
7344 + int shadows_obj; /* This object header shadows the
7345 + specified object if > 0 */
7347 + /* is_shrink applies to object headers written when wemake a hole. */
7348 + u32 is_shrink;
7352 +/*--------------------------- Tnode -------------------------- */
7354 +struct yaffs_tnode {
7355 + struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
7358 +/*------------------------ Object -----------------------------*/
7359 +/* An object can be one of:
7360 + * - a directory (no data, has children links
7361 + * - a regular file (data.... not prunes :->).
7362 + * - a symlink [symbolic link] (the alias).
7363 + * - a hard link
7364 + */
7366 +struct yaffs_file_var {
7367 + loff_t file_size;
7368 + loff_t scanned_size;
7369 + loff_t shrink_size;
7370 + int top_level;
7371 + struct yaffs_tnode *top;
7374 +struct yaffs_dir_var {
7375 + struct list_head children; /* list of child links */
7376 + struct list_head dirty; /* Entry for list of dirty directories */
7379 +struct yaffs_symlink_var {
7380 + YCHAR *alias;
7383 +struct yaffs_hardlink_var {
7384 + struct yaffs_obj *equiv_obj;
7385 + u32 equiv_id;
7388 +union yaffs_obj_var {
7389 + struct yaffs_file_var file_variant;
7390 + struct yaffs_dir_var dir_variant;
7391 + struct yaffs_symlink_var symlink_variant;
7392 + struct yaffs_hardlink_var hardlink_variant;
7395 +struct yaffs_obj {
7396 + u8 deleted:1; /* This should only apply to unlinked files. */
7397 + u8 soft_del:1; /* it has also been soft deleted */
7398 + u8 unlinked:1; /* An unlinked file.*/
7399 + u8 fake:1; /* A fake object has no presence on NAND. */
7400 + u8 rename_allowed:1; /* Some objects cannot be renamed. */
7401 + u8 unlink_allowed:1;
7402 + u8 dirty:1; /* the object needs to be written to flash */
7403 + u8 valid:1; /* When the file system is being loaded up, this
7404 + * object might be created before the data
7405 + * is available
7406 + * ie. file data chunks encountered before
7407 + * the header.
7408 + */
7409 + u8 lazy_loaded:1; /* This object has been lazy loaded and
7410 + * is missing some detail */
7412 + u8 defered_free:1; /* Object is removed from NAND, but is
7413 + * still in the inode cache.
7414 + * Free of object is defered.
7415 + * until the inode is released.
7416 + */
7417 + u8 being_created:1; /* This object is still being created
7418 + * so skip some verification checks. */
7419 + u8 is_shadowed:1; /* This object is shadowed on the way
7420 + * to being renamed. */
7422 + u8 xattr_known:1; /* We know if this has object has xattribs
7423 + * or not. */
7424 + u8 has_xattr:1; /* This object has xattribs.
7425 + * Only valid if xattr_known. */
7427 + u8 serial; /* serial number of chunk in NAND.*/
7428 + u16 sum; /* sum of the name to speed searching */
7430 + struct yaffs_dev *my_dev; /* The device I'm on */
7432 + struct list_head hash_link; /* list of objects in hash bucket */
7434 + struct list_head hard_links; /* hard linked object chain*/
7436 + /* directory structure stuff */
7437 + /* also used for linking up the free list */
7438 + struct yaffs_obj *parent;
7439 + struct list_head siblings;
7441 + /* Where's my object header in NAND? */
7442 + int hdr_chunk;
7444 + int n_data_chunks; /* Number of data chunks for this file. */
7446 + u32 obj_id; /* the object id value */
7448 + u32 yst_mode;
7450 + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
7452 +#ifdef CONFIG_YAFFS_WINCE
7453 + u32 win_ctime[2];
7454 + u32 win_mtime[2];
7455 + u32 win_atime[2];
7456 +#else
7457 + u32 yst_uid;
7458 + u32 yst_gid;
7459 + u32 yst_atime;
7460 + u32 yst_mtime;
7461 + u32 yst_ctime;
7462 +#endif
7464 + u32 yst_rdev;
7466 + void *my_inode;
7468 + enum yaffs_obj_type variant_type;
7470 + union yaffs_obj_var variant;
7474 +struct yaffs_obj_bucket {
7475 + struct list_head list;
7476 + int count;
7479 +/* yaffs_checkpt_obj holds the definition of an object as dumped
7480 + * by checkpointing.
7481 + */
7483 +struct yaffs_checkpt_obj {
7484 + int struct_type;
7485 + u32 obj_id;
7486 + u32 parent_id;
7487 + int hdr_chunk;
7488 + enum yaffs_obj_type variant_type:3;
7489 + u8 deleted:1;
7490 + u8 soft_del:1;
7491 + u8 unlinked:1;
7492 + u8 fake:1;
7493 + u8 rename_allowed:1;
7494 + u8 unlink_allowed:1;
7495 + u8 serial;
7496 + int n_data_chunks;
7497 + loff_t size_or_equiv_obj;
7500 +/*--------------------- Temporary buffers ----------------
7502 + * These are chunk-sized working buffers. Each device has a few.
7503 + */
7505 +struct yaffs_buffer {
7506 + u8 *buffer;
7507 + int in_use;
7510 +/*----------------- Device ---------------------------------*/
7512 +struct yaffs_param {
7513 + const YCHAR *name;
7515 + /*
7516 + * Entry parameters set up way early. Yaffs sets up the rest.
7517 + * The structure should be zeroed out before use so that unused
7518 + * and default values are zero.
7519 + */
7521 + int inband_tags; /* Use unband tags */
7522 + u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
7523 + be a power of 2 */
7524 + int chunks_per_block; /* does not need to be a power of 2 */
7525 + int spare_bytes_per_chunk; /* spare area size */
7526 + int start_block; /* Start block we're allowed to use */
7527 + int end_block; /* End block we're allowed to use */
7528 + int n_reserved_blocks; /* Tuneable so that we can reduce
7529 + * reserved blocks on NOR and RAM. */
7531 + int n_caches; /* If <= 0, then short op caching is disabled,
7532 + * else the number of short op caches.
7533 + */
7534 + int cache_bypass_aligned; /* If non-zero then bypass the cache for
7535 + * aligned writes.
7536 + */
7538 + int use_nand_ecc; /* Flag to decide whether or not to use
7539 + * NAND driver ECC on data (yaffs1) */
7540 + int tags_9bytes; /* Use 9 byte tags */
7541 + int no_tags_ecc; /* Flag to decide whether or not to do ECC
7542 + * on packed tags (yaffs2) */
7544 + int is_yaffs2; /* Use yaffs2 mode on this device */
7546 + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
7548 + int refresh_period; /* How often to check for a block refresh */
7550 + /* Checkpoint control. Can be set before or after initialisation */
7551 + u8 skip_checkpt_rd;
7552 + u8 skip_checkpt_wr;
7554 + int enable_xattr; /* Enable xattribs */
7556 + int max_objects; /*
7557 + * Set to limit the number of objects created.
7558 + * 0 = no limit.
7559 + */
7561 + /* The remove_obj_fn function must be supplied by OS flavours that
7562 + * need it.
7563 + * yaffs direct uses it to implement the faster readdir.
7564 + * Linux uses it to protect the directory during unlocking.
7565 + */
7566 + void (*remove_obj_fn) (struct yaffs_obj *obj);
7568 + /* Callback to mark the superblock dirty */
7569 + void (*sb_dirty_fn) (struct yaffs_dev *dev);
7571 + /* Callback to control garbage collection. */
7572 + unsigned (*gc_control_fn) (struct yaffs_dev *dev);
7574 + /* Debug control flags. Don't use unless you know what you're doing */
7575 + int use_header_file_size; /* Flag to determine if we should use
7576 + * file sizes from the header */
7577 + int disable_lazy_load; /* Disable lazy loading on this device */
7578 + int wide_tnodes_disabled; /* Set to disable wide tnodes */
7579 + int disable_soft_del; /* yaffs 1 only: Set to disable the use of
7580 + * softdeletion. */
7582 + int defered_dir_update; /* Set to defer directory updates */
7584 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
7585 + int auto_unicode;
7586 +#endif
7587 + int always_check_erased; /* Force chunk erased check always on */
7589 + int disable_summary;
7590 + int disable_bad_block_marking;
7594 +struct yaffs_driver {
7595 + int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
7596 + const u8 *data, int data_len,
7597 + const u8 *oob, int oob_len);
7598 + int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
7599 + u8 *data, int data_len,
7600 + u8 *oob, int oob_len,
7601 + enum yaffs_ecc_result *ecc_result);
7602 + int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
7603 + int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
7604 + int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
7605 + int (*drv_initialise_fn) (struct yaffs_dev *dev);
7606 + int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
7609 +struct yaffs_tags_handler {
7610 + int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
7611 + int nand_chunk, const u8 *data,
7612 + const struct yaffs_ext_tags *tags);
7613 + int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
7614 + int nand_chunk, u8 *data,
7615 + struct yaffs_ext_tags *tags);
7617 + int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
7618 + enum yaffs_block_state *state,
7619 + u32 *seq_number);
7620 + int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
7623 +struct yaffs_dev {
7624 + struct yaffs_param param;
7625 + struct yaffs_driver drv;
7626 + struct yaffs_tags_handler tagger;
7628 + /* Context storage. Holds extra OS specific data for this device */
7630 + void *os_context;
7631 + void *driver_context;
7633 + struct list_head dev_list;
7635 + int ll_init;
7636 + /* Runtime parameters. Set up by YAFFS. */
7637 + int data_bytes_per_chunk;
7639 + /* Non-wide tnode stuff */
7640 + u16 chunk_grp_bits; /* Number of bits that need to be resolved if
7641 + * the tnodes are not wide enough.
7642 + */
7643 + u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
7645 + /* Stuff to support wide tnodes */
7646 + u32 tnode_width;
7647 + u32 tnode_mask;
7648 + u32 tnode_size;
7650 + /* Stuff for figuring out file offset to chunk conversions */
7651 + u32 chunk_shift; /* Shift value */
7652 + u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
7653 + u32 chunk_mask; /* Mask to use for power-of-2 case */
7655 + int is_mounted;
7656 + int read_only;
7657 + int is_checkpointed;
7659 + /* Stuff to support block offsetting to support start block zero */
7660 + int internal_start_block;
7661 + int internal_end_block;
7662 + int block_offset;
7663 + int chunk_offset;
7665 + /* Runtime checkpointing stuff */
7666 + int checkpt_page_seq; /* running sequence number of checkpt pages */
7667 + int checkpt_byte_count;
7668 + int checkpt_byte_offs;
7669 + u8 *checkpt_buffer;
7670 + int checkpt_open_write;
7671 + int blocks_in_checkpt;
7672 + int checkpt_cur_chunk;
7673 + int checkpt_cur_block;
7674 + int checkpt_next_block;
7675 + int *checkpt_block_list;
7676 + int checkpt_max_blocks;
7677 + u32 checkpt_sum;
7678 + u32 checkpt_xor;
7680 + int checkpoint_blocks_required; /* Number of blocks needed to store
7681 + * current checkpoint set */
7683 + /* Block Info */
7684 + struct yaffs_block_info *block_info;
7685 + u8 *chunk_bits; /* bitmap of chunks in use */
7686 + u8 block_info_alt:1; /* allocated using alternative alloc */
7687 + u8 chunk_bits_alt:1; /* allocated using alternative alloc */
7688 + int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
7689 + * Must be consistent with chunks_per_block.
7690 + */
7692 + int n_erased_blocks;
7693 + int alloc_block; /* Current block being allocated off */
7694 + u32 alloc_page;
7695 + int alloc_block_finder; /* Used to search for next allocation block */
7697 + /* Object and Tnode memory management */
7698 + void *allocator;
7699 + int n_obj;
7700 + int n_tnodes;
7702 + int n_hardlinks;
7704 + struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
7705 + u32 bucket_finder;
7707 + int n_free_chunks;
7709 + /* Garbage collection control */
7710 + u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
7711 + u32 n_clean_ups;
7713 + unsigned has_pending_prioritised_gc; /* We think this device might
7714 + have pending prioritised gcs */
7715 + unsigned gc_disable;
7716 + unsigned gc_block_finder;
7717 + unsigned gc_dirtiest;
7718 + unsigned gc_pages_in_use;
7719 + unsigned gc_not_done;
7720 + unsigned gc_block;
7721 + unsigned gc_chunk;
7722 + unsigned gc_skip;
7723 + struct yaffs_summary_tags *gc_sum_tags;
7725 + /* Special directories */
7726 + struct yaffs_obj *root_dir;
7727 + struct yaffs_obj *lost_n_found;
7729 + int buffered_block; /* Which block is buffered here? */
7730 + int doing_buffered_block_rewrite;
7732 + struct yaffs_cache *cache;
7733 + int cache_last_use;
7735 + /* Stuff for background deletion and unlinked files. */
7736 + struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
7737 + files live. */
7738 + struct yaffs_obj *del_dir; /* Directory where deleted objects are
7739 + sent to disappear. */
7740 + struct yaffs_obj *unlinked_deletion; /* Current file being
7741 + background deleted. */
7742 + int n_deleted_files; /* Count of files awaiting deletion; */
7743 + int n_unlinked_files; /* Count of unlinked files. */
7744 + int n_bg_deletions; /* Count of background deletions. */
7746 + /* Temporary buffer management */
7747 + struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
7748 + int max_temp;
7749 + int temp_in_use;
7750 + int unmanaged_buffer_allocs;
7751 + int unmanaged_buffer_deallocs;
7753 + /* yaffs2 runtime stuff */
7754 + unsigned seq_number; /* Sequence number of currently
7755 + allocating block */
7756 + unsigned oldest_dirty_seq;
7757 + unsigned oldest_dirty_block;
7759 + /* Block refreshing */
7760 + int refresh_skip; /* A skip down counter.
7761 + * Refresh happens when this gets to zero. */
7763 + /* Dirty directory handling */
7764 + struct list_head dirty_dirs; /* List of dirty directories */
7766 + /* Summary */
7767 + int chunks_per_summary;
7768 + struct yaffs_summary_tags *sum_tags;
7770 + /* Statistics */
7771 + u32 n_page_writes;
7772 + u32 n_page_reads;
7773 + u32 n_erasures;
7774 + u32 n_bad_queries;
7775 + u32 n_bad_markings;
7776 + u32 n_erase_failures;
7777 + u32 n_gc_copies;
7778 + u32 all_gcs;
7779 + u32 passive_gc_count;
7780 + u32 oldest_dirty_gc_count;
7781 + u32 n_gc_blocks;
7782 + u32 bg_gcs;
7783 + u32 n_retried_writes;
7784 + u32 n_retired_blocks;
7785 + u32 n_ecc_fixed;
7786 + u32 n_ecc_unfixed;
7787 + u32 n_tags_ecc_fixed;
7788 + u32 n_tags_ecc_unfixed;
7789 + u32 n_deletions;
7790 + u32 n_unmarked_deletions;
7791 + u32 refresh_count;
7792 + u32 cache_hits;
7793 + u32 tags_used;
7794 + u32 summary_used;
7798 +/* The CheckpointDevice structure holds the device information that changes
7799 + *at runtime and must be preserved over unmount/mount cycles.
7800 + */
7801 +struct yaffs_checkpt_dev {
7802 + int struct_type;
7803 + int n_erased_blocks;
7804 + int alloc_block; /* Current block being allocated off */
7805 + u32 alloc_page;
7806 + int n_free_chunks;
7808 + int n_deleted_files; /* Count of files awaiting deletion; */
7809 + int n_unlinked_files; /* Count of unlinked files. */
7810 + int n_bg_deletions; /* Count of background deletions. */
7812 + /* yaffs2 runtime stuff */
7813 + unsigned seq_number; /* Sequence number of currently
7814 + * allocating block */
7818 +struct yaffs_checkpt_validity {
7819 + int struct_type;
7820 + u32 magic;
7821 + u32 version;
7822 + u32 head;
7825 +struct yaffs_shadow_fixer {
7826 + int obj_id;
7827 + int shadowed_id;
7828 + struct yaffs_shadow_fixer *next;
7831 +/* Structure for doing xattr modifications */
7832 +struct yaffs_xattr_mod {
7833 + int set; /* If 0 then this is a deletion */
7834 + const YCHAR *name;
7835 + const void *data;
7836 + int size;
7837 + int flags;
7838 + int result;
7841 +/*----------------------- YAFFS Functions -----------------------*/
7843 +int yaffs_guts_initialise(struct yaffs_dev *dev);
7844 +void yaffs_deinitialise(struct yaffs_dev *dev);
7846 +int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
7848 +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
7849 + struct yaffs_obj *new_dir, const YCHAR * new_name);
7851 +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
7852 +int yaffs_del_obj(struct yaffs_obj *obj);
7853 +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
7854 + enum yaffs_obj_type type);
7857 +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
7858 +loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
7859 +int yaffs_get_obj_inode(struct yaffs_obj *obj);
7860 +unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
7861 +int yaffs_get_obj_link_count(struct yaffs_obj *obj);
7863 +/* File operations */
7864 +int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
7865 + int n_bytes);
7866 +int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
7867 + int n_bytes, int write_trhrough);
7868 +int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
7870 +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
7871 + const YCHAR *name, u32 mode, u32 uid,
7872 + u32 gid);
7874 +int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
7876 +/* Flushing and checkpointing */
7877 +void yaffs_flush_whole_cache(struct yaffs_dev *dev);
7879 +int yaffs_checkpoint_save(struct yaffs_dev *dev);
7880 +int yaffs_checkpoint_restore(struct yaffs_dev *dev);
7882 +/* Directory operations */
7883 +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
7884 + u32 mode, u32 uid, u32 gid);
7885 +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
7886 + const YCHAR *name);
7887 +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
7889 +/* Link operations */
7890 +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
7891 + struct yaffs_obj *equiv_obj);
7893 +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
7895 +/* Symlink operations */
7896 +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
7897 + const YCHAR *name, u32 mode, u32 uid,
7898 + u32 gid, const YCHAR *alias);
7899 +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
7901 +/* Special inodes (fifos, sockets and devices) */
7902 +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
7903 + const YCHAR *name, u32 mode, u32 uid,
7904 + u32 gid, u32 rdev);
7906 +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
7907 + const void *value, int size, int flags);
7908 +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
7909 + int size);
7910 +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
7911 +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
7913 +/* Special directories */
7914 +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
7915 +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
7917 +void yaffs_handle_defered_free(struct yaffs_obj *obj);
7919 +void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
7921 +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
7923 +/* Debug dump */
7924 +int yaffs_dump_obj(struct yaffs_obj *obj);
7926 +void yaffs_guts_test(struct yaffs_dev *dev);
7927 +int yaffs_guts_ll_init(struct yaffs_dev *dev);
7930 +/* A few useful functions to be used within the core files*/
7931 +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
7932 + int lyn);
7933 +int yaffs_check_ff(u8 *buffer, int n_bytes);
7934 +void yaffs_handle_chunk_error(struct yaffs_dev *dev,
7935 + struct yaffs_block_info *bi);
7937 +u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
7938 +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
7940 +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
7941 + int number,
7942 + enum yaffs_obj_type type);
7943 +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
7944 + int nand_chunk, int in_scan);
7945 +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
7946 +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
7947 + const struct yaffs_obj_hdr *oh);
7948 +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
7949 +YCHAR *yaffs_clone_str(const YCHAR *str);
7950 +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
7951 +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
7952 +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
7953 + int force, int is_shrink, int shadows,
7954 + struct yaffs_xattr_mod *xop);
7955 +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
7956 + int backward_scanning);
7957 +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
7958 +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
7959 +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
7960 + struct yaffs_file_var *file_struct,
7961 + u32 chunk_id,
7962 + struct yaffs_tnode *passed_tn);
7964 +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
7965 + int n_bytes, int write_trhrough);
7966 +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
7967 +void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
7969 +int yaffs_count_free_chunks(struct yaffs_dev *dev);
7971 +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
7972 + struct yaffs_file_var *file_struct,
7973 + u32 chunk_id);
7975 +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
7976 + unsigned pos);
7978 +int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
7980 +int yaffs_guts_format_dev(struct yaffs_dev *dev);
7982 +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
7983 + int *chunk_out, u32 *offset_out);
7985 + * Marshalling functions to get loff_t file sizes into aand out of
7986 + * object headers.
7987 + */
7988 +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
7989 +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
7990 +loff_t yaffs_max_file_size(struct yaffs_dev *dev);
7993 + * Debug function to count number of blocks in each state
7994 + * NB Needs to be called with correct number of integers
7995 + */
7997 +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
7999 +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
8000 + struct yaffs_ext_tags *tags);
8002 +#endif
8003 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_linux.h linux-3.4.90/fs/yaffs2/yaffs_linux.h
8004 --- linux-3.4.90.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
8005 +++ linux-3.4.90/fs/yaffs2/yaffs_linux.h 2014-05-17 15:08:09.000000000 +0200
8006 @@ -0,0 +1,48 @@
8008 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8010 + * Copyright (C) 2002-2011 Aleph One Ltd.
8011 + * for Toby Churchill Ltd and Brightstar Engineering
8013 + * Created by Charles Manning <charles@aleph1.co.uk>
8015 + * This program is free software; you can redistribute it and/or modify
8016 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8017 + * published by the Free Software Foundation.
8019 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8020 + */
8022 +#ifndef __YAFFS_LINUX_H__
8023 +#define __YAFFS_LINUX_H__
8025 +#include "yportenv.h"
8027 +struct yaffs_linux_context {
8028 + struct list_head context_list; /* List of these we have mounted */
8029 + struct yaffs_dev *dev;
8030 + struct super_block *super;
8031 + struct task_struct *bg_thread; /* Background thread for this device */
8032 + int bg_running;
8033 + struct mutex gross_lock; /* Gross locking mutex*/
8034 + u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
8035 + * at compile time so we have to allocate it.
8036 + */
8037 + struct list_head search_contexts;
8038 + struct task_struct *readdir_process;
8039 + unsigned mount_id;
8040 + int dirty;
8043 +#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
8044 +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
8046 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
8047 +#define WRITE_SIZE_STR "writesize"
8048 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
8049 +#else
8050 +#define WRITE_SIZE_STR "oobblock"
8051 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
8052 +#endif
8054 +#endif
8055 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.c linux-3.4.90/fs/yaffs2/yaffs_mtdif.c
8056 --- linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
8057 +++ linux-3.4.90/fs/yaffs2/yaffs_mtdif.c 2014-05-17 15:08:09.000000000 +0200
8058 @@ -0,0 +1,309 @@
8060 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8062 + * Copyright (C) 2002-2011 Aleph One Ltd.
8063 + * for Toby Churchill Ltd and Brightstar Engineering
8065 + * Created by Charles Manning <charles@aleph1.co.uk>
8067 + * This program is free software; you can redistribute it and/or modify
8068 + * it under the terms of the GNU General Public License version 2 as
8069 + * published by the Free Software Foundation.
8070 + */
8072 +#include "yportenv.h"
8074 +#include "yaffs_mtdif.h"
8076 +#include "linux/mtd/mtd.h"
8077 +#include "linux/types.h"
8078 +#include "linux/time.h"
8079 +#include "linux/major.h"
8080 +#include "linux/mtd/nand.h"
8081 +#include "linux/kernel.h"
8082 +#include "linux/version.h"
8083 +#include "linux/types.h"
8085 +#include "yaffs_trace.h"
8086 +#include "yaffs_guts.h"
8087 +#include "yaffs_linux.h"
8090 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
8091 +#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
8092 +#endif
8095 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
8096 +#define mtd_erase(m, ei) (m)->erase(m, ei)
8097 +#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
8098 +#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
8099 +#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
8100 +#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
8101 +#endif
8105 +int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
8107 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8108 + u32 addr =
8109 + ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
8110 + dev->param.chunks_per_block;
8111 + struct erase_info ei;
8112 + int retval = 0;
8114 + ei.mtd = mtd;
8115 + ei.addr = addr;
8116 + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
8117 + ei.time = 1000;
8118 + ei.retries = 2;
8119 + ei.callback = NULL;
8120 + ei.priv = (u_long) dev;
8122 + retval = mtd_erase(mtd, &ei);
8124 + if (retval == 0)
8125 + return YAFFS_OK;
8127 + return YAFFS_FAIL;
8131 +static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
8132 + const u8 *data, int data_len,
8133 + const u8 *oob, int oob_len)
8135 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8136 + loff_t addr;
8137 + struct mtd_oob_ops ops;
8138 + int retval;
8140 + yaffs_trace(YAFFS_TRACE_MTD,
8141 + "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
8142 + dev, nand_chunk, data, data_len, oob, oob_len);
8144 + if (!data || !data_len) {
8145 + data = NULL;
8146 + data_len = 0;
8149 + if (!oob || !oob_len) {
8150 + oob = NULL;
8151 + oob_len = 0;
8154 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
8155 + memset(&ops, 0, sizeof(ops));
8156 + ops.mode = MTD_OPS_AUTO_OOB;
8157 + ops.len = (data) ? data_len : 0;
8158 + ops.ooblen = oob_len;
8159 + ops.datbuf = (u8 *)data;
8160 + ops.oobbuf = (u8 *)oob;
8162 + retval = mtd_write_oob(mtd, addr, &ops);
8163 + if (retval) {
8164 + yaffs_trace(YAFFS_TRACE_MTD,
8165 + "write_oob failed, chunk %d, mtd error %d",
8166 + nand_chunk, retval);
8168 + return retval ? YAFFS_FAIL : YAFFS_OK;
8171 +static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
8172 + u8 *data, int data_len,
8173 + u8 *oob, int oob_len,
8174 + enum yaffs_ecc_result *ecc_result)
8176 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8177 + loff_t addr;
8178 + struct mtd_oob_ops ops;
8179 + int retval;
8181 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
8182 + memset(&ops, 0, sizeof(ops));
8183 + ops.mode = MTD_OPS_AUTO_OOB;
8184 + ops.len = (data) ? data_len : 0;
8185 + ops.ooblen = oob_len;
8186 + ops.datbuf = data;
8187 + ops.oobbuf = oob;
8189 +#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
8190 + /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
8191 + * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
8192 + */
8193 + ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
8194 +#endif
8195 + /* Read page and oob using MTD.
8196 + * Check status and determine ECC result.
8197 + */
8198 + retval = mtd_read_oob(mtd, addr, &ops);
8199 + if (retval)
8200 + yaffs_trace(YAFFS_TRACE_MTD,
8201 + "read_oob failed, chunk %d, mtd error %d",
8202 + nand_chunk, retval);
8204 + switch (retval) {
8205 + case 0:
8206 + /* no error */
8207 + if(ecc_result)
8208 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
8209 + break;
8211 + case -EUCLEAN:
8212 + /* MTD's ECC fixed the data */
8213 + if(ecc_result)
8214 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
8215 + dev->n_ecc_fixed++;
8216 + break;
8218 + case -EBADMSG:
8219 + default:
8220 + /* MTD's ECC could not fix the data */
8221 + dev->n_ecc_unfixed++;
8222 + if(ecc_result)
8223 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
8224 + return YAFFS_FAIL;
8227 + return YAFFS_OK;
8230 +static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
8232 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8234 + loff_t addr;
8235 + struct erase_info ei;
8236 + int retval = 0;
8237 + u32 block_size;
8239 + block_size = dev->param.total_bytes_per_chunk *
8240 + dev->param.chunks_per_block;
8241 + addr = ((loff_t) block_no) * block_size;
8243 + ei.mtd = mtd;
8244 + ei.addr = addr;
8245 + ei.len = block_size;
8246 + ei.time = 1000;
8247 + ei.retries = 2;
8248 + ei.callback = NULL;
8249 + ei.priv = (u_long) dev;
8251 + retval = mtd_erase(mtd, &ei);
8253 + if (retval == 0)
8254 + return YAFFS_OK;
8256 + return YAFFS_FAIL;
8259 +static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
8261 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8262 + int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
8263 + int retval;
8265 + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
8267 + retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
8268 + return (retval) ? YAFFS_FAIL : YAFFS_OK;
8271 +static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
8273 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8274 + int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
8275 + int retval;
8277 + yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
8279 + retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
8280 + return (retval) ? YAFFS_FAIL : YAFFS_OK;
8283 +static int yaffs_mtd_initialise(struct yaffs_dev *dev)
8285 + return YAFFS_OK;
8288 +static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
8290 + return YAFFS_OK;
8294 +void yaffs_mtd_drv_install(struct yaffs_dev *dev)
8296 + struct yaffs_driver *drv = &dev->drv;
8298 + drv->drv_write_chunk_fn = yaffs_mtd_write;
8299 + drv->drv_read_chunk_fn = yaffs_mtd_read;
8300 + drv->drv_erase_fn = yaffs_mtd_erase;
8301 + drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
8302 + drv->drv_check_bad_fn = yaffs_mtd_check_bad;
8303 + drv->drv_initialise_fn = yaffs_mtd_initialise;
8304 + drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
8308 +struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
8310 + struct mtd_info *mtd;
8312 + mtd = yaffs_get_mtd_device(sdev);
8314 + /* Check it's an mtd device..... */
8315 + if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
8316 + return NULL; /* This isn't an mtd device */
8318 + /* Check it's NAND */
8319 + if (mtd->type != MTD_NANDFLASH) {
8320 + yaffs_trace(YAFFS_TRACE_ALWAYS,
8321 + "yaffs: MTD device is not NAND it's type %d",
8322 + mtd->type);
8323 + return NULL;
8326 + yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
8327 + yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
8328 + yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
8329 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
8330 + yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
8331 +#else
8332 + yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
8333 +#endif
8335 + return mtd;
8338 +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
8340 + if (yaffs_version == 2) {
8341 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
8342 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
8343 + !inband_tags) {
8344 + yaffs_trace(YAFFS_TRACE_ALWAYS,
8345 + "MTD device does not have the right page sizes"
8346 + );
8347 + return -1;
8349 + } else {
8350 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
8351 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
8352 + yaffs_trace(YAFFS_TRACE_ALWAYS,
8353 + "MTD device does not support have the right page sizes"
8354 + );
8355 + return -1;
8359 + return 0;
8363 +void yaffs_put_mtd_device(struct mtd_info *mtd)
8365 + if(mtd)
8366 + put_mtd_device(mtd);
8368 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.h linux-3.4.90/fs/yaffs2/yaffs_mtdif.h
8369 --- linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
8370 +++ linux-3.4.90/fs/yaffs2/yaffs_mtdif.h 2014-05-17 15:08:09.000000000 +0200
8371 @@ -0,0 +1,25 @@
8373 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8375 + * Copyright (C) 2002-2011 Aleph One Ltd.
8376 + * for Toby Churchill Ltd and Brightstar Engineering
8378 + * Created by Charles Manning <charles@aleph1.co.uk>
8380 + * This program is free software; you can redistribute it and/or modify
8381 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8382 + * published by the Free Software Foundation.
8384 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8385 + */
8387 +#ifndef __YAFFS_MTDIF_H__
8388 +#define __YAFFS_MTDIF_H__
8390 +#include "yaffs_guts.h"
8392 +void yaffs_mtd_drv_install(struct yaffs_dev *dev);
8393 +struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
8394 +void yaffs_put_mtd_device(struct mtd_info *mtd);
8395 +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
8396 +#endif
8397 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.c linux-3.4.90/fs/yaffs2/yaffs_nameval.c
8398 --- linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
8399 +++ linux-3.4.90/fs/yaffs2/yaffs_nameval.c 2014-05-17 15:08:09.000000000 +0200
8400 @@ -0,0 +1,208 @@
8402 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8404 + * Copyright (C) 2002-2011 Aleph One Ltd.
8405 + * for Toby Churchill Ltd and Brightstar Engineering
8407 + * Created by Charles Manning <charles@aleph1.co.uk>
8409 + * This program is free software; you can redistribute it and/or modify
8410 + * it under the terms of the GNU General Public License version 2 as
8411 + * published by the Free Software Foundation.
8412 + */
8415 + * This simple implementation of a name-value store assumes a small number of
8416 +* values and fits into a small finite buffer.
8418 + * Each attribute is stored as a record:
8419 + * sizeof(int) bytes record size.
8420 + * strnlen+1 bytes name null terminated.
8421 + * nbytes value.
8422 + * ----------
8423 + * total size stored in record size
8425 + * This code has not been tested with unicode yet.
8426 + */
8428 +#include "yaffs_nameval.h"
8430 +#include "yportenv.h"
8432 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
8433 + int *exist_size)
8435 + int pos = 0;
8436 + int size;
8438 + memcpy(&size, xb, sizeof(int));
8439 + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
8440 + if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
8441 + name, size)) {
8442 + if (exist_size)
8443 + *exist_size = size;
8444 + return pos;
8446 + pos += size;
8447 + if (pos < xb_size - sizeof(int))
8448 + memcpy(&size, xb + pos, sizeof(int));
8449 + else
8450 + size = 0;
8452 + if (exist_size)
8453 + *exist_size = 0;
8454 + return -ENODATA;
8457 +static int nval_used(const char *xb, int xb_size)
8459 + int pos = 0;
8460 + int size;
8462 + memcpy(&size, xb + pos, sizeof(int));
8463 + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
8464 + pos += size;
8465 + if (pos < xb_size - sizeof(int))
8466 + memcpy(&size, xb + pos, sizeof(int));
8467 + else
8468 + size = 0;
8470 + return pos;
8473 +int nval_del(char *xb, int xb_size, const YCHAR *name)
8475 + int pos = nval_find(xb, xb_size, name, NULL);
8476 + int size;
8478 + if (pos < 0 || pos >= xb_size)
8479 + return -ENODATA;
8481 + /* Find size, shift rest over this record,
8482 + * then zero out the rest of buffer */
8483 + memcpy(&size, xb + pos, sizeof(int));
8484 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
8485 + memset(xb + (xb_size - size), 0, size);
8486 + return 0;
8489 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
8490 + int bsize, int flags)
8492 + int pos;
8493 + int namelen = strnlen(name, xb_size);
8494 + int reclen;
8495 + int size_exist = 0;
8496 + int space;
8497 + int start;
8499 + pos = nval_find(xb, xb_size, name, &size_exist);
8501 + if (flags & XATTR_CREATE && pos >= 0)
8502 + return -EEXIST;
8503 + if (flags & XATTR_REPLACE && pos < 0)
8504 + return -ENODATA;
8506 + start = nval_used(xb, xb_size);
8507 + space = xb_size - start + size_exist;
8509 + reclen = (sizeof(int) + namelen + 1 + bsize);
8511 + if (reclen > space)
8512 + return -ENOSPC;
8514 + if (pos >= 0) {
8515 + nval_del(xb, xb_size, name);
8516 + start = nval_used(xb, xb_size);
8519 + pos = start;
8521 + memcpy(xb + pos, &reclen, sizeof(int));
8522 + pos += sizeof(int);
8523 + strncpy((YCHAR *) (xb + pos), name, reclen);
8524 + pos += (namelen + 1);
8525 + memcpy(xb + pos, buf, bsize);
8526 + return 0;
8529 +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
8530 + int bsize)
8532 + int pos = nval_find(xb, xb_size, name, NULL);
8533 + int size;
8535 + if (pos >= 0 && pos < xb_size) {
8537 + memcpy(&size, xb + pos, sizeof(int));
8538 + pos += sizeof(int); /* advance past record length */
8539 + size -= sizeof(int);
8541 + /* Advance over name string */
8542 + while (xb[pos] && size > 0 && pos < xb_size) {
8543 + pos++;
8544 + size--;
8546 + /*Advance over NUL */
8547 + pos++;
8548 + size--;
8550 + /* If bsize is zero then this is a size query.
8551 + * Return the size, but don't copy.
8552 + */
8553 + if (!bsize)
8554 + return size;
8556 + if (size <= bsize) {
8557 + memcpy(buf, xb + pos, size);
8558 + return size;
8561 + if (pos >= 0)
8562 + return -ERANGE;
8564 + return -ENODATA;
8567 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
8569 + int pos = 0;
8570 + int size;
8571 + int name_len;
8572 + int ncopied = 0;
8573 + int filled = 0;
8575 + memcpy(&size, xb + pos, sizeof(int));
8576 + while (size > sizeof(int) &&
8577 + size <= xb_size &&
8578 + (pos + size) < xb_size &&
8579 + !filled) {
8580 + pos += sizeof(int);
8581 + size -= sizeof(int);
8582 + name_len = strnlen((YCHAR *) (xb + pos), size);
8583 + if (ncopied + name_len + 1 < bsize) {
8584 + memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
8585 + buf += name_len;
8586 + *buf = '\0';
8587 + buf++;
8588 + if (sizeof(YCHAR) > 1) {
8589 + *buf = '\0';
8590 + buf++;
8592 + ncopied += (name_len + 1);
8593 + } else {
8594 + filled = 1;
8596 + pos += size;
8597 + if (pos < xb_size - sizeof(int))
8598 + memcpy(&size, xb + pos, sizeof(int));
8599 + else
8600 + size = 0;
8602 + return ncopied;
8605 +int nval_hasvalues(const char *xb, int xb_size)
8607 + return nval_used(xb, xb_size) > 0;
8609 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.h linux-3.4.90/fs/yaffs2/yaffs_nameval.h
8610 --- linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
8611 +++ linux-3.4.90/fs/yaffs2/yaffs_nameval.h 2014-05-17 15:08:09.000000000 +0200
8612 @@ -0,0 +1,28 @@
8614 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8616 + * Copyright (C) 2002-2011 Aleph One Ltd.
8617 + * for Toby Churchill Ltd and Brightstar Engineering
8619 + * Created by Charles Manning <charles@aleph1.co.uk>
8621 + * This program is free software; you can redistribute it and/or modify
8622 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8623 + * published by the Free Software Foundation.
8625 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8626 + */
8628 +#ifndef __NAMEVAL_H__
8629 +#define __NAMEVAL_H__
8631 +#include "yportenv.h"
8633 +int nval_del(char *xb, int xb_size, const YCHAR * name);
8634 +int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
8635 + int bsize, int flags);
8636 +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
8637 + int bsize);
8638 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
8639 +int nval_hasvalues(const char *xb, int xb_size);
8640 +#endif
8641 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nand.c linux-3.4.90/fs/yaffs2/yaffs_nand.c
8642 --- linux-3.4.90.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
8643 +++ linux-3.4.90/fs/yaffs2/yaffs_nand.c 2014-05-17 15:08:09.000000000 +0200
8644 @@ -0,0 +1,122 @@
8646 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8648 + * Copyright (C) 2002-2011 Aleph One Ltd.
8649 + * for Toby Churchill Ltd and Brightstar Engineering
8651 + * Created by Charles Manning <charles@aleph1.co.uk>
8653 + * This program is free software; you can redistribute it and/or modify
8654 + * it under the terms of the GNU General Public License version 2 as
8655 + * published by the Free Software Foundation.
8656 + */
8658 +#include "yaffs_nand.h"
8659 +#include "yaffs_tagscompat.h"
8661 +#include "yaffs_getblockinfo.h"
8662 +#include "yaffs_summary.h"
8664 +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
8666 + return chunk - dev->chunk_offset;
8669 +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
8670 + u8 *buffer, struct yaffs_ext_tags *tags)
8672 + int result;
8673 + struct yaffs_ext_tags local_tags;
8674 + int flash_chunk = apply_chunk_offset(dev, nand_chunk);
8676 + dev->n_page_reads++;
8678 + /* If there are no tags provided use local tags. */
8679 + if (!tags)
8680 + tags = &local_tags;
8682 + result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
8683 + if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
8685 + struct yaffs_block_info *bi;
8686 + bi = yaffs_get_block_info(dev,
8687 + nand_chunk /
8688 + dev->param.chunks_per_block);
8689 + yaffs_handle_chunk_error(dev, bi);
8691 + return result;
8694 +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
8695 + int nand_chunk,
8696 + const u8 *buffer, struct yaffs_ext_tags *tags)
8698 + int result;
8699 + int flash_chunk = apply_chunk_offset(dev, nand_chunk);
8701 + dev->n_page_writes++;
8703 + if (!tags) {
8704 + yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
8705 + BUG();
8706 + return YAFFS_FAIL;
8709 + tags->seq_number = dev->seq_number;
8710 + tags->chunk_used = 1;
8711 + yaffs_trace(YAFFS_TRACE_WRITE,
8712 + "Writing chunk %d tags %d %d",
8713 + nand_chunk, tags->obj_id, tags->chunk_id);
8715 + result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
8716 + buffer, tags);
8718 + yaffs_summary_add(dev, tags, nand_chunk);
8720 + return result;
8723 +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
8725 + block_no -= dev->block_offset;
8726 + dev->n_bad_markings++;
8728 + if (dev->param.disable_bad_block_marking)
8729 + return YAFFS_OK;
8731 + return dev->tagger.mark_bad_fn(dev, block_no);
8735 +int yaffs_query_init_block_state(struct yaffs_dev *dev,
8736 + int block_no,
8737 + enum yaffs_block_state *state,
8738 + u32 *seq_number)
8740 + block_no -= dev->block_offset;
8741 + return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
8744 +int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
8746 + int result;
8748 + block_no -= dev->block_offset;
8749 + dev->n_erasures++;
8750 + result = dev->drv.drv_erase_fn(dev, block_no);
8751 + return result;
8754 +int yaffs_init_nand(struct yaffs_dev *dev)
8756 + if (dev->drv.drv_initialise_fn)
8757 + return dev->drv.drv_initialise_fn(dev);
8758 + return YAFFS_OK;
8761 +int yaffs_deinit_nand(struct yaffs_dev *dev)
8763 + if (dev->drv.drv_deinitialise_fn)
8764 + return dev->drv.drv_deinitialise_fn(dev);
8765 + return YAFFS_OK;
8767 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nand.h linux-3.4.90/fs/yaffs2/yaffs_nand.h
8768 --- linux-3.4.90.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
8769 +++ linux-3.4.90/fs/yaffs2/yaffs_nand.h 2014-05-17 15:08:09.000000000 +0200
8770 @@ -0,0 +1,39 @@
8772 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8774 + * Copyright (C) 2002-2011 Aleph One Ltd.
8775 + * for Toby Churchill Ltd and Brightstar Engineering
8777 + * Created by Charles Manning <charles@aleph1.co.uk>
8779 + * This program is free software; you can redistribute it and/or modify
8780 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8781 + * published by the Free Software Foundation.
8783 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8784 + */
8786 +#ifndef __YAFFS_NAND_H__
8787 +#define __YAFFS_NAND_H__
8788 +#include "yaffs_guts.h"
8790 +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
8791 + u8 *buffer, struct yaffs_ext_tags *tags);
8793 +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
8794 + int nand_chunk,
8795 + const u8 *buffer, struct yaffs_ext_tags *tags);
8797 +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
8799 +int yaffs_query_init_block_state(struct yaffs_dev *dev,
8800 + int block_no,
8801 + enum yaffs_block_state *state,
8802 + unsigned *seq_number);
8804 +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
8806 +int yaffs_init_nand(struct yaffs_dev *dev);
8807 +int yaffs_deinit_nand(struct yaffs_dev *dev);
8809 +#endif
8810 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.4.90/fs/yaffs2/yaffs_packedtags1.c
8811 --- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
8812 +++ linux-3.4.90/fs/yaffs2/yaffs_packedtags1.c 2014-05-17 15:08:09.000000000 +0200
8813 @@ -0,0 +1,56 @@
8815 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8817 + * Copyright (C) 2002-2011 Aleph One Ltd.
8818 + * for Toby Churchill Ltd and Brightstar Engineering
8820 + * Created by Charles Manning <charles@aleph1.co.uk>
8822 + * This program is free software; you can redistribute it and/or modify
8823 + * it under the terms of the GNU General Public License version 2 as
8824 + * published by the Free Software Foundation.
8825 + */
8827 +#include "yaffs_packedtags1.h"
8828 +#include "yportenv.h"
8830 +static const u8 all_ff[20] = {
8831 + 0xff, 0xff, 0xff, 0xff,
8832 + 0xff, 0xff, 0xff, 0xff,
8833 + 0xff, 0xff, 0xff, 0xff,
8834 + 0xff, 0xff, 0xff, 0xff,
8835 + 0xff, 0xff, 0xff, 0xff
8838 +void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
8839 + const struct yaffs_ext_tags *t)
8841 + pt->chunk_id = t->chunk_id;
8842 + pt->serial_number = t->serial_number;
8843 + pt->n_bytes = t->n_bytes;
8844 + pt->obj_id = t->obj_id;
8845 + pt->ecc = 0;
8846 + pt->deleted = (t->is_deleted) ? 0 : 1;
8847 + pt->unused_stuff = 0;
8848 + pt->should_be_ff = 0xffffffff;
8851 +void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
8852 + const struct yaffs_packed_tags1 *pt)
8855 + if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
8856 + t->block_bad = 0;
8857 + if (pt->should_be_ff != 0xffffffff)
8858 + t->block_bad = 1;
8859 + t->chunk_used = 1;
8860 + t->obj_id = pt->obj_id;
8861 + t->chunk_id = pt->chunk_id;
8862 + t->n_bytes = pt->n_bytes;
8863 + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
8864 + t->is_deleted = (pt->deleted) ? 0 : 1;
8865 + t->serial_number = pt->serial_number;
8866 + } else {
8867 + memset(t, 0, sizeof(struct yaffs_ext_tags));
8870 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.4.90/fs/yaffs2/yaffs_packedtags1.h
8871 --- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
8872 +++ linux-3.4.90/fs/yaffs2/yaffs_packedtags1.h 2014-05-17 15:08:09.000000000 +0200
8873 @@ -0,0 +1,39 @@
8875 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8877 + * Copyright (C) 2002-2011 Aleph One Ltd.
8878 + * for Toby Churchill Ltd and Brightstar Engineering
8880 + * Created by Charles Manning <charles@aleph1.co.uk>
8882 + * This program is free software; you can redistribute it and/or modify
8883 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8884 + * published by the Free Software Foundation.
8886 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8887 + */
8889 +/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
8891 +#ifndef __YAFFS_PACKEDTAGS1_H__
8892 +#define __YAFFS_PACKEDTAGS1_H__
8894 +#include "yaffs_guts.h"
8896 +struct yaffs_packed_tags1 {
8897 + u32 chunk_id:20;
8898 + u32 serial_number:2;
8899 + u32 n_bytes:10;
8900 + u32 obj_id:18;
8901 + u32 ecc:12;
8902 + u32 deleted:1;
8903 + u32 unused_stuff:1;
8904 + unsigned should_be_ff;
8908 +void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
8909 + const struct yaffs_ext_tags *t);
8910 +void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
8911 + const struct yaffs_packed_tags1 *pt);
8912 +#endif
8913 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.4.90/fs/yaffs2/yaffs_packedtags2.c
8914 --- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
8915 +++ linux-3.4.90/fs/yaffs2/yaffs_packedtags2.c 2014-05-17 15:08:09.000000000 +0200
8916 @@ -0,0 +1,197 @@
8918 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8920 + * Copyright (C) 2002-2011 Aleph One Ltd.
8921 + * for Toby Churchill Ltd and Brightstar Engineering
8923 + * Created by Charles Manning <charles@aleph1.co.uk>
8925 + * This program is free software; you can redistribute it and/or modify
8926 + * it under the terms of the GNU General Public License version 2 as
8927 + * published by the Free Software Foundation.
8928 + */
8930 +#include "yaffs_packedtags2.h"
8931 +#include "yportenv.h"
8932 +#include "yaffs_trace.h"
8934 +/* This code packs a set of extended tags into a binary structure for
8935 + * NAND storage
8936 + */
8938 +/* Some of the information is "extra" struff which can be packed in to
8939 + * speed scanning
8940 + * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
8941 + */
8943 +/* Extra flags applied to chunk_id */
8945 +#define EXTRA_HEADER_INFO_FLAG 0x80000000
8946 +#define EXTRA_SHRINK_FLAG 0x40000000
8947 +#define EXTRA_SHADOWS_FLAG 0x20000000
8948 +#define EXTRA_SPARE_FLAGS 0x10000000
8950 +#define ALL_EXTRA_FLAGS 0xf0000000
8952 +/* Also, the top 4 bits of the object Id are set to the object type. */
8953 +#define EXTRA_OBJECT_TYPE_SHIFT (28)
8954 +#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
8956 +static void yaffs_dump_packed_tags2_tags_only(
8957 + const struct yaffs_packed_tags2_tags_only *ptt)
8959 + yaffs_trace(YAFFS_TRACE_MTD,
8960 + "packed tags obj %d chunk %d byte %d seq %d",
8961 + ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
8964 +static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
8966 + yaffs_dump_packed_tags2_tags_only(&pt->t);
8969 +static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
8971 + yaffs_trace(YAFFS_TRACE_MTD,
8972 + "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
8973 + t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
8974 + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
8975 + t->seq_number);
8979 +static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
8981 + if (t->chunk_id != 0 || !t->extra_available)
8982 + return 0;
8984 + /* Check if the file size is too long to store */
8985 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
8986 + (t->extra_file_size >> 31) != 0)
8987 + return 0;
8988 + return 1;
8991 +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
8992 + const struct yaffs_ext_tags *t)
8994 + ptt->chunk_id = t->chunk_id;
8995 + ptt->seq_number = t->seq_number;
8996 + ptt->n_bytes = t->n_bytes;
8997 + ptt->obj_id = t->obj_id;
8999 + /* Only store extra tags for object headers.
9000 + * If it is a file then only store if the file size is short\
9001 + * enough to fit.
9002 + */
9003 + if (yaffs_check_tags_extra_packable(t)) {
9004 + /* Store the extra header info instead */
9005 + /* We save the parent object in the chunk_id */
9006 + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
9007 + if (t->extra_is_shrink)
9008 + ptt->chunk_id |= EXTRA_SHRINK_FLAG;
9009 + if (t->extra_shadows)
9010 + ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
9012 + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
9013 + ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
9015 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
9016 + ptt->n_bytes = t->extra_equiv_id;
9017 + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
9018 + ptt->n_bytes = (unsigned) t->extra_file_size;
9019 + else
9020 + ptt->n_bytes = 0;
9023 + yaffs_dump_packed_tags2_tags_only(ptt);
9024 + yaffs_dump_tags2(t);
9027 +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
9028 + const struct yaffs_ext_tags *t, int tags_ecc)
9030 + yaffs_pack_tags2_tags_only(&pt->t, t);
9032 + if (tags_ecc)
9033 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
9034 + sizeof(struct yaffs_packed_tags2_tags_only),
9035 + &pt->ecc);
9038 +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
9039 + struct yaffs_packed_tags2_tags_only *ptt)
9041 + memset(t, 0, sizeof(struct yaffs_ext_tags));
9043 + if (ptt->seq_number == 0xffffffff)
9044 + return;
9046 + t->block_bad = 0;
9047 + t->chunk_used = 1;
9048 + t->obj_id = ptt->obj_id;
9049 + t->chunk_id = ptt->chunk_id;
9050 + t->n_bytes = ptt->n_bytes;
9051 + t->is_deleted = 0;
9052 + t->serial_number = 0;
9053 + t->seq_number = ptt->seq_number;
9055 + /* Do extra header info stuff */
9056 + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
9057 + t->chunk_id = 0;
9058 + t->n_bytes = 0;
9060 + t->extra_available = 1;
9061 + t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
9062 + t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
9063 + t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
9064 + t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
9065 + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
9067 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
9068 + t->extra_equiv_id = ptt->n_bytes;
9069 + else
9070 + t->extra_file_size = ptt->n_bytes;
9072 + yaffs_dump_packed_tags2_tags_only(ptt);
9073 + yaffs_dump_tags2(t);
9076 +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
9077 + int tags_ecc)
9079 + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
9081 + if (pt->t.seq_number != 0xffffffff && tags_ecc) {
9082 + /* Chunk is in use and we need to do ECC */
9084 + struct yaffs_ecc_other ecc;
9085 + int result;
9086 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
9087 + sizeof(struct yaffs_packed_tags2_tags_only),
9088 + &ecc);
9089 + result =
9090 + yaffs_ecc_correct_other((unsigned char *)&pt->t,
9091 + sizeof(struct yaffs_packed_tags2_tags_only),
9092 + &pt->ecc, &ecc);
9093 + switch (result) {
9094 + case 0:
9095 + ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
9096 + break;
9097 + case 1:
9098 + ecc_result = YAFFS_ECC_RESULT_FIXED;
9099 + break;
9100 + case -1:
9101 + ecc_result = YAFFS_ECC_RESULT_UNFIXED;
9102 + break;
9103 + default:
9104 + ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
9107 + yaffs_unpack_tags2_tags_only(t, &pt->t);
9109 + t->ecc_result = ecc_result;
9111 + yaffs_dump_packed_tags2(pt);
9112 + yaffs_dump_tags2(t);
9114 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.4.90/fs/yaffs2/yaffs_packedtags2.h
9115 --- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
9116 +++ linux-3.4.90/fs/yaffs2/yaffs_packedtags2.h 2014-05-17 15:08:09.000000000 +0200
9117 @@ -0,0 +1,47 @@
9119 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
9121 + * Copyright (C) 2002-2011 Aleph One Ltd.
9122 + * for Toby Churchill Ltd and Brightstar Engineering
9124 + * Created by Charles Manning <charles@aleph1.co.uk>
9126 + * This program is free software; you can redistribute it and/or modify
9127 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9128 + * published by the Free Software Foundation.
9130 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9131 + */
9133 +/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
9135 +#ifndef __YAFFS_PACKEDTAGS2_H__
9136 +#define __YAFFS_PACKEDTAGS2_H__
9138 +#include "yaffs_guts.h"
9139 +#include "yaffs_ecc.h"
9141 +struct yaffs_packed_tags2_tags_only {
9142 + unsigned seq_number;
9143 + unsigned obj_id;
9144 + unsigned chunk_id;
9145 + unsigned n_bytes;
9148 +struct yaffs_packed_tags2 {
9149 + struct yaffs_packed_tags2_tags_only t;
9150 + struct yaffs_ecc_other ecc;
9153 +/* Full packed tags with ECC, used for oob tags */
9154 +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
9155 + const struct yaffs_ext_tags *t, int tags_ecc);
9156 +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
9157 + int tags_ecc);
9159 +/* Only the tags part (no ECC for use with inband tags */
9160 +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
9161 + const struct yaffs_ext_tags *t);
9162 +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
9163 + struct yaffs_packed_tags2_tags_only *pt);
9164 +#endif
9165 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_summary.c linux-3.4.90/fs/yaffs2/yaffs_summary.c
9166 --- linux-3.4.90.orig/fs/yaffs2/yaffs_summary.c 1970-01-01 01:00:00.000000000 +0100
9167 +++ linux-3.4.90/fs/yaffs2/yaffs_summary.c 2014-05-17 15:08:09.000000000 +0200
9168 @@ -0,0 +1,312 @@
9170 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
9172 + * Copyright (C) 2002-2011 Aleph One Ltd.
9173 + * for Toby Churchill Ltd and Brightstar Engineering
9175 + * Created by Charles Manning <charles@aleph1.co.uk>
9177 + * This program is free software; you can redistribute it and/or modify
9178 + * it under the terms of the GNU General Public License version 2 as
9179 + * published by the Free Software Foundation.
9180 + */
9182 +/* Summaries write the useful part of the tags for the chunks in a block into an
9183 + * an array which is written to the last n chunks of the block.
9184 + * Reading the summaries gives all the tags for the block in one read. Much
9185 + * faster.
9187 + * Chunks holding summaries are marked with tags making it look like
9188 + * they are part of a fake file.
9190 + * The summary could also be used during gc.
9192 + */
9194 +#include "yaffs_summary.h"
9195 +#include "yaffs_packedtags2.h"
9196 +#include "yaffs_nand.h"
9197 +#include "yaffs_getblockinfo.h"
9198 +#include "yaffs_bitmap.h"
9201 + * The summary is built up in an array of summary tags.
9202 + * This gets written to the last one or two (maybe more) chunks in a block.
9203 + * A summary header is written as the first part of each chunk of summary data.
9204 + * The summary header must match or the summary is rejected.
9205 + */
9207 +/* Summary tags don't need the sequence number because that is redundant. */
9208 +struct yaffs_summary_tags {
9209 + unsigned obj_id;
9210 + unsigned chunk_id;
9211 + unsigned n_bytes;
9214 +/* Summary header */
9215 +struct yaffs_summary_header {
9216 + unsigned version; /* Must match current version */
9217 + unsigned block; /* Must be this block */
9218 + unsigned seq; /* Must be this sequence number */
9219 + unsigned sum; /* Just add up all the bytes in the tags */
9223 +static void yaffs_summary_clear(struct yaffs_dev *dev)
9225 + if (!dev->sum_tags)
9226 + return;
9227 + memset(dev->sum_tags, 0, dev->chunks_per_summary *
9228 + sizeof(struct yaffs_summary_tags));
9232 +void yaffs_summary_deinit(struct yaffs_dev *dev)
9234 + kfree(dev->sum_tags);
9235 + dev->sum_tags = NULL;
9236 + kfree(dev->gc_sum_tags);
9237 + dev->gc_sum_tags = NULL;
9238 + dev->chunks_per_summary = 0;
9241 +int yaffs_summary_init(struct yaffs_dev *dev)
9243 + int sum_bytes;
9244 + int chunks_used; /* Number of chunks used by summary */
9245 + int sum_tags_bytes;
9247 + sum_bytes = dev->param.chunks_per_block *
9248 + sizeof(struct yaffs_summary_tags);
9250 + chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
9251 + (dev->data_bytes_per_chunk -
9252 + sizeof(struct yaffs_summary_header));
9254 + dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
9255 + sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
9256 + dev->chunks_per_summary;
9257 + dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
9258 + dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
9259 + if (!dev->sum_tags || !dev->gc_sum_tags) {
9260 + yaffs_summary_deinit(dev);
9261 + return YAFFS_FAIL;
9264 + yaffs_summary_clear(dev);
9266 + return YAFFS_OK;
9269 +static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
9271 + u8 *sum_buffer = (u8 *)dev->sum_tags;
9272 + int i;
9273 + unsigned sum = 0;
9275 + i = sizeof(struct yaffs_summary_tags) *
9276 + dev->chunks_per_summary;
9277 + while (i > 0) {
9278 + sum += *sum_buffer;
9279 + sum_buffer++;
9280 + i--;
9283 + return sum;
9286 +static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
9288 + struct yaffs_ext_tags tags;
9289 + u8 *buffer;
9290 + u8 *sum_buffer = (u8 *)dev->sum_tags;
9291 + int n_bytes;
9292 + int chunk_in_nand;
9293 + int chunk_in_block;
9294 + int result;
9295 + int this_tx;
9296 + struct yaffs_summary_header hdr;
9297 + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
9298 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
9300 + buffer = yaffs_get_temp_buffer(dev);
9301 + n_bytes = sizeof(struct yaffs_summary_tags) *
9302 + dev->chunks_per_summary;
9303 + memset(&tags, 0, sizeof(struct yaffs_ext_tags));
9304 + tags.obj_id = YAFFS_OBJECTID_SUMMARY;
9305 + tags.chunk_id = 1;
9306 + chunk_in_block = dev->chunks_per_summary;
9307 + chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
9308 + dev->chunks_per_summary;
9309 + hdr.version = YAFFS_SUMMARY_VERSION;
9310 + hdr.block = blk;
9311 + hdr.seq = bi->seq_number;
9312 + hdr.sum = yaffs_summary_sum(dev);
9314 + do {
9315 + this_tx = n_bytes;
9316 + if (this_tx > sum_bytes_per_chunk)
9317 + this_tx = sum_bytes_per_chunk;
9318 + memcpy(buffer, &hdr, sizeof(hdr));
9319 + memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
9320 + tags.n_bytes = this_tx + sizeof(hdr);
9321 + result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
9322 + buffer, &tags);
9324 + if (result != YAFFS_OK)
9325 + break;
9326 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
9327 + bi->pages_in_use++;
9328 + dev->n_free_chunks--;
9330 + n_bytes -= this_tx;
9331 + sum_buffer += this_tx;
9332 + chunk_in_nand++;
9333 + chunk_in_block++;
9334 + tags.chunk_id++;
9335 + } while (result == YAFFS_OK && n_bytes > 0);
9336 + yaffs_release_temp_buffer(dev, buffer);
9339 + if (result == YAFFS_OK)
9340 + bi->has_summary = 1;
9343 + return result;
9346 +int yaffs_summary_read(struct yaffs_dev *dev,
9347 + struct yaffs_summary_tags *st,
9348 + int blk)
9350 + struct yaffs_ext_tags tags;
9351 + u8 *buffer;
9352 + u8 *sum_buffer = (u8 *)st;
9353 + int n_bytes;
9354 + int chunk_id;
9355 + int chunk_in_nand;
9356 + int chunk_in_block;
9357 + int result;
9358 + int this_tx;
9359 + struct yaffs_summary_header hdr;
9360 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
9361 + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
9362 + int sum_tags_bytes;
9364 + sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
9365 + dev->chunks_per_summary;
9366 + buffer = yaffs_get_temp_buffer(dev);
9367 + n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
9368 + chunk_in_block = dev->chunks_per_summary;
9369 + chunk_in_nand = blk * dev->param.chunks_per_block +
9370 + dev->chunks_per_summary;
9371 + chunk_id = 1;
9372 + do {
9373 + this_tx = n_bytes;
9374 + if (this_tx > sum_bytes_per_chunk)
9375 + this_tx = sum_bytes_per_chunk;
9376 + result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
9377 + buffer, &tags);
9379 + if (tags.chunk_id != chunk_id ||
9380 + tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
9381 + tags.chunk_used == 0 ||
9382 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
9383 + tags.n_bytes != (this_tx + sizeof(hdr)))
9384 + result = YAFFS_FAIL;
9385 + if (result != YAFFS_OK)
9386 + break;
9388 + if (st == dev->sum_tags) {
9389 + /* If we're scanning then update the block info */
9390 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
9391 + bi->pages_in_use++;
9393 + memcpy(&hdr, buffer, sizeof(hdr));
9394 + memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
9395 + n_bytes -= this_tx;
9396 + sum_buffer += this_tx;
9397 + chunk_in_nand++;
9398 + chunk_in_block++;
9399 + chunk_id++;
9400 + } while (result == YAFFS_OK && n_bytes > 0);
9401 + yaffs_release_temp_buffer(dev, buffer);
9403 + if (result == YAFFS_OK) {
9404 + /* Verify header */
9405 + if (hdr.version != YAFFS_SUMMARY_VERSION ||
9406 + hdr.seq != bi->seq_number ||
9407 + hdr.sum != yaffs_summary_sum(dev))
9408 + result = YAFFS_FAIL;
9411 + if (st == dev->sum_tags && result == YAFFS_OK)
9412 + bi->has_summary = 1;
9414 + return result;
9417 +int yaffs_summary_add(struct yaffs_dev *dev,
9418 + struct yaffs_ext_tags *tags,
9419 + int chunk_in_nand)
9421 + struct yaffs_packed_tags2_tags_only tags_only;
9422 + struct yaffs_summary_tags *sum_tags;
9423 + int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
9424 + int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
9426 + if (!dev->sum_tags)
9427 + return YAFFS_OK;
9429 + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
9430 + yaffs_pack_tags2_tags_only(&tags_only, tags);
9431 + sum_tags = &dev->sum_tags[chunk_in_block];
9432 + sum_tags->chunk_id = tags_only.chunk_id;
9433 + sum_tags->n_bytes = tags_only.n_bytes;
9434 + sum_tags->obj_id = tags_only.obj_id;
9436 + if (chunk_in_block == dev->chunks_per_summary - 1) {
9437 + /* Time to write out the summary */
9438 + yaffs_summary_write(dev, block_in_nand);
9439 + yaffs_summary_clear(dev);
9440 + yaffs_skip_rest_of_block(dev);
9443 + return YAFFS_OK;
9446 +int yaffs_summary_fetch(struct yaffs_dev *dev,
9447 + struct yaffs_ext_tags *tags,
9448 + int chunk_in_block)
9450 + struct yaffs_packed_tags2_tags_only tags_only;
9451 + struct yaffs_summary_tags *sum_tags;
9452 + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
9453 + sum_tags = &dev->sum_tags[chunk_in_block];
9454 + tags_only.chunk_id = sum_tags->chunk_id;
9455 + tags_only.n_bytes = sum_tags->n_bytes;
9456 + tags_only.obj_id = sum_tags->obj_id;
9457 + yaffs_unpack_tags2_tags_only(tags, &tags_only);
9458 + return YAFFS_OK;
9460 + return YAFFS_FAIL;
9463 +void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
9465 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
9466 + int i;
9468 + if (!bi->has_summary)
9469 + return;
9471 + for (i = dev->chunks_per_summary;
9472 + i < dev->param.chunks_per_block;
9473 + i++) {
9474 + if (yaffs_check_chunk_bit(dev, blk, i)) {
9475 + yaffs_clear_chunk_bit(dev, blk, i);
9476 + bi->pages_in_use--;
9477 + dev->n_free_chunks++;
9481 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_summary.h linux-3.4.90/fs/yaffs2/yaffs_summary.h
9482 --- linux-3.4.90.orig/fs/yaffs2/yaffs_summary.h 1970-01-01 01:00:00.000000000 +0100
9483 +++ linux-3.4.90/fs/yaffs2/yaffs_summary.h 2014-05-17 15:08:09.000000000 +0200
9484 @@ -0,0 +1,37 @@
9486 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
9488 + * Copyright (C) 2002-2011 Aleph One Ltd.
9489 + * for Toby Churchill Ltd and Brightstar Engineering
9491 + * Created by Charles Manning <charles@aleph1.co.uk>
9493 + * This program is free software; you can redistribute it and/or modify
9494 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9495 + * published by the Free Software Foundation.
9497 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9498 + */
9500 +#ifndef __YAFFS_SUMMARY_H__
9501 +#define __YAFFS_SUMMARY_H__
9503 +#include "yaffs_packedtags2.h"
9506 +int yaffs_summary_init(struct yaffs_dev *dev);
9507 +void yaffs_summary_deinit(struct yaffs_dev *dev);
9509 +int yaffs_summary_add(struct yaffs_dev *dev,
9510 + struct yaffs_ext_tags *tags,
9511 + int chunk_in_block);
9512 +int yaffs_summary_fetch(struct yaffs_dev *dev,
9513 + struct yaffs_ext_tags *tags,
9514 + int chunk_in_block);
9515 +int yaffs_summary_read(struct yaffs_dev *dev,
9516 + struct yaffs_summary_tags *st,
9517 + int blk);
9518 +void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
9521 +#endif
9522 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.4.90/fs/yaffs2/yaffs_tagscompat.c
9523 --- linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
9524 +++ linux-3.4.90/fs/yaffs2/yaffs_tagscompat.c 2014-05-17 15:08:09.000000000 +0200
9525 @@ -0,0 +1,381 @@
9527 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
9529 + * Copyright (C) 2002-2011 Aleph One Ltd.
9530 + * for Toby Churchill Ltd and Brightstar Engineering
9532 + * Created by Charles Manning <charles@aleph1.co.uk>
9534 + * This program is free software; you can redistribute it and/or modify
9535 + * it under the terms of the GNU General Public License version 2 as
9536 + * published by the Free Software Foundation.
9537 + */
9539 +#include "yaffs_guts.h"
9540 +#include "yaffs_tagscompat.h"
9541 +#include "yaffs_ecc.h"
9542 +#include "yaffs_getblockinfo.h"
9543 +#include "yaffs_trace.h"
9545 +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
9548 +/********** Tags ECC calculations *********/
9551 +void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
9553 + /* Calculate an ecc */
9554 + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
9555 + unsigned i, j;
9556 + unsigned ecc = 0;
9557 + unsigned bit = 0;
9559 + tags->ecc = 0;
9561 + for (i = 0; i < 8; i++) {
9562 + for (j = 1; j & 0xff; j <<= 1) {
9563 + bit++;
9564 + if (b[i] & j)
9565 + ecc ^= bit;
9568 + tags->ecc = ecc;
9571 +int yaffs_check_tags_ecc(struct yaffs_tags *tags)
9573 + unsigned ecc = tags->ecc;
9575 + yaffs_calc_tags_ecc(tags);
9577 + ecc ^= tags->ecc;
9579 + if (ecc && ecc <= 64) {
9580 + /* TODO: Handle the failure better. Retire? */
9581 + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
9583 + ecc--;
9585 + b[ecc / 8] ^= (1 << (ecc & 7));
9587 + /* Now recvalc the ecc */
9588 + yaffs_calc_tags_ecc(tags);
9590 + return 1; /* recovered error */
9591 + } else if (ecc) {
9592 + /* Wierd ecc failure value */
9593 + /* TODO Need to do somethiong here */
9594 + return -1; /* unrecovered error */
9596 + return 0;
9599 +/********** Tags **********/
9601 +static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
9602 + struct yaffs_tags *tags_ptr)
9604 + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
9606 + yaffs_calc_tags_ecc(tags_ptr);
9608 + spare_ptr->tb0 = tu->as_bytes[0];
9609 + spare_ptr->tb1 = tu->as_bytes[1];
9610 + spare_ptr->tb2 = tu->as_bytes[2];
9611 + spare_ptr->tb3 = tu->as_bytes[3];
9612 + spare_ptr->tb4 = tu->as_bytes[4];
9613 + spare_ptr->tb5 = tu->as_bytes[5];
9614 + spare_ptr->tb6 = tu->as_bytes[6];
9615 + spare_ptr->tb7 = tu->as_bytes[7];
9618 +static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
9619 + struct yaffs_spare *spare_ptr,
9620 + struct yaffs_tags *tags_ptr)
9622 + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
9623 + int result;
9625 + tu->as_bytes[0] = spare_ptr->tb0;
9626 + tu->as_bytes[1] = spare_ptr->tb1;
9627 + tu->as_bytes[2] = spare_ptr->tb2;
9628 + tu->as_bytes[3] = spare_ptr->tb3;
9629 + tu->as_bytes[4] = spare_ptr->tb4;
9630 + tu->as_bytes[5] = spare_ptr->tb5;
9631 + tu->as_bytes[6] = spare_ptr->tb6;
9632 + tu->as_bytes[7] = spare_ptr->tb7;
9634 + result = yaffs_check_tags_ecc(tags_ptr);
9635 + if (result > 0)
9636 + dev->n_tags_ecc_fixed++;
9637 + else if (result < 0)
9638 + dev->n_tags_ecc_unfixed++;
9641 +static void yaffs_spare_init(struct yaffs_spare *spare)
9643 + memset(spare, 0xff, sizeof(struct yaffs_spare));
9646 +static int yaffs_wr_nand(struct yaffs_dev *dev,
9647 + int nand_chunk, const u8 *data,
9648 + struct yaffs_spare *spare)
9650 + int data_size = dev->data_bytes_per_chunk;
9652 + return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
9653 + data, data_size,
9654 + (u8 *) spare, sizeof(*spare));
9657 +static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
9658 + int nand_chunk,
9659 + u8 *data,
9660 + struct yaffs_spare *spare,
9661 + enum yaffs_ecc_result *ecc_result,
9662 + int correct_errors)
9664 + int ret_val;
9665 + struct yaffs_spare local_spare;
9666 + int data_size;
9667 + int spare_size;
9668 + int ecc_result1, ecc_result2;
9669 + u8 calc_ecc[3];
9671 + if (!spare) {
9672 + /* If we don't have a real spare, then we use a local one. */
9673 + /* Need this for the calculation of the ecc */
9674 + spare = &local_spare;
9676 + data_size = dev->data_bytes_per_chunk;
9677 + spare_size = sizeof(struct yaffs_spare);
9679 + if (dev->param.use_nand_ecc)
9680 + return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
9681 + data, data_size,
9682 + (u8 *) spare, spare_size,
9683 + ecc_result);
9686 + /* Handle the ECC at this level. */
9688 + ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
9689 + data, data_size,
9690 + (u8 *)spare, spare_size,
9691 + NULL);
9692 + if (!data || !correct_errors)
9693 + return ret_val;
9695 + /* Do ECC correction if needed. */
9696 + yaffs_ecc_calc(data, calc_ecc);
9697 + ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
9698 + yaffs_ecc_calc(&data[256], calc_ecc);
9699 + ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
9701 + if (ecc_result1 > 0) {
9702 + yaffs_trace(YAFFS_TRACE_ERROR,
9703 + "**>>yaffs ecc error fix performed on chunk %d:0",
9704 + nand_chunk);
9705 + dev->n_ecc_fixed++;
9706 + } else if (ecc_result1 < 0) {
9707 + yaffs_trace(YAFFS_TRACE_ERROR,
9708 + "**>>yaffs ecc error unfixed on chunk %d:0",
9709 + nand_chunk);
9710 + dev->n_ecc_unfixed++;
9713 + if (ecc_result2 > 0) {
9714 + yaffs_trace(YAFFS_TRACE_ERROR,
9715 + "**>>yaffs ecc error fix performed on chunk %d:1",
9716 + nand_chunk);
9717 + dev->n_ecc_fixed++;
9718 + } else if (ecc_result2 < 0) {
9719 + yaffs_trace(YAFFS_TRACE_ERROR,
9720 + "**>>yaffs ecc error unfixed on chunk %d:1",
9721 + nand_chunk);
9722 + dev->n_ecc_unfixed++;
9725 + if (ecc_result1 || ecc_result2) {
9726 + /* We had a data problem on this page */
9727 + yaffs_handle_rd_data_error(dev, nand_chunk);
9730 + if (ecc_result1 < 0 || ecc_result2 < 0)
9731 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
9732 + else if (ecc_result1 > 0 || ecc_result2 > 0)
9733 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
9734 + else
9735 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
9737 + return ret_val;
9741 + * Functions for robustisizing
9742 + */
9744 +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
9746 + int flash_block = nand_chunk / dev->param.chunks_per_block;
9748 + /* Mark the block for retirement */
9749 + yaffs_get_block_info(dev, flash_block + dev->block_offset)->
9750 + needs_retiring = 1;
9751 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9752 + "**>>Block %d marked for retirement",
9753 + flash_block);
9755 + /* TODO:
9756 + * Just do a garbage collection on the affected block
9757 + * then retire the block
9758 + * NB recursion
9759 + */
9762 +static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
9763 + int nand_chunk,
9764 + const u8 *data, const struct yaffs_ext_tags *ext_tags)
9766 + struct yaffs_spare spare;
9767 + struct yaffs_tags tags;
9769 + yaffs_spare_init(&spare);
9771 + if (ext_tags->is_deleted)
9772 + spare.page_status = 0;
9773 + else {
9774 + tags.obj_id = ext_tags->obj_id;
9775 + tags.chunk_id = ext_tags->chunk_id;
9777 + tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
9779 + if (dev->data_bytes_per_chunk >= 1024)
9780 + tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
9781 + else
9782 + tags.n_bytes_msb = 3;
9784 + tags.serial_number = ext_tags->serial_number;
9786 + if (!dev->param.use_nand_ecc && data) {
9787 + yaffs_ecc_calc(data, spare.ecc1);
9788 + yaffs_ecc_calc(&data[256], spare.ecc2);
9791 + yaffs_load_tags_to_spare(&spare, &tags);
9793 + return yaffs_wr_nand(dev, nand_chunk, data, &spare);
9796 +static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
9797 + int nand_chunk,
9798 + u8 *data, struct yaffs_ext_tags *ext_tags)
9800 + struct yaffs_spare spare;
9801 + struct yaffs_tags tags;
9802 + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
9803 + static struct yaffs_spare spare_ff;
9804 + static int init;
9805 + int deleted;
9807 + if (!init) {
9808 + memset(&spare_ff, 0xff, sizeof(spare_ff));
9809 + init = 1;
9812 + if (!yaffs_rd_chunk_nand(dev, nand_chunk,
9813 + data, &spare, &ecc_result, 1))
9814 + return YAFFS_FAIL;
9816 + /* ext_tags may be NULL */
9817 + if (!ext_tags)
9818 + return YAFFS_OK;
9820 + deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
9822 + ext_tags->is_deleted = deleted;
9823 + ext_tags->ecc_result = ecc_result;
9824 + ext_tags->block_bad = 0; /* We're reading it */
9825 + /* therefore it is not a bad block */
9826 + ext_tags->chunk_used =
9827 + memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
9829 + if (ext_tags->chunk_used) {
9830 + yaffs_get_tags_from_spare(dev, &spare, &tags);
9831 + ext_tags->obj_id = tags.obj_id;
9832 + ext_tags->chunk_id = tags.chunk_id;
9833 + ext_tags->n_bytes = tags.n_bytes_lsb;
9835 + if (dev->data_bytes_per_chunk >= 1024)
9836 + ext_tags->n_bytes |=
9837 + (((unsigned)tags.n_bytes_msb) << 10);
9839 + ext_tags->serial_number = tags.serial_number;
9842 + return YAFFS_OK;
9845 +static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
9847 + struct yaffs_spare spare;
9849 + memset(&spare, 0xff, sizeof(struct yaffs_spare));
9851 + spare.block_status = 'Y';
9853 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
9854 + &spare);
9855 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
9856 + NULL, &spare);
9858 + return YAFFS_OK;
9861 +static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
9862 + int block_no,
9863 + enum yaffs_block_state *state,
9864 + u32 *seq_number)
9866 + struct yaffs_spare spare0, spare1;
9867 + static struct yaffs_spare spare_ff;
9868 + static int init;
9869 + enum yaffs_ecc_result dummy;
9871 + if (!init) {
9872 + memset(&spare_ff, 0xff, sizeof(spare_ff));
9873 + init = 1;
9876 + *seq_number = 0;
9878 + /* Look for bad block markers in the first two chunks */
9879 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
9880 + NULL, &spare0, &dummy, 0);
9881 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
9882 + NULL, &spare1, &dummy, 0);
9884 + if (hweight8(spare0.block_status & spare1.block_status) < 7)
9885 + *state = YAFFS_BLOCK_STATE_DEAD;
9886 + else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
9887 + *state = YAFFS_BLOCK_STATE_EMPTY;
9888 + else
9889 + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
9891 + return YAFFS_OK;
9894 +void yaffs_tags_compat_install(struct yaffs_dev *dev)
9896 + if(dev->param.is_yaffs2)
9897 + return;
9898 + if(!dev->tagger.write_chunk_tags_fn)
9899 + dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
9900 + if(!dev->tagger.read_chunk_tags_fn)
9901 + dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
9902 + if(!dev->tagger.query_block_fn)
9903 + dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
9904 + if(!dev->tagger.mark_bad_fn)
9905 + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
9907 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.4.90/fs/yaffs2/yaffs_tagscompat.h
9908 --- linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
9909 +++ linux-3.4.90/fs/yaffs2/yaffs_tagscompat.h 2014-05-17 15:08:09.000000000 +0200
9910 @@ -0,0 +1,44 @@
9912 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
9914 + * Copyright (C) 2002-2011 Aleph One Ltd.
9915 + * for Toby Churchill Ltd and Brightstar Engineering
9917 + * Created by Charles Manning <charles@aleph1.co.uk>
9919 + * This program is free software; you can redistribute it and/or modify
9920 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9921 + * published by the Free Software Foundation.
9923 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9924 + */
9926 +#ifndef __YAFFS_TAGSCOMPAT_H__
9927 +#define __YAFFS_TAGSCOMPAT_H__
9930 +#include "yaffs_guts.h"
9932 +#if 0
9935 +int yaffs_tags_compat_wr(struct yaffs_dev *dev,
9936 + int nand_chunk,
9937 + const u8 *data, const struct yaffs_ext_tags *tags);
9938 +int yaffs_tags_compat_rd(struct yaffs_dev *dev,
9939 + int nand_chunk,
9940 + u8 *data, struct yaffs_ext_tags *tags);
9941 +int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
9942 +int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
9943 + int block_no,
9944 + enum yaffs_block_state *state,
9945 + u32 *seq_number);
9947 +#endif
9950 +void yaffs_tags_compat_install(struct yaffs_dev *dev);
9951 +void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
9952 +int yaffs_check_tags_ecc(struct yaffs_tags *tags);
9954 +#endif
9955 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.c
9956 --- linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 01:00:00.000000000 +0100
9957 +++ linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.c 2014-05-17 15:08:09.000000000 +0200
9958 @@ -0,0 +1,199 @@
9960 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
9962 + * Copyright (C) 2002-2011 Aleph One Ltd.
9963 + * for Toby Churchill Ltd and Brightstar Engineering
9965 + * Created by Charles Manning <charles@aleph1.co.uk>
9967 + * This program is free software; you can redistribute it and/or modify
9968 + * it under the terms of the GNU General Public License version 2 as
9969 + * published by the Free Software Foundation.
9970 + */
9972 +#include "yaffs_guts.h"
9973 +#include "yaffs_trace.h"
9974 +#include "yaffs_packedtags2.h"
9976 +static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
9977 + int nand_chunk, const u8 *data,
9978 + const struct yaffs_ext_tags *tags)
9980 + struct yaffs_packed_tags2 pt;
9981 + int retval;
9983 + int packed_tags_size =
9984 + dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
9985 + void *packed_tags_ptr =
9986 + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
9988 + yaffs_trace(YAFFS_TRACE_MTD,
9989 + "yaffs_tags_marshall_write chunk %d data %p tags %p",
9990 + nand_chunk, data, tags);
9992 + /* For yaffs2 writing there must be both data and tags.
9993 + * If we're using inband tags, then the tags are stuffed into
9994 + * the end of the data buffer.
9995 + */
9996 + if (!data || !tags)
9997 + BUG();
9998 + else if (dev->param.inband_tags) {
9999 + struct yaffs_packed_tags2_tags_only *pt2tp;
10000 + pt2tp =
10001 + (struct yaffs_packed_tags2_tags_only *)(data +
10002 + dev->
10003 + data_bytes_per_chunk);
10004 + yaffs_pack_tags2_tags_only(pt2tp, tags);
10005 + } else {
10006 + yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
10009 + retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
10010 + data, dev->param.total_bytes_per_chunk,
10011 + (dev->param.inband_tags) ? NULL : packed_tags_ptr,
10012 + (dev->param.inband_tags) ? 0 : packed_tags_size);
10014 + return retval;
10017 +static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
10018 + int nand_chunk, u8 *data,
10019 + struct yaffs_ext_tags *tags)
10021 + int retval = 0;
10022 + int local_data = 0;
10023 + u8 spare_buffer[100];
10024 + enum yaffs_ecc_result ecc_result;
10026 + struct yaffs_packed_tags2 pt;
10028 + int packed_tags_size =
10029 + dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
10030 + void *packed_tags_ptr =
10031 + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
10033 + yaffs_trace(YAFFS_TRACE_MTD,
10034 + "yaffs_tags_marshall_read chunk %d data %p tags %p",
10035 + nand_chunk, data, tags);
10037 + if (dev->param.inband_tags) {
10038 + if (!data) {
10039 + local_data = 1;
10040 + data = yaffs_get_temp_buffer(dev);
10044 + if (dev->param.inband_tags || (data && !tags))
10045 + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
10046 + data, dev->param.total_bytes_per_chunk,
10047 + NULL, 0,
10048 + &ecc_result);
10049 + else if (tags)
10050 + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
10051 + data, dev->param.total_bytes_per_chunk,
10052 + spare_buffer, packed_tags_size,
10053 + &ecc_result);
10054 + else
10055 + BUG();
10058 + if (dev->param.inband_tags) {
10059 + if (tags) {
10060 + struct yaffs_packed_tags2_tags_only *pt2tp;
10061 + pt2tp =
10062 + (struct yaffs_packed_tags2_tags_only *)
10063 + &data[dev->data_bytes_per_chunk];
10064 + yaffs_unpack_tags2_tags_only(tags, pt2tp);
10066 + } else if (tags) {
10067 + memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
10068 + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
10071 + if (local_data)
10072 + yaffs_release_temp_buffer(dev, data);
10074 + if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
10075 + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
10076 + dev->n_ecc_unfixed++;
10079 + if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
10080 + if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
10081 + tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
10082 + dev->n_ecc_fixed++;
10085 + if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
10086 + return YAFFS_OK;
10087 + else
10088 + return YAFFS_FAIL;
10091 +static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
10092 + enum yaffs_block_state *state,
10093 + u32 *seq_number)
10095 + int retval;
10097 + yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
10098 + block_no);
10100 + retval = dev->drv.drv_check_bad_fn(dev, block_no);
10102 + if (retval== YAFFS_FAIL) {
10103 + yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
10105 + *state = YAFFS_BLOCK_STATE_DEAD;
10106 + *seq_number = 0;
10107 + } else {
10108 + struct yaffs_ext_tags t;
10110 + yaffs_tags_marshall_read(dev,
10111 + block_no * dev->param.chunks_per_block,
10112 + NULL, &t);
10114 + if (t.chunk_used) {
10115 + *seq_number = t.seq_number;
10116 + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
10117 + } else {
10118 + *seq_number = 0;
10119 + *state = YAFFS_BLOCK_STATE_EMPTY;
10123 + yaffs_trace(YAFFS_TRACE_MTD,
10124 + "block query returns seq %d state %d",
10125 + *seq_number, *state);
10127 + if (retval == 0)
10128 + return YAFFS_OK;
10129 + else
10130 + return YAFFS_FAIL;
10133 +static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
10135 + return dev->drv.drv_mark_bad_fn(dev, block_no);
10140 +void yaffs_tags_marshall_install(struct yaffs_dev *dev)
10142 + if (!dev->param.is_yaffs2)
10143 + return;
10145 + if (!dev->tagger.write_chunk_tags_fn)
10146 + dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
10148 + if (!dev->tagger.read_chunk_tags_fn)
10149 + dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
10151 + if (!dev->tagger.query_block_fn)
10152 + dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
10154 + if (!dev->tagger.mark_bad_fn)
10155 + dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
10158 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.h
10159 --- linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 01:00:00.000000000 +0100
10160 +++ linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.h 2014-05-17 15:08:09.000000000 +0200
10161 @@ -0,0 +1,22 @@
10163 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
10165 + * Copyright (C) 2002-2011 Aleph One Ltd.
10166 + * for Toby Churchill Ltd and Brightstar Engineering
10168 + * Created by Charles Manning <charles@aleph1.co.uk>
10170 + * This program is free software; you can redistribute it and/or modify
10171 + * it under the terms of the GNU Lesser General Public License version 2.1 as
10172 + * published by the Free Software Foundation.
10174 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
10175 + */
10177 +#ifndef __YAFFS_TAGSMARSHALL_H__
10178 +#define __YAFFS_TAGSMARSHALL_H__
10180 +#include "yaffs_guts.h"
10181 +void yaffs_tags_marshall_install(struct yaffs_dev *dev);
10183 +#endif
10184 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_trace.h linux-3.4.90/fs/yaffs2/yaffs_trace.h
10185 --- linux-3.4.90.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
10186 +++ linux-3.4.90/fs/yaffs2/yaffs_trace.h 2014-05-17 15:08:09.000000000 +0200
10187 @@ -0,0 +1,57 @@
10189 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
10191 + * Copyright (C) 2002-2011 Aleph One Ltd.
10192 + * for Toby Churchill Ltd and Brightstar Engineering
10194 + * Created by Charles Manning <charles@aleph1.co.uk>
10196 + * This program is free software; you can redistribute it and/or modify
10197 + * it under the terms of the GNU Lesser General Public License version 2.1 as
10198 + * published by the Free Software Foundation.
10200 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
10201 + */
10203 +#ifndef __YTRACE_H__
10204 +#define __YTRACE_H__
10206 +extern unsigned int yaffs_trace_mask;
10207 +extern unsigned int yaffs_wr_attempts;
10210 + * Tracing flags.
10211 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
10212 + */
10214 +#define YAFFS_TRACE_OS 0x00000002
10215 +#define YAFFS_TRACE_ALLOCATE 0x00000004
10216 +#define YAFFS_TRACE_SCAN 0x00000008
10217 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
10218 +#define YAFFS_TRACE_ERASE 0x00000020
10219 +#define YAFFS_TRACE_GC 0x00000040
10220 +#define YAFFS_TRACE_WRITE 0x00000080
10221 +#define YAFFS_TRACE_TRACING 0x00000100
10222 +#define YAFFS_TRACE_DELETION 0x00000200
10223 +#define YAFFS_TRACE_BUFFERS 0x00000400
10224 +#define YAFFS_TRACE_NANDACCESS 0x00000800
10225 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
10226 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
10227 +#define YAFFS_TRACE_MTD 0x00004000
10228 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
10230 +#define YAFFS_TRACE_VERIFY 0x00010000
10231 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
10232 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
10233 +#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
10235 +#define YAFFS_TRACE_SYNC 0x00100000
10236 +#define YAFFS_TRACE_BACKGROUND 0x00200000
10237 +#define YAFFS_TRACE_LOCK 0x00400000
10238 +#define YAFFS_TRACE_MOUNT 0x00800000
10240 +#define YAFFS_TRACE_ERROR 0x40000000
10241 +#define YAFFS_TRACE_BUG 0x80000000
10242 +#define YAFFS_TRACE_ALWAYS 0xf0000000
10244 +#endif
10245 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_verify.c linux-3.4.90/fs/yaffs2/yaffs_verify.c
10246 --- linux-3.4.90.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
10247 +++ linux-3.4.90/fs/yaffs2/yaffs_verify.c 2014-05-17 15:08:09.000000000 +0200
10248 @@ -0,0 +1,529 @@
10250 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
10252 + * Copyright (C) 2002-2011 Aleph One Ltd.
10253 + * for Toby Churchill Ltd and Brightstar Engineering
10255 + * Created by Charles Manning <charles@aleph1.co.uk>
10257 + * This program is free software; you can redistribute it and/or modify
10258 + * it under the terms of the GNU General Public License version 2 as
10259 + * published by the Free Software Foundation.
10260 + */
10262 +#include "yaffs_verify.h"
10263 +#include "yaffs_trace.h"
10264 +#include "yaffs_bitmap.h"
10265 +#include "yaffs_getblockinfo.h"
10266 +#include "yaffs_nand.h"
10268 +int yaffs_skip_verification(struct yaffs_dev *dev)
10270 + (void) dev;
10271 + return !(yaffs_trace_mask &
10272 + (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
10275 +static int yaffs_skip_full_verification(struct yaffs_dev *dev)
10277 + (void) dev;
10278 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
10281 +static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
10283 + (void) dev;
10284 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
10287 +static const char * const block_state_name[] = {
10288 + "Unknown",
10289 + "Needs scan",
10290 + "Scanning",
10291 + "Empty",
10292 + "Allocating",
10293 + "Full",
10294 + "Dirty",
10295 + "Checkpoint",
10296 + "Collecting",
10297 + "Dead"
10300 +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
10302 + int actually_used;
10303 + int in_use;
10305 + if (yaffs_skip_verification(dev))
10306 + return;
10308 + /* Report illegal runtime states */
10309 + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
10310 + yaffs_trace(YAFFS_TRACE_VERIFY,
10311 + "Block %d has undefined state %d",
10312 + n, bi->block_state);
10314 + switch (bi->block_state) {
10315 + case YAFFS_BLOCK_STATE_UNKNOWN:
10316 + case YAFFS_BLOCK_STATE_SCANNING:
10317 + case YAFFS_BLOCK_STATE_NEEDS_SCAN:
10318 + yaffs_trace(YAFFS_TRACE_VERIFY,
10319 + "Block %d has bad run-state %s",
10320 + n, block_state_name[bi->block_state]);
10323 + /* Check pages in use and soft deletions are legal */
10325 + actually_used = bi->pages_in_use - bi->soft_del_pages;
10327 + if (bi->pages_in_use < 0 ||
10328 + bi->pages_in_use > dev->param.chunks_per_block ||
10329 + bi->soft_del_pages < 0 ||
10330 + bi->soft_del_pages > dev->param.chunks_per_block ||
10331 + actually_used < 0 || actually_used > dev->param.chunks_per_block)
10332 + yaffs_trace(YAFFS_TRACE_VERIFY,
10333 + "Block %d has illegal values pages_in_used %d soft_del_pages %d",
10334 + n, bi->pages_in_use, bi->soft_del_pages);
10336 + /* Check chunk bitmap legal */
10337 + in_use = yaffs_count_chunk_bits(dev, n);
10338 + if (in_use != bi->pages_in_use)
10339 + yaffs_trace(YAFFS_TRACE_VERIFY,
10340 + "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
10341 + n, bi->pages_in_use, in_use);
10344 +void yaffs_verify_collected_blk(struct yaffs_dev *dev,
10345 + struct yaffs_block_info *bi, int n)
10347 + yaffs_verify_blk(dev, bi, n);
10349 + /* After collection the block should be in the erased state */
10351 + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
10352 + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
10353 + yaffs_trace(YAFFS_TRACE_ERROR,
10354 + "Block %d is in state %d after gc, should be erased",
10355 + n, bi->block_state);
10359 +void yaffs_verify_blocks(struct yaffs_dev *dev)
10361 + int i;
10362 + int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
10363 + int illegal_states = 0;
10365 + if (yaffs_skip_verification(dev))
10366 + return;
10368 + memset(state_count, 0, sizeof(state_count));
10370 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
10371 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
10372 + yaffs_verify_blk(dev, bi, i);
10374 + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
10375 + state_count[bi->block_state]++;
10376 + else
10377 + illegal_states++;
10380 + yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
10382 + yaffs_trace(YAFFS_TRACE_VERIFY,
10383 + "%d blocks have illegal states",
10384 + illegal_states);
10385 + if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
10386 + yaffs_trace(YAFFS_TRACE_VERIFY,
10387 + "Too many allocating blocks");
10389 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
10390 + yaffs_trace(YAFFS_TRACE_VERIFY,
10391 + "%s %d blocks",
10392 + block_state_name[i], state_count[i]);
10394 + if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
10395 + yaffs_trace(YAFFS_TRACE_VERIFY,
10396 + "Checkpoint block count wrong dev %d count %d",
10397 + dev->blocks_in_checkpt,
10398 + state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
10400 + if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
10401 + yaffs_trace(YAFFS_TRACE_VERIFY,
10402 + "Erased block count wrong dev %d count %d",
10403 + dev->n_erased_blocks,
10404 + state_count[YAFFS_BLOCK_STATE_EMPTY]);
10406 + if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
10407 + yaffs_trace(YAFFS_TRACE_VERIFY,
10408 + "Too many collecting blocks %d (max is 1)",
10409 + state_count[YAFFS_BLOCK_STATE_COLLECTING]);
10413 + * Verify the object header. oh must be valid, but obj and tags may be NULL in
10414 + * which case those tests will not be performed.
10415 + */
10416 +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
10417 + struct yaffs_ext_tags *tags, int parent_check)
10419 + if (obj && yaffs_skip_verification(obj->my_dev))
10420 + return;
10422 + if (!(tags && obj && oh)) {
10423 + yaffs_trace(YAFFS_TRACE_VERIFY,
10424 + "Verifying object header tags %p obj %p oh %p",
10425 + tags, obj, oh);
10426 + return;
10429 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
10430 + oh->type > YAFFS_OBJECT_TYPE_MAX)
10431 + yaffs_trace(YAFFS_TRACE_VERIFY,
10432 + "Obj %d header type is illegal value 0x%x",
10433 + tags->obj_id, oh->type);
10435 + if (tags->obj_id != obj->obj_id)
10436 + yaffs_trace(YAFFS_TRACE_VERIFY,
10437 + "Obj %d header mismatch obj_id %d",
10438 + tags->obj_id, obj->obj_id);
10440 + /*
10441 + * Check that the object's parent ids match if parent_check requested.
10443 + * Tests do not apply to the root object.
10444 + */
10446 + if (parent_check && tags->obj_id > 1 && !obj->parent)
10447 + yaffs_trace(YAFFS_TRACE_VERIFY,
10448 + "Obj %d header mismatch parent_id %d obj->parent is NULL",
10449 + tags->obj_id, oh->parent_obj_id);
10451 + if (parent_check && obj->parent &&
10452 + oh->parent_obj_id != obj->parent->obj_id &&
10453 + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
10454 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
10455 + yaffs_trace(YAFFS_TRACE_VERIFY,
10456 + "Obj %d header mismatch parent_id %d parent_obj_id %d",
10457 + tags->obj_id, oh->parent_obj_id,
10458 + obj->parent->obj_id);
10460 + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
10461 + yaffs_trace(YAFFS_TRACE_VERIFY,
10462 + "Obj %d header name is NULL",
10463 + obj->obj_id);
10465 + if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
10466 + yaffs_trace(YAFFS_TRACE_VERIFY,
10467 + "Obj %d header name is 0xff",
10468 + obj->obj_id);
10471 +void yaffs_verify_file(struct yaffs_obj *obj)
10473 + u32 x;
10474 + int required_depth;
10475 + int actual_depth;
10476 + int last_chunk;
10477 + u32 offset_in_chunk;
10478 + u32 the_chunk;
10480 + u32 i;
10481 + struct yaffs_dev *dev;
10482 + struct yaffs_ext_tags tags;
10483 + struct yaffs_tnode *tn;
10484 + u32 obj_id;
10486 + if (!obj)
10487 + return;
10489 + if (yaffs_skip_verification(obj->my_dev))
10490 + return;
10492 + dev = obj->my_dev;
10493 + obj_id = obj->obj_id;
10496 + /* Check file size is consistent with tnode depth */
10497 + yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
10498 + &last_chunk, &offset_in_chunk);
10499 + last_chunk++;
10500 + x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
10501 + required_depth = 0;
10502 + while (x > 0) {
10503 + x >>= YAFFS_TNODES_INTERNAL_BITS;
10504 + required_depth++;
10507 + actual_depth = obj->variant.file_variant.top_level;
10509 + /* Check that the chunks in the tnode tree are all correct.
10510 + * We do this by scanning through the tnode tree and
10511 + * checking the tags for every chunk match.
10512 + */
10514 + if (yaffs_skip_nand_verification(dev))
10515 + return;
10517 + for (i = 1; i <= last_chunk; i++) {
10518 + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
10520 + if (!tn)
10521 + continue;
10523 + the_chunk = yaffs_get_group_base(dev, tn, i);
10524 + if (the_chunk > 0) {
10525 + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
10526 + &tags);
10527 + if (tags.obj_id != obj_id || tags.chunk_id != i)
10528 + yaffs_trace(YAFFS_TRACE_VERIFY,
10529 + "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
10530 + obj_id, i, the_chunk,
10531 + tags.obj_id, tags.chunk_id);
10536 +void yaffs_verify_link(struct yaffs_obj *obj)
10538 + if (obj && yaffs_skip_verification(obj->my_dev))
10539 + return;
10541 + /* Verify sane equivalent object */
10544 +void yaffs_verify_symlink(struct yaffs_obj *obj)
10546 + if (obj && yaffs_skip_verification(obj->my_dev))
10547 + return;
10549 + /* Verify symlink string */
10552 +void yaffs_verify_special(struct yaffs_obj *obj)
10554 + if (obj && yaffs_skip_verification(obj->my_dev))
10555 + return;
10558 +void yaffs_verify_obj(struct yaffs_obj *obj)
10560 + struct yaffs_dev *dev;
10561 + u32 chunk_min;
10562 + u32 chunk_max;
10563 + u32 chunk_id_ok;
10564 + u32 chunk_in_range;
10565 + u32 chunk_wrongly_deleted;
10566 + u32 chunk_valid;
10568 + if (!obj)
10569 + return;
10571 + if (obj->being_created)
10572 + return;
10574 + dev = obj->my_dev;
10576 + if (yaffs_skip_verification(dev))
10577 + return;
10579 + /* Check sane object header chunk */
10581 + chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
10582 + chunk_max =
10583 + (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
10585 + chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
10586 + ((unsigned)(obj->hdr_chunk)) <= chunk_max);
10587 + chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
10588 + chunk_valid = chunk_in_range &&
10589 + yaffs_check_chunk_bit(dev,
10590 + obj->hdr_chunk / dev->param.chunks_per_block,
10591 + obj->hdr_chunk % dev->param.chunks_per_block);
10592 + chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
10594 + if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
10595 + yaffs_trace(YAFFS_TRACE_VERIFY,
10596 + "Obj %d has chunk_id %d %s %s",
10597 + obj->obj_id, obj->hdr_chunk,
10598 + chunk_id_ok ? "" : ",out of range",
10599 + chunk_wrongly_deleted ? ",marked as deleted" : "");
10601 + if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
10602 + struct yaffs_ext_tags tags;
10603 + struct yaffs_obj_hdr *oh;
10604 + u8 *buffer = yaffs_get_temp_buffer(dev);
10606 + oh = (struct yaffs_obj_hdr *)buffer;
10608 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
10610 + yaffs_verify_oh(obj, oh, &tags, 1);
10612 + yaffs_release_temp_buffer(dev, buffer);
10615 + /* Verify it has a parent */
10616 + if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
10617 + yaffs_trace(YAFFS_TRACE_VERIFY,
10618 + "Obj %d has parent pointer %p which does not look like an object",
10619 + obj->obj_id, obj->parent);
10622 + /* Verify parent is a directory */
10623 + if (obj->parent &&
10624 + obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
10625 + yaffs_trace(YAFFS_TRACE_VERIFY,
10626 + "Obj %d's parent is not a directory (type %d)",
10627 + obj->obj_id, obj->parent->variant_type);
10630 + switch (obj->variant_type) {
10631 + case YAFFS_OBJECT_TYPE_FILE:
10632 + yaffs_verify_file(obj);
10633 + break;
10634 + case YAFFS_OBJECT_TYPE_SYMLINK:
10635 + yaffs_verify_symlink(obj);
10636 + break;
10637 + case YAFFS_OBJECT_TYPE_DIRECTORY:
10638 + yaffs_verify_dir(obj);
10639 + break;
10640 + case YAFFS_OBJECT_TYPE_HARDLINK:
10641 + yaffs_verify_link(obj);
10642 + break;
10643 + case YAFFS_OBJECT_TYPE_SPECIAL:
10644 + yaffs_verify_special(obj);
10645 + break;
10646 + case YAFFS_OBJECT_TYPE_UNKNOWN:
10647 + default:
10648 + yaffs_trace(YAFFS_TRACE_VERIFY,
10649 + "Obj %d has illegaltype %d",
10650 + obj->obj_id, obj->variant_type);
10651 + break;
10655 +void yaffs_verify_objects(struct yaffs_dev *dev)
10657 + struct yaffs_obj *obj;
10658 + int i;
10659 + struct list_head *lh;
10661 + if (yaffs_skip_verification(dev))
10662 + return;
10664 + /* Iterate through the objects in each hash entry */
10666 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
10667 + list_for_each(lh, &dev->obj_bucket[i].list) {
10668 + obj = list_entry(lh, struct yaffs_obj, hash_link);
10669 + yaffs_verify_obj(obj);
10674 +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
10676 + struct list_head *lh;
10677 + struct yaffs_obj *list_obj;
10678 + int count = 0;
10680 + if (!obj) {
10681 + yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
10682 + BUG();
10683 + return;
10686 + if (yaffs_skip_verification(obj->my_dev))
10687 + return;
10689 + if (!obj->parent) {
10690 + yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
10691 + BUG();
10692 + return;
10695 + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
10696 + yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
10697 + BUG();
10700 + /* Iterate through the objects in each hash entry */
10702 + list_for_each(lh, &obj->parent->variant.dir_variant.children) {
10703 + list_obj = list_entry(lh, struct yaffs_obj, siblings);
10704 + yaffs_verify_obj(list_obj);
10705 + if (obj == list_obj)
10706 + count++;
10709 + if (count != 1) {
10710 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10711 + "Object in directory %d times",
10712 + count);
10713 + BUG();
10717 +void yaffs_verify_dir(struct yaffs_obj *directory)
10719 + struct list_head *lh;
10720 + struct yaffs_obj *list_obj;
10722 + if (!directory) {
10723 + BUG();
10724 + return;
10727 + if (yaffs_skip_full_verification(directory->my_dev))
10728 + return;
10730 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
10731 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10732 + "Directory has wrong type: %d",
10733 + directory->variant_type);
10734 + BUG();
10737 + /* Iterate through the objects in each hash entry */
10739 + list_for_each(lh, &directory->variant.dir_variant.children) {
10740 + list_obj = list_entry(lh, struct yaffs_obj, siblings);
10741 + if (list_obj->parent != directory) {
10742 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10743 + "Object in directory list has wrong parent %p",
10744 + list_obj->parent);
10745 + BUG();
10747 + yaffs_verify_obj_in_dir(list_obj);
10751 +static int yaffs_free_verification_failures;
10753 +void yaffs_verify_free_chunks(struct yaffs_dev *dev)
10755 + int counted;
10756 + int difference;
10758 + if (yaffs_skip_verification(dev))
10759 + return;
10761 + counted = yaffs_count_free_chunks(dev);
10763 + difference = dev->n_free_chunks - counted;
10765 + if (difference) {
10766 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10767 + "Freechunks verification failure %d %d %d",
10768 + dev->n_free_chunks, counted, difference);
10769 + yaffs_free_verification_failures++;
10773 +int yaffs_verify_file_sane(struct yaffs_obj *in)
10775 + (void) in;
10776 + return YAFFS_OK;
10778 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_verify.h linux-3.4.90/fs/yaffs2/yaffs_verify.h
10779 --- linux-3.4.90.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
10780 +++ linux-3.4.90/fs/yaffs2/yaffs_verify.h 2014-05-17 15:08:09.000000000 +0200
10781 @@ -0,0 +1,43 @@
10783 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
10785 + * Copyright (C) 2002-2011 Aleph One Ltd.
10786 + * for Toby Churchill Ltd and Brightstar Engineering
10788 + * Created by Charles Manning <charles@aleph1.co.uk>
10790 + * This program is free software; you can redistribute it and/or modify
10791 + * it under the terms of the GNU Lesser General Public License version 2.1 as
10792 + * published by the Free Software Foundation.
10794 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
10795 + */
10797 +#ifndef __YAFFS_VERIFY_H__
10798 +#define __YAFFS_VERIFY_H__
10800 +#include "yaffs_guts.h"
10802 +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
10803 + int n);
10804 +void yaffs_verify_collected_blk(struct yaffs_dev *dev,
10805 + struct yaffs_block_info *bi, int n);
10806 +void yaffs_verify_blocks(struct yaffs_dev *dev);
10808 +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
10809 + struct yaffs_ext_tags *tags, int parent_check);
10810 +void yaffs_verify_file(struct yaffs_obj *obj);
10811 +void yaffs_verify_link(struct yaffs_obj *obj);
10812 +void yaffs_verify_symlink(struct yaffs_obj *obj);
10813 +void yaffs_verify_special(struct yaffs_obj *obj);
10814 +void yaffs_verify_obj(struct yaffs_obj *obj);
10815 +void yaffs_verify_objects(struct yaffs_dev *dev);
10816 +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
10817 +void yaffs_verify_dir(struct yaffs_obj *directory);
10818 +void yaffs_verify_free_chunks(struct yaffs_dev *dev);
10820 +int yaffs_verify_file_sane(struct yaffs_obj *obj);
10822 +int yaffs_skip_verification(struct yaffs_dev *dev);
10824 +#endif
10825 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_vfs.c linux-3.4.90/fs/yaffs2/yaffs_vfs.c
10826 --- linux-3.4.90.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
10827 +++ linux-3.4.90/fs/yaffs2/yaffs_vfs.c 2014-05-17 15:08:09.000000000 +0200
10828 @@ -0,0 +1,3600 @@
10830 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
10832 + * Copyright (C) 2002-2011 Aleph One Ltd.
10833 + * for Toby Churchill Ltd and Brightstar Engineering
10835 + * Created by Charles Manning <charles@aleph1.co.uk>
10836 + * Acknowledgements:
10837 + * Luc van OostenRyck for numerous patches.
10838 + * Nick Bane for numerous patches.
10839 + * Nick Bane for 2.5/2.6 integration.
10840 + * Andras Toth for mknod rdev issue.
10841 + * Michael Fischer for finding the problem with inode inconsistency.
10842 + * Some code bodily lifted from JFFS
10844 + * This program is free software; you can redistribute it and/or modify
10845 + * it under the terms of the GNU General Public License version 2 as
10846 + * published by the Free Software Foundation.
10847 + */
10851 + * This is the file system front-end to YAFFS that hooks it up to
10852 + * the VFS.
10854 + * Special notes:
10855 + * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
10856 + * this superblock
10857 + * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
10858 + * superblock
10859 + * >> inode->u.generic_ip points to the associated struct yaffs_obj.
10860 + */
10863 + * There are two variants of the VFS glue code. This variant should compile
10864 + * for any version of Linux.
10865 + */
10866 +#include <linux/version.h>
10868 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
10869 +#define YAFFS_COMPILE_BACKGROUND
10870 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
10871 +#define YAFFS_COMPILE_FREEZER
10872 +#endif
10873 +#endif
10875 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
10876 +#define YAFFS_COMPILE_EXPORTFS
10877 +#endif
10879 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
10880 +#define YAFFS_USE_SETATTR_COPY
10881 +#define YAFFS_USE_TRUNCATE_SETSIZE
10882 +#endif
10883 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
10884 +#define YAFFS_HAS_EVICT_INODE
10885 +#endif
10887 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
10888 +#define YAFFS_NEW_FOLLOW_LINK 1
10889 +#else
10890 +#define YAFFS_NEW_FOLLOW_LINK 0
10891 +#endif
10893 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
10894 +#define YAFFS_HAS_WRITE_SUPER
10895 +#endif
10898 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
10899 +#include <linux/config.h>
10900 +#endif
10902 +#include <linux/kernel.h>
10903 +#include <linux/module.h>
10904 +#include <linux/slab.h>
10905 +#include <linux/init.h>
10906 +#include <linux/fs.h>
10907 +#include <linux/proc_fs.h>
10908 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
10909 +#include <linux/smp_lock.h>
10910 +#endif
10911 +#include <linux/pagemap.h>
10912 +#include <linux/mtd/mtd.h>
10913 +#include <linux/interrupt.h>
10914 +#include <linux/string.h>
10915 +#include <linux/ctype.h>
10917 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
10918 +#include <linux/namei.h>
10919 +#endif
10921 +#ifdef YAFFS_COMPILE_EXPORTFS
10922 +#include <linux/exportfs.h>
10923 +#endif
10925 +#ifdef YAFFS_COMPILE_BACKGROUND
10926 +#include <linux/kthread.h>
10927 +#include <linux/delay.h>
10928 +#endif
10929 +#ifdef YAFFS_COMPILE_FREEZER
10930 +#include <linux/freezer.h>
10931 +#endif
10933 +#include <asm/div64.h>
10935 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
10937 +#include <linux/statfs.h>
10939 +#define UnlockPage(p) unlock_page(p)
10940 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
10942 +/* FIXME: use sb->s_id instead ? */
10943 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
10945 +#else
10947 +#include <linux/locks.h>
10948 +#define BDEVNAME_SIZE 0
10949 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
10951 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
10952 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
10953 +#define __user
10954 +#endif
10956 +#endif
10958 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
10959 +#define YPROC_ROOT (&proc_root)
10960 +#else
10961 +#define YPROC_ROOT NULL
10962 +#endif
10964 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
10965 +#define Y_INIT_TIMER(a) init_timer(a)
10966 +#else
10967 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
10968 +#endif
10970 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
10971 +#define YAFFS_USE_WRITE_BEGIN_END 1
10972 +#else
10973 +#define YAFFS_USE_WRITE_BEGIN_END 0
10974 +#endif
10976 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
10977 +#define YAFFS_SUPER_HAS_DIRTY
10978 +#endif
10981 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
10982 +#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
10983 +#endif
10985 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
10986 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
10988 + uint64_t result = partition_size;
10989 + do_div(result, block_size);
10990 + return (uint32_t) result;
10992 +#else
10993 +#define YCALCBLOCKS(s, b) ((s)/(b))
10994 +#endif
10996 +#include <linux/uaccess.h>
10997 +#include <linux/mtd/mtd.h>
10999 +#include "yportenv.h"
11000 +#include "yaffs_trace.h"
11001 +#include "yaffs_guts.h"
11002 +#include "yaffs_attribs.h"
11004 +#include "yaffs_linux.h"
11006 +#include "yaffs_mtdif.h"
11007 +#include "yaffs_packedtags2.h"
11008 +#include "yaffs_getblockinfo.h"
11010 +unsigned int yaffs_trace_mask =
11011 + YAFFS_TRACE_BAD_BLOCKS |
11012 + YAFFS_TRACE_ALWAYS |
11013 + 0;
11015 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
11016 +unsigned int yaffs_auto_checkpoint = 1;
11017 +unsigned int yaffs_gc_control = 1;
11018 +unsigned int yaffs_bg_enable = 1;
11019 +unsigned int yaffs_auto_select = 1;
11020 +/* Module Parameters */
11021 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11022 +module_param(yaffs_trace_mask, uint, 0644);
11023 +module_param(yaffs_wr_attempts, uint, 0644);
11024 +module_param(yaffs_auto_checkpoint, uint, 0644);
11025 +module_param(yaffs_gc_control, uint, 0644);
11026 +module_param(yaffs_bg_enable, uint, 0644);
11027 +#else
11028 +MODULE_PARM(yaffs_trace_mask, "i");
11029 +MODULE_PARM(yaffs_wr_attempts, "i");
11030 +MODULE_PARM(yaffs_auto_checkpoint, "i");
11031 +MODULE_PARM(yaffs_gc_control, "i");
11032 +#endif
11034 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
11035 +/* use iget and read_inode */
11036 +#define Y_IGET(sb, inum) iget((sb), (inum))
11038 +#else
11039 +/* Call local equivalent */
11040 +#define YAFFS_USE_OWN_IGET
11041 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
11043 +#endif
11045 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
11046 +#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
11047 +#else
11048 +#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
11049 +#endif
11051 +#define yaffs_inode_to_obj(iptr) \
11052 + ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
11053 +#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
11055 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11056 +#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
11057 +#else
11058 +#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
11059 +#endif
11061 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
11062 +#define Y_CLEAR_INODE(i) clear_inode(i)
11063 +#else
11064 +#define Y_CLEAR_INODE(i) end_writeback(i)
11065 +#endif
11068 +#define update_dir_time(dir) do {\
11069 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
11070 + } while (0)
11072 +static void yaffs_fill_inode_from_obj(struct inode *inode,
11073 + struct yaffs_obj *obj);
11076 +static void yaffs_gross_lock(struct yaffs_dev *dev)
11078 + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
11079 + mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
11080 + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
11083 +static void yaffs_gross_unlock(struct yaffs_dev *dev)
11085 + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
11086 + mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
11090 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
11092 + /* Lifted from jffs2 */
11094 + struct yaffs_obj *obj;
11095 + unsigned char *pg_buf;
11096 + int ret;
11097 + loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
11098 + struct yaffs_dev *dev;
11100 + yaffs_trace(YAFFS_TRACE_OS,
11101 + "yaffs_readpage_nolock at %lld, size %08x",
11102 + (long long)pos,
11103 + (unsigned)PAGE_CACHE_SIZE);
11105 + obj = yaffs_dentry_to_obj(f->f_dentry);
11107 + dev = obj->my_dev;
11109 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11110 + BUG_ON(!PageLocked(pg));
11111 +#else
11112 + if (!PageLocked(pg))
11113 + PAGE_BUG(pg);
11114 +#endif
11116 + pg_buf = kmap(pg);
11117 + /* FIXME: Can kmap fail? */
11119 + yaffs_gross_lock(dev);
11121 + ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
11123 + yaffs_gross_unlock(dev);
11125 + if (ret >= 0)
11126 + ret = 0;
11128 + if (ret) {
11129 + ClearPageUptodate(pg);
11130 + SetPageError(pg);
11131 + } else {
11132 + SetPageUptodate(pg);
11133 + ClearPageError(pg);
11136 + flush_dcache_page(pg);
11137 + kunmap(pg);
11139 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
11140 + return ret;
11143 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
11145 + int ret = yaffs_readpage_nolock(f, pg);
11146 + UnlockPage(pg);
11147 + return ret;
11150 +static int yaffs_readpage(struct file *f, struct page *pg)
11152 + int ret;
11154 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
11155 + ret = yaffs_readpage_unlock(f, pg);
11156 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
11157 + return ret;
11160 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
11161 +#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
11162 +#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
11163 +#else
11164 +#define YCRED_FSUID() YCRED(current)->fsuid
11165 +#define YCRED_FSGID() YCRED(current)->fsgid
11167 +static inline uid_t i_uid_read(const struct inode *inode)
11169 + return inode->i_uid;
11172 +static inline gid_t i_gid_read(const struct inode *inode)
11174 + return inode->i_gid;
11177 +static inline void i_uid_write(struct inode *inode, uid_t uid)
11179 + inode->i_uid = uid;
11182 +static inline void i_gid_write(struct inode *inode, gid_t gid)
11184 + inode->i_gid = gid;
11186 +#endif
11188 +static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
11190 + struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
11192 + if (lc)
11193 + lc->dirty = val;
11195 +# ifdef YAFFS_SUPER_HAS_DIRTY
11197 + struct super_block *sb = lc->super;
11199 + if (sb)
11200 + sb->s_dirt = val;
11202 +#endif
11206 +static void yaffs_set_super_dirty(struct yaffs_dev *dev)
11208 + yaffs_set_super_dirty_val(dev, 1);
11211 +static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
11213 + yaffs_set_super_dirty_val(dev, 0);
11216 +static int yaffs_check_super_dirty(struct yaffs_dev *dev)
11218 + struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
11220 + if (lc && lc->dirty)
11221 + return 1;
11223 +# ifdef YAFFS_SUPER_HAS_DIRTY
11225 + struct super_block *sb = lc->super;
11227 + if (sb && sb->s_dirt)
11228 + return 1;
11230 +#endif
11231 + return 0;
11235 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11236 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
11237 +#else
11238 +static int yaffs_writepage(struct page *page)
11239 +#endif
11241 + struct yaffs_dev *dev;
11242 + struct address_space *mapping = page->mapping;
11243 + struct inode *inode;
11244 + unsigned long end_index;
11245 + char *buffer;
11246 + struct yaffs_obj *obj;
11247 + int n_written = 0;
11248 + unsigned n_bytes;
11249 + loff_t i_size;
11251 + if (!mapping)
11252 + BUG();
11253 + inode = mapping->host;
11254 + if (!inode)
11255 + BUG();
11256 + i_size = i_size_read(inode);
11258 + end_index = i_size >> PAGE_CACHE_SHIFT;
11260 + if (page->index < end_index)
11261 + n_bytes = PAGE_CACHE_SIZE;
11262 + else {
11263 + n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
11265 + if (page->index > end_index || !n_bytes) {
11266 + yaffs_trace(YAFFS_TRACE_OS,
11267 + "yaffs_writepage at %lld, inode size = %lld!!",
11268 + ((loff_t)page->index) << PAGE_CACHE_SHIFT,
11269 + inode->i_size);
11270 + yaffs_trace(YAFFS_TRACE_OS,
11271 + " -> don't care!!");
11273 + zero_user_segment(page, 0, PAGE_CACHE_SIZE);
11274 + set_page_writeback(page);
11275 + unlock_page(page);
11276 + end_page_writeback(page);
11277 + return 0;
11281 + if (n_bytes != PAGE_CACHE_SIZE)
11282 + zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
11284 + get_page(page);
11286 + buffer = kmap(page);
11288 + obj = yaffs_inode_to_obj(inode);
11289 + dev = obj->my_dev;
11290 + yaffs_gross_lock(dev);
11292 + yaffs_trace(YAFFS_TRACE_OS,
11293 + "yaffs_writepage at %lld, size %08x",
11294 + ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
11295 + yaffs_trace(YAFFS_TRACE_OS,
11296 + "writepag0: obj = %lld, ino = %lld",
11297 + obj->variant.file_variant.file_size, inode->i_size);
11299 + n_written = yaffs_wr_file(obj, buffer,
11300 + ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
11302 + yaffs_set_super_dirty(dev);
11304 + yaffs_trace(YAFFS_TRACE_OS,
11305 + "writepag1: obj = %lld, ino = %lld",
11306 + obj->variant.file_variant.file_size, inode->i_size);
11308 + yaffs_gross_unlock(dev);
11310 + kunmap(page);
11311 + set_page_writeback(page);
11312 + unlock_page(page);
11313 + end_page_writeback(page);
11314 + put_page(page);
11316 + return (n_written == n_bytes) ? 0 : -ENOSPC;
11319 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
11320 +/* For now we just assume few parallel writes and check against a small number. */
11321 +/* Todo: need to do this with a counter to handle parallel reads better */
11323 +static ssize_t yaffs_hold_space(struct file *f)
11325 + struct yaffs_obj *obj;
11326 + struct yaffs_dev *dev;
11328 + int n_free_chunks;
11330 + obj = yaffs_dentry_to_obj(f->f_dentry);
11332 + dev = obj->my_dev;
11334 + yaffs_gross_lock(dev);
11336 + n_free_chunks = yaffs_get_n_free_chunks(dev);
11338 + yaffs_gross_unlock(dev);
11340 + return (n_free_chunks > 20) ? 1 : 0;
11343 +static void yaffs_release_space(struct file *f)
11345 + struct yaffs_obj *obj;
11346 + struct yaffs_dev *dev;
11348 + obj = yaffs_dentry_to_obj(f->f_dentry);
11350 + dev = obj->my_dev;
11352 + yaffs_gross_lock(dev);
11354 + yaffs_gross_unlock(dev);
11357 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
11358 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
11359 + loff_t pos, unsigned len, unsigned flags,
11360 + struct page **pagep, void **fsdata)
11362 + struct page *pg = NULL;
11363 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
11365 + int ret = 0;
11366 + int space_held = 0;
11368 + /* Get a page */
11369 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
11370 + pg = grab_cache_page_write_begin(mapping, index, flags);
11371 +#else
11372 + pg = __grab_cache_page(mapping, index);
11373 +#endif
11375 + *pagep = pg;
11376 + if (!pg) {
11377 + ret = -ENOMEM;
11378 + goto out;
11380 + yaffs_trace(YAFFS_TRACE_OS,
11381 + "start yaffs_write_begin index %d(%x) uptodate %d",
11382 + (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
11384 + /* Get fs space */
11385 + space_held = yaffs_hold_space(filp);
11387 + if (!space_held) {
11388 + ret = -ENOSPC;
11389 + goto out;
11392 + /* Update page if required */
11394 + if (!Page_Uptodate(pg))
11395 + ret = yaffs_readpage_nolock(filp, pg);
11397 + if (ret)
11398 + goto out;
11400 + /* Happy path return */
11401 + yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
11403 + return 0;
11405 +out:
11406 + yaffs_trace(YAFFS_TRACE_OS,
11407 + "end yaffs_write_begin fail returning %d", ret);
11408 + if (space_held)
11409 + yaffs_release_space(filp);
11410 + if (pg) {
11411 + unlock_page(pg);
11412 + page_cache_release(pg);
11414 + return ret;
11417 +#else
11419 +static int yaffs_prepare_write(struct file *f, struct page *pg,
11420 + unsigned offset, unsigned to)
11422 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
11424 + if (!Page_Uptodate(pg))
11425 + return yaffs_readpage_nolock(f, pg);
11426 + return 0;
11428 +#endif
11431 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
11432 + loff_t * pos)
11434 + struct yaffs_obj *obj;
11435 + int n_written;
11436 + loff_t ipos;
11437 + struct inode *inode;
11438 + struct yaffs_dev *dev;
11440 + obj = yaffs_dentry_to_obj(f->f_dentry);
11442 + if (!obj) {
11443 + yaffs_trace(YAFFS_TRACE_OS,
11444 + "yaffs_file_write: hey obj is null!");
11445 + return -EINVAL;
11448 + dev = obj->my_dev;
11450 + yaffs_gross_lock(dev);
11452 + inode = f->f_dentry->d_inode;
11454 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
11455 + ipos = inode->i_size;
11456 + else
11457 + ipos = *pos;
11459 + yaffs_trace(YAFFS_TRACE_OS,
11460 + "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
11461 + (unsigned)n, (unsigned)n, obj->obj_id, ipos);
11463 + n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
11465 + yaffs_set_super_dirty(dev);
11467 + yaffs_trace(YAFFS_TRACE_OS,
11468 + "yaffs_file_write: %d(%x) bytes written",
11469 + (unsigned)n, (unsigned)n);
11471 + if (n_written > 0) {
11472 + ipos += n_written;
11473 + *pos = ipos;
11474 + if (ipos > inode->i_size) {
11475 + inode->i_size = ipos;
11476 + inode->i_blocks = (ipos + 511) >> 9;
11478 + yaffs_trace(YAFFS_TRACE_OS,
11479 + "yaffs_file_write size updated to %lld bytes, %d blocks",
11480 + ipos, (int)(inode->i_blocks));
11484 + yaffs_gross_unlock(dev);
11485 + return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
11489 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
11490 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
11491 + loff_t pos, unsigned len, unsigned copied,
11492 + struct page *pg, void *fsdadata)
11494 + int ret = 0;
11495 + void *addr, *kva;
11496 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
11498 + kva = kmap(pg);
11499 + addr = kva + offset_into_page;
11501 + yaffs_trace(YAFFS_TRACE_OS,
11502 + "yaffs_write_end addr %p pos %lld n_bytes %d",
11503 + addr, pos, copied);
11505 + ret = yaffs_file_write(filp, addr, copied, &pos);
11507 + if (ret != copied) {
11508 + yaffs_trace(YAFFS_TRACE_OS,
11509 + "yaffs_write_end not same size ret %d copied %d",
11510 + ret, copied);
11511 + SetPageError(pg);
11514 + kunmap(pg);
11516 + yaffs_release_space(filp);
11517 + unlock_page(pg);
11518 + page_cache_release(pg);
11519 + return ret;
11521 +#else
11523 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
11524 + unsigned to)
11526 + void *addr, *kva;
11528 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
11529 + int n_bytes = to - offset;
11530 + int n_written;
11532 + kva = kmap(pg);
11533 + addr = kva + offset;
11535 + yaffs_trace(YAFFS_TRACE_OS,
11536 + "yaffs_commit_write addr %p pos %lld n_bytes %d",
11537 + addr, pos, n_bytes);
11539 + n_written = yaffs_file_write(f, addr, n_bytes, &pos);
11541 + if (n_written != n_bytes) {
11542 + yaffs_trace(YAFFS_TRACE_OS,
11543 + "yaffs_commit_write not same size n_written %d n_bytes %d",
11544 + n_written, n_bytes);
11545 + SetPageError(pg);
11547 + kunmap(pg);
11549 + yaffs_trace(YAFFS_TRACE_OS,
11550 + "yaffs_commit_write returning %d",
11551 + n_written == n_bytes ? 0 : n_written);
11553 + return n_written == n_bytes ? 0 : n_written;
11555 +#endif
11557 +static struct address_space_operations yaffs_file_address_operations = {
11558 + .readpage = yaffs_readpage,
11559 + .writepage = yaffs_writepage,
11560 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
11561 + .write_begin = yaffs_write_begin,
11562 + .write_end = yaffs_write_end,
11563 +#else
11564 + .prepare_write = yaffs_prepare_write,
11565 + .commit_write = yaffs_commit_write,
11566 +#endif
11570 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
11571 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
11572 +#else
11573 +static int yaffs_file_flush(struct file *file)
11574 +#endif
11576 + struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
11578 + struct yaffs_dev *dev = obj->my_dev;
11580 + yaffs_trace(YAFFS_TRACE_OS,
11581 + "yaffs_file_flush object %d (%s)",
11582 + obj->obj_id,
11583 + obj->dirty ? "dirty" : "clean");
11585 + yaffs_gross_lock(dev);
11587 + yaffs_flush_file(obj, 1, 0);
11589 + yaffs_gross_unlock(dev);
11591 + return 0;
11595 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
11596 +static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
11597 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
11598 +static int yaffs_sync_object(struct file *file, int datasync)
11599 +#else
11600 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
11601 + int datasync)
11602 +#endif
11604 + struct yaffs_obj *obj;
11605 + struct yaffs_dev *dev;
11606 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
11607 + struct dentry *dentry = file->f_path.dentry;
11608 +#endif
11610 + obj = yaffs_dentry_to_obj(dentry);
11612 + dev = obj->my_dev;
11614 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
11615 + "yaffs_sync_object");
11616 + yaffs_gross_lock(dev);
11617 + yaffs_flush_file(obj, 1, datasync);
11618 + yaffs_gross_unlock(dev);
11619 + return 0;
11623 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
11624 +static const struct file_operations yaffs_file_operations = {
11625 + .read = do_sync_read,
11626 + .write = do_sync_write,
11627 + .aio_read = generic_file_aio_read,
11628 + .aio_write = generic_file_aio_write,
11629 + .mmap = generic_file_mmap,
11630 + .flush = yaffs_file_flush,
11631 + .fsync = yaffs_sync_object,
11632 + .splice_read = generic_file_splice_read,
11633 + .splice_write = generic_file_splice_write,
11634 + .llseek = generic_file_llseek,
11637 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
11639 +static const struct file_operations yaffs_file_operations = {
11640 + .read = do_sync_read,
11641 + .write = do_sync_write,
11642 + .aio_read = generic_file_aio_read,
11643 + .aio_write = generic_file_aio_write,
11644 + .mmap = generic_file_mmap,
11645 + .flush = yaffs_file_flush,
11646 + .fsync = yaffs_sync_object,
11647 + .sendfile = generic_file_sendfile,
11650 +#else
11652 +static const struct file_operations yaffs_file_operations = {
11653 + .read = generic_file_read,
11654 + .write = generic_file_write,
11655 + .mmap = generic_file_mmap,
11656 + .flush = yaffs_file_flush,
11657 + .fsync = yaffs_sync_object,
11658 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11659 + .sendfile = generic_file_sendfile,
11660 +#endif
11662 +#endif
11667 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
11668 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
11670 + void *kaddr = kmap_atomic(page, KM_USER0);
11671 + memset(kaddr + start, 0, end - start);
11672 + kunmap_atomic(kaddr, KM_USER0);
11673 + flush_dcache_page(page);
11675 +#endif
11678 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
11680 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
11681 + truncate_setsize(inode, newsize);
11682 + return 0;
11683 +#else
11684 + truncate_inode_pages(&inode->i_data, newsize);
11685 + return 0;
11686 +#endif
11691 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
11693 +#ifdef YAFFS_USE_SETATTR_COPY
11694 + setattr_copy(inode, attr);
11695 + return 0;
11696 +#else
11697 + return inode_setattr(inode, attr);
11698 +#endif
11702 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
11704 + struct inode *inode = dentry->d_inode;
11705 + int error = 0;
11706 + struct yaffs_dev *dev;
11708 + yaffs_trace(YAFFS_TRACE_OS,
11709 + "yaffs_setattr of object %d",
11710 + yaffs_inode_to_obj(inode)->obj_id);
11711 +#if 0
11712 + /* Fail if a requested resize >= 2GB */
11713 + if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
11714 + error = -EINVAL;
11715 +#endif
11717 + if (error == 0)
11718 + error = inode_change_ok(inode, attr);
11719 + if (error == 0) {
11720 + int result;
11721 + if (!error) {
11722 + error = yaffs_vfs_setattr(inode, attr);
11723 + yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
11724 + if (attr->ia_valid & ATTR_SIZE) {
11725 + yaffs_vfs_setsize(inode, attr->ia_size);
11726 + inode->i_blocks = (inode->i_size + 511) >> 9;
11729 + dev = yaffs_inode_to_obj(inode)->my_dev;
11730 + if (attr->ia_valid & ATTR_SIZE) {
11731 + yaffs_trace(YAFFS_TRACE_OS,
11732 + "resize to %d(%x)",
11733 + (int)(attr->ia_size),
11734 + (int)(attr->ia_size));
11736 + yaffs_gross_lock(dev);
11737 + result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
11738 + if (result == YAFFS_OK) {
11739 + error = 0;
11740 + } else {
11741 + error = -EPERM;
11743 + yaffs_gross_unlock(dev);
11747 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
11749 + return error;
11752 +static int yaffs_setxattr(struct dentry *dentry, const char *name,
11753 + const void *value, size_t size, int flags)
11755 + struct inode *inode = dentry->d_inode;
11756 + int error = 0;
11757 + struct yaffs_dev *dev;
11758 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11760 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
11762 + if (error == 0) {
11763 + int result;
11764 + dev = obj->my_dev;
11765 + yaffs_gross_lock(dev);
11766 + result = yaffs_set_xattrib(obj, name, value, size, flags);
11767 + if (result == YAFFS_OK)
11768 + error = 0;
11769 + else if (result < 0)
11770 + error = result;
11771 + yaffs_gross_unlock(dev);
11774 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
11776 + return error;
11779 +static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
11780 + void *buff, size_t size)
11782 + struct inode *inode = dentry->d_inode;
11783 + int error = 0;
11784 + struct yaffs_dev *dev;
11785 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11787 + yaffs_trace(YAFFS_TRACE_OS,
11788 + "yaffs_getxattr \"%s\" from object %d",
11789 + name, obj->obj_id);
11791 + if (error == 0) {
11792 + dev = obj->my_dev;
11793 + yaffs_gross_lock(dev);
11794 + error = yaffs_get_xattrib(obj, name, buff, size);
11795 + yaffs_gross_unlock(dev);
11798 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
11800 + return error;
11803 +static int yaffs_removexattr(struct dentry *dentry, const char *name)
11805 + struct inode *inode = dentry->d_inode;
11806 + int error = 0;
11807 + struct yaffs_dev *dev;
11808 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11810 + yaffs_trace(YAFFS_TRACE_OS,
11811 + "yaffs_removexattr of object %d", obj->obj_id);
11813 + if (error == 0) {
11814 + int result;
11815 + dev = obj->my_dev;
11816 + yaffs_gross_lock(dev);
11817 + result = yaffs_remove_xattrib(obj, name);
11818 + if (result == YAFFS_OK)
11819 + error = 0;
11820 + else if (result < 0)
11821 + error = result;
11822 + yaffs_gross_unlock(dev);
11825 + yaffs_trace(YAFFS_TRACE_OS,
11826 + "yaffs_removexattr done returning %d", error);
11828 + return error;
11831 +static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
11833 + struct inode *inode = dentry->d_inode;
11834 + int error = 0;
11835 + struct yaffs_dev *dev;
11836 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11838 + yaffs_trace(YAFFS_TRACE_OS,
11839 + "yaffs_listxattr of object %d", obj->obj_id);
11841 + if (error == 0) {
11842 + dev = obj->my_dev;
11843 + yaffs_gross_lock(dev);
11844 + error = yaffs_list_xattrib(obj, buff, size);
11845 + yaffs_gross_unlock(dev);
11848 + yaffs_trace(YAFFS_TRACE_OS,
11849 + "yaffs_listxattr done returning %d", error);
11851 + return error;
11855 +static const struct inode_operations yaffs_file_inode_operations = {
11856 + .setattr = yaffs_setattr,
11857 + .setxattr = yaffs_setxattr,
11858 + .getxattr = yaffs_getxattr,
11859 + .listxattr = yaffs_listxattr,
11860 + .removexattr = yaffs_removexattr,
11864 +static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
11865 + int buflen)
11867 + unsigned char *alias;
11868 + int ret;
11870 + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
11872 + yaffs_gross_lock(dev);
11874 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
11876 + yaffs_gross_unlock(dev);
11878 + if (!alias)
11879 + return -ENOMEM;
11881 + ret = vfs_readlink(dentry, buffer, buflen, alias);
11882 + kfree(alias);
11883 + return ret;
11886 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11887 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
11889 + void *ret;
11890 +#else
11891 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
11893 + int ret
11894 +#endif
11895 + unsigned char *alias;
11896 + int ret_int = 0;
11897 + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
11899 + yaffs_gross_lock(dev);
11901 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
11902 + yaffs_gross_unlock(dev);
11904 + if (!alias) {
11905 + ret_int = -ENOMEM;
11906 + goto out;
11908 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11909 + nd_set_link(nd, alias);
11910 + ret = alias;
11911 +out:
11912 + if (ret_int)
11913 + ret = ERR_PTR(ret_int);
11914 + return ret;
11915 +#else
11916 + ret = vfs_follow_link(nd, alias);
11917 + kfree(alias);
11918 +out:
11919 + if (ret_int)
11920 + ret = ret_int;
11921 + return ret;
11922 +#endif
11926 +#ifdef YAFFS_HAS_PUT_INODE
11928 +/* For now put inode is just for debugging
11929 + * Put inode is called when the inode **structure** is put.
11930 + */
11931 +static void yaffs_put_inode(struct inode *inode)
11933 + yaffs_trace(YAFFS_TRACE_OS,
11934 + "yaffs_put_inode: ino %d, count %d"),
11935 + (int)inode->i_ino, atomic_read(&inode->i_count);
11938 +#endif
11940 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11941 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
11943 + kfree(alias);
11945 +#endif
11947 +static const struct inode_operations yaffs_symlink_inode_operations = {
11948 + .readlink = yaffs_readlink,
11949 + .follow_link = yaffs_follow_link,
11950 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11951 + .put_link = yaffs_put_link,
11952 +#endif
11953 + .setattr = yaffs_setattr,
11954 + .setxattr = yaffs_setxattr,
11955 + .getxattr = yaffs_getxattr,
11956 + .listxattr = yaffs_listxattr,
11957 + .removexattr = yaffs_removexattr,
11960 +#ifdef YAFFS_USE_OWN_IGET
11962 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
11964 + struct inode *inode;
11965 + struct yaffs_obj *obj;
11966 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
11968 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
11970 + inode = iget_locked(sb, ino);
11971 + if (!inode)
11972 + return ERR_PTR(-ENOMEM);
11973 + if (!(inode->i_state & I_NEW))
11974 + return inode;
11976 + /* NB This is called as a side effect of other functions, but
11977 + * we had to release the lock to prevent deadlocks, so
11978 + * need to lock again.
11979 + */
11981 + yaffs_gross_lock(dev);
11983 + obj = yaffs_find_by_number(dev, inode->i_ino);
11985 + yaffs_fill_inode_from_obj(inode, obj);
11987 + yaffs_gross_unlock(dev);
11989 + unlock_new_inode(inode);
11990 + return inode;
11993 +#else
11995 +static void yaffs_read_inode(struct inode *inode)
11997 + /* NB This is called as a side effect of other functions, but
11998 + * we had to release the lock to prevent deadlocks, so
11999 + * need to lock again.
12000 + */
12002 + struct yaffs_obj *obj;
12003 + struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
12005 + yaffs_trace(YAFFS_TRACE_OS,
12006 + "yaffs_read_inode for %d", (int)inode->i_ino);
12008 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
12009 + yaffs_gross_lock(dev);
12011 + obj = yaffs_find_by_number(dev, inode->i_ino);
12013 + yaffs_fill_inode_from_obj(inode, obj);
12015 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
12016 + yaffs_gross_unlock(dev);
12019 +#endif
12023 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
12024 + struct yaffs_obj *obj)
12026 + struct inode *inode;
12028 + if (!sb) {
12029 + yaffs_trace(YAFFS_TRACE_OS,
12030 + "yaffs_get_inode for NULL super_block!!");
12031 + return NULL;
12035 + if (!obj) {
12036 + yaffs_trace(YAFFS_TRACE_OS,
12037 + "yaffs_get_inode for NULL object!!");
12038 + return NULL;
12042 + yaffs_trace(YAFFS_TRACE_OS,
12043 + "yaffs_get_inode for object %d", obj->obj_id);
12045 + inode = Y_IGET(sb, obj->obj_id);
12046 + if (IS_ERR(inode))
12047 + return NULL;
12049 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
12050 + /* iget also increments the inode's i_count */
12051 + /* NB You can't be holding gross_lock or deadlock will happen! */
12053 + return inode;
12058 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
12059 +#define YCRED(x) x
12060 +#else
12061 +#define YCRED(x) (x->cred)
12062 +#endif
12064 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12065 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
12066 + dev_t rdev)
12067 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12068 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
12069 + dev_t rdev)
12070 +#else
12071 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
12072 + int rdev)
12073 +#endif
12075 + struct inode *inode;
12077 + struct yaffs_obj *obj = NULL;
12078 + struct yaffs_dev *dev;
12080 + struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
12082 + int error = -ENOSPC;
12083 + uid_t uid = YCRED_FSUID();
12084 + gid_t gid =
12085 + (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
12087 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
12088 + mode |= S_ISGID;
12090 + if (parent) {
12091 + yaffs_trace(YAFFS_TRACE_OS,
12092 + "yaffs_mknod: parent object %d type %d",
12093 + parent->obj_id, parent->variant_type);
12094 + } else {
12095 + yaffs_trace(YAFFS_TRACE_OS,
12096 + "yaffs_mknod: could not get parent object");
12097 + return -EPERM;
12100 + yaffs_trace(YAFFS_TRACE_OS,
12101 + "yaffs_mknod: making oject for %s, mode %x dev %x",
12102 + dentry->d_name.name, mode, rdev);
12104 + dev = parent->my_dev;
12106 + yaffs_gross_lock(dev);
12108 + switch (mode & S_IFMT) {
12109 + default:
12110 + /* Special (socket, fifo, device...) */
12111 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
12112 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12113 + obj =
12114 + yaffs_create_special(parent, dentry->d_name.name, mode, uid,
12115 + gid, old_encode_dev(rdev));
12116 +#else
12117 + obj =
12118 + yaffs_create_special(parent, dentry->d_name.name, mode, uid,
12119 + gid, rdev);
12120 +#endif
12121 + break;
12122 + case S_IFREG: /* file */
12123 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
12124 + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
12125 + gid);
12126 + break;
12127 + case S_IFDIR: /* directory */
12128 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
12129 + obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
12130 + uid, gid);
12131 + break;
12132 + case S_IFLNK: /* symlink */
12133 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
12134 + obj = NULL; /* Do we ever get here? */
12135 + break;
12138 + /* Can not call yaffs_get_inode() with gross lock held */
12139 + yaffs_gross_unlock(dev);
12141 + if (obj) {
12142 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
12143 + d_instantiate(dentry, inode);
12144 + update_dir_time(dir);
12145 + yaffs_trace(YAFFS_TRACE_OS,
12146 + "yaffs_mknod created object %d count = %d",
12147 + obj->obj_id, atomic_read(&inode->i_count));
12148 + error = 0;
12149 + yaffs_fill_inode_from_obj(dir, parent);
12150 + } else {
12151 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
12152 + error = -ENOMEM;
12155 + return error;
12158 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12159 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
12160 +#else
12161 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
12162 +#endif
12164 + int ret_val;
12165 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
12166 + ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
12167 + return ret_val;
12171 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12172 +static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
12173 + bool dummy)
12174 +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12175 +static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
12176 + struct nameidata *n)
12177 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12178 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
12179 + struct nameidata *n)
12180 +#else
12181 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
12182 +#endif
12184 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
12185 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
12188 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12189 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
12190 + unsigned int dummy)
12191 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12192 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
12193 + struct nameidata *n)
12194 +#else
12195 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
12196 +#endif
12198 + struct yaffs_obj *obj;
12199 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
12201 + struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
12203 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
12204 + yaffs_gross_lock(dev);
12206 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
12207 + yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
12209 + obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
12211 + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
12213 + /* Can't hold gross lock when calling yaffs_get_inode() */
12214 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
12215 + yaffs_gross_unlock(dev);
12217 + if (obj) {
12218 + yaffs_trace(YAFFS_TRACE_OS,
12219 + "yaffs_lookup found %d", obj->obj_id);
12221 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
12222 + } else {
12223 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
12227 +/* added NCB for 2.5/6 compatability - forces add even if inode is
12228 + * NULL which creates dentry hash */
12229 + d_add(dentry, inode);
12231 + return NULL;
12235 + * Create a link...
12236 + */
12237 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
12238 + struct dentry *dentry)
12240 + struct inode *inode = old_dentry->d_inode;
12241 + struct yaffs_obj *obj = NULL;
12242 + struct yaffs_obj *link = NULL;
12243 + struct yaffs_dev *dev;
12245 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
12247 + obj = yaffs_inode_to_obj(inode);
12248 + dev = obj->my_dev;
12250 + yaffs_gross_lock(dev);
12252 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
12253 + link =
12254 + yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
12255 + obj);
12257 + if (link) {
12258 + set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
12259 + d_instantiate(dentry, old_dentry->d_inode);
12260 + atomic_inc(&old_dentry->d_inode->i_count);
12261 + yaffs_trace(YAFFS_TRACE_OS,
12262 + "yaffs_link link count %d i_count %d",
12263 + old_dentry->d_inode->i_nlink,
12264 + atomic_read(&old_dentry->d_inode->i_count));
12267 + yaffs_gross_unlock(dev);
12269 + if (link) {
12270 + update_dir_time(dir);
12271 + return 0;
12274 + return -EPERM;
12277 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
12278 + const char *symname)
12280 + struct yaffs_obj *obj;
12281 + struct yaffs_dev *dev;
12282 + uid_t uid = YCRED_FSUID();
12283 + gid_t gid =
12284 + (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
12286 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
12288 + if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
12289 + YAFFS_MAX_NAME_LENGTH)
12290 + return -ENAMETOOLONG;
12292 + if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
12293 + YAFFS_MAX_ALIAS_LENGTH)
12294 + return -ENAMETOOLONG;
12296 + dev = yaffs_inode_to_obj(dir)->my_dev;
12297 + yaffs_gross_lock(dev);
12298 + obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
12299 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
12300 + yaffs_gross_unlock(dev);
12302 + if (obj) {
12303 + struct inode *inode;
12305 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
12306 + d_instantiate(dentry, inode);
12307 + update_dir_time(dir);
12308 + yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
12309 + return 0;
12310 + } else {
12311 + yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
12314 + return -ENOMEM;
12318 + * The VFS layer already does all the dentry stuff for rename.
12320 + * NB: POSIX says you can rename an object over an old object of the same name
12321 + */
12322 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
12323 + struct inode *new_dir, struct dentry *new_dentry)
12325 + struct yaffs_dev *dev;
12326 + int ret_val = YAFFS_FAIL;
12327 + struct yaffs_obj *target;
12329 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
12330 + dev = yaffs_inode_to_obj(old_dir)->my_dev;
12332 + yaffs_gross_lock(dev);
12334 + /* Check if the target is an existing directory that is not empty. */
12335 + target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
12336 + new_dentry->d_name.name);
12338 + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
12339 + !list_empty(&target->variant.dir_variant.children)) {
12341 + yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
12343 + ret_val = YAFFS_FAIL;
12344 + } else {
12345 + /* Now does unlinking internally using shadowing mechanism */
12346 + yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
12348 + ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
12349 + old_dentry->d_name.name,
12350 + yaffs_inode_to_obj(new_dir),
12351 + new_dentry->d_name.name);
12353 + yaffs_gross_unlock(dev);
12355 + if (ret_val == YAFFS_OK) {
12356 + if (target)
12357 + inode_dec_link_count(new_dentry->d_inode);
12359 + update_dir_time(old_dir);
12360 + if (old_dir != new_dir)
12361 + update_dir_time(new_dir);
12362 + return 0;
12363 + } else {
12364 + return -ENOTEMPTY;
12371 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
12373 + int ret_val;
12375 + struct yaffs_dev *dev;
12376 + struct yaffs_obj *obj;
12378 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
12379 + (int)(dir->i_ino), dentry->d_name.name);
12380 + obj = yaffs_inode_to_obj(dir);
12381 + dev = obj->my_dev;
12383 + yaffs_gross_lock(dev);
12385 + ret_val = yaffs_unlinker(obj, dentry->d_name.name);
12387 + if (ret_val == YAFFS_OK) {
12388 + inode_dec_link_count(dentry->d_inode);
12389 + dir->i_version++;
12390 + yaffs_gross_unlock(dev);
12391 + update_dir_time(dir);
12392 + return 0;
12394 + yaffs_gross_unlock(dev);
12395 + return -ENOTEMPTY;
12400 +static const struct inode_operations yaffs_dir_inode_operations = {
12401 + .create = yaffs_create,
12402 + .lookup = yaffs_lookup,
12403 + .link = yaffs_link,
12404 + .unlink = yaffs_unlink,
12405 + .symlink = yaffs_symlink,
12406 + .mkdir = yaffs_mkdir,
12407 + .rmdir = yaffs_unlink,
12408 + .mknod = yaffs_mknod,
12409 + .rename = yaffs_rename,
12410 + .setattr = yaffs_setattr,
12411 + .setxattr = yaffs_setxattr,
12412 + .getxattr = yaffs_getxattr,
12413 + .listxattr = yaffs_listxattr,
12414 + .removexattr = yaffs_removexattr,
12417 +/*-----------------------------------------------------------------*/
12418 +/* Directory search context allows us to unlock access to yaffs during
12419 + * filldir without causing problems with the directory being modified.
12420 + * This is similar to the tried and tested mechanism used in yaffs direct.
12422 + * A search context iterates along a doubly linked list of siblings in the
12423 + * directory. If the iterating object is deleted then this would corrupt
12424 + * the list iteration, likely causing a crash. The search context avoids
12425 + * this by using the remove_obj_fn to move the search context to the
12426 + * next object before the object is deleted.
12428 + * Many readdirs (and thus seach conexts) may be alive simulateously so
12429 + * each struct yaffs_dev has a list of these.
12431 + * A seach context lives for the duration of a readdir.
12433 + * All these functions must be called while yaffs is locked.
12434 + */
12436 +struct yaffs_search_context {
12437 + struct yaffs_dev *dev;
12438 + struct yaffs_obj *dir_obj;
12439 + struct yaffs_obj *next_return;
12440 + struct list_head others;
12444 + * yaffs_new_search() creates a new search context, initialises it and
12445 + * adds it to the device's search context list.
12447 + * Called at start of readdir.
12448 + */
12449 +static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
12451 + struct yaffs_dev *dev = dir->my_dev;
12452 + struct yaffs_search_context *sc =
12453 + kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
12454 + if (sc) {
12455 + sc->dir_obj = dir;
12456 + sc->dev = dev;
12457 + if (list_empty(&sc->dir_obj->variant.dir_variant.children))
12458 + sc->next_return = NULL;
12459 + else
12460 + sc->next_return =
12461 + list_entry(dir->variant.dir_variant.children.next,
12462 + struct yaffs_obj, siblings);
12463 + INIT_LIST_HEAD(&sc->others);
12464 + list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
12466 + return sc;
12470 + * yaffs_search_end() disposes of a search context and cleans up.
12471 + */
12472 +static void yaffs_search_end(struct yaffs_search_context *sc)
12474 + if (sc) {
12475 + list_del(&sc->others);
12476 + kfree(sc);
12481 + * yaffs_search_advance() moves a search context to the next object.
12482 + * Called when the search iterates or when an object removal causes
12483 + * the search context to be moved to the next object.
12484 + */
12485 +static void yaffs_search_advance(struct yaffs_search_context *sc)
12487 + if (!sc)
12488 + return;
12490 + if (sc->next_return == NULL ||
12491 + list_empty(&sc->dir_obj->variant.dir_variant.children))
12492 + sc->next_return = NULL;
12493 + else {
12494 + struct list_head *next = sc->next_return->siblings.next;
12496 + if (next == &sc->dir_obj->variant.dir_variant.children)
12497 + sc->next_return = NULL; /* end of list */
12498 + else
12499 + sc->next_return =
12500 + list_entry(next, struct yaffs_obj, siblings);
12505 + * yaffs_remove_obj_callback() is called when an object is unlinked.
12506 + * We check open search contexts and advance any which are currently
12507 + * on the object being iterated.
12508 + */
12509 +static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
12512 + struct list_head *i;
12513 + struct yaffs_search_context *sc;
12514 + struct list_head *search_contexts =
12515 + &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
12517 + /* Iterate through the directory search contexts.
12518 + * If any are currently on the object being removed, then advance
12519 + * the search context to the next object to prevent a hanging pointer.
12520 + */
12521 + list_for_each(i, search_contexts) {
12522 + sc = list_entry(i, struct yaffs_search_context, others);
12523 + if (sc->next_return == obj)
12524 + yaffs_search_advance(sc);
12530 +/*-----------------------------------------------------------------*/
12532 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
12533 +static int yaffs_readdir(struct file *file, struct dir_context *ctx)
12535 + struct yaffs_obj *obj;
12536 + struct yaffs_dev *dev;
12537 + struct yaffs_search_context *sc;
12538 + struct inode *inode = file->f_dentry->d_inode;
12539 + unsigned long offset, curoffs;
12540 + struct yaffs_obj *l;
12541 + int ret_val = 0;
12543 + char name[YAFFS_MAX_NAME_LENGTH + 1];
12545 + obj = yaffs_dentry_to_obj(file->f_dentry);
12546 + dev = obj->my_dev;
12548 + yaffs_gross_lock(dev);
12550 + yaffs_dev_to_lc(dev)->readdir_process = current;
12552 + offset = ctx->pos;
12554 + sc = yaffs_new_search(obj);
12555 + if (!sc) {
12556 + ret_val = -ENOMEM;
12557 + goto out;
12560 + yaffs_trace(YAFFS_TRACE_OS,
12561 + "yaffs_readdir: starting at %d", (int)offset);
12563 + if (offset == 0) {
12564 + yaffs_trace(YAFFS_TRACE_OS,
12565 + "yaffs_readdir: entry . ino %d",
12566 + (int)inode->i_ino);
12567 + yaffs_gross_unlock(dev);
12568 + if (!dir_emit_dot(file, ctx)) {
12569 + yaffs_gross_lock(dev);
12570 + goto out;
12572 + yaffs_gross_lock(dev);
12573 + offset++;
12574 + ctx->pos++;
12576 + if (offset == 1) {
12577 + yaffs_trace(YAFFS_TRACE_OS,
12578 + "yaffs_readdir: entry .. ino %d",
12579 + (int)file->f_dentry->d_parent->d_inode->i_ino);
12580 + yaffs_gross_unlock(dev);
12581 + if (!dir_emit_dotdot(file, ctx)) {
12582 + yaffs_gross_lock(dev);
12583 + goto out;
12585 + yaffs_gross_lock(dev);
12586 + offset++;
12587 + ctx->pos++;
12590 + curoffs = 1;
12592 + /* If the directory has changed since the open or last call to
12593 + readdir, rewind to after the 2 canned entries. */
12594 + if (file->f_version != inode->i_version) {
12595 + offset = 2;
12596 + ctx->pos = offset;
12597 + file->f_version = inode->i_version;
12600 + while (sc->next_return) {
12601 + curoffs++;
12602 + l = sc->next_return;
12603 + if (curoffs >= offset) {
12604 + int this_inode = yaffs_get_obj_inode(l);
12605 + int this_type = yaffs_get_obj_type(l);
12607 + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
12608 + yaffs_trace(YAFFS_TRACE_OS,
12609 + "yaffs_readdir: %s inode %d",
12610 + name, yaffs_get_obj_inode(l));
12612 + yaffs_gross_unlock(dev);
12614 + if (!dir_emit(ctx, name, strlen(name),
12615 + this_inode, this_type) < 0) {
12616 + yaffs_gross_lock(dev);
12617 + goto out;
12620 + yaffs_gross_lock(dev);
12622 + offset++;
12623 + ctx->pos++;
12625 + yaffs_search_advance(sc);
12628 +out:
12629 + yaffs_search_end(sc);
12630 + yaffs_dev_to_lc(dev)->readdir_process = NULL;
12631 + yaffs_gross_unlock(dev);
12633 + return ret_val;
12635 +#else
12636 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
12638 + struct yaffs_obj *obj;
12639 + struct yaffs_dev *dev;
12640 + struct yaffs_search_context *sc;
12641 + struct inode *inode = f->f_dentry->d_inode;
12642 + unsigned long offset, curoffs;
12643 + struct yaffs_obj *l;
12644 + int ret_val = 0;
12646 + char name[YAFFS_MAX_NAME_LENGTH + 1];
12648 + obj = yaffs_dentry_to_obj(f->f_dentry);
12649 + dev = obj->my_dev;
12651 + yaffs_gross_lock(dev);
12653 + yaffs_dev_to_lc(dev)->readdir_process = current;
12655 + offset = f->f_pos;
12657 + sc = yaffs_new_search(obj);
12658 + if (!sc) {
12659 + ret_val = -ENOMEM;
12660 + goto out;
12663 + yaffs_trace(YAFFS_TRACE_OS,
12664 + "yaffs_readdir: starting at %d", (int)offset);
12666 + if (offset == 0) {
12667 + yaffs_trace(YAFFS_TRACE_OS,
12668 + "yaffs_readdir: entry . ino %d",
12669 + (int)inode->i_ino);
12670 + yaffs_gross_unlock(dev);
12671 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
12672 + yaffs_gross_lock(dev);
12673 + goto out;
12675 + yaffs_gross_lock(dev);
12676 + offset++;
12677 + f->f_pos++;
12679 + if (offset == 1) {
12680 + yaffs_trace(YAFFS_TRACE_OS,
12681 + "yaffs_readdir: entry .. ino %d",
12682 + (int)f->f_dentry->d_parent->d_inode->i_ino);
12683 + yaffs_gross_unlock(dev);
12684 + if (filldir(dirent, "..", 2, offset,
12685 + f->f_dentry->d_parent->d_inode->i_ino,
12686 + DT_DIR) < 0) {
12687 + yaffs_gross_lock(dev);
12688 + goto out;
12690 + yaffs_gross_lock(dev);
12691 + offset++;
12692 + f->f_pos++;
12695 + curoffs = 1;
12697 + /* If the directory has changed since the open or last call to
12698 + readdir, rewind to after the 2 canned entries. */
12699 + if (f->f_version != inode->i_version) {
12700 + offset = 2;
12701 + f->f_pos = offset;
12702 + f->f_version = inode->i_version;
12705 + while (sc->next_return) {
12706 + curoffs++;
12707 + l = sc->next_return;
12708 + if (curoffs >= offset) {
12709 + int this_inode = yaffs_get_obj_inode(l);
12710 + int this_type = yaffs_get_obj_type(l);
12712 + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
12713 + yaffs_trace(YAFFS_TRACE_OS,
12714 + "yaffs_readdir: %s inode %d",
12715 + name, yaffs_get_obj_inode(l));
12717 + yaffs_gross_unlock(dev);
12719 + if (filldir(dirent,
12720 + name,
12721 + strlen(name),
12722 + offset, this_inode, this_type) < 0) {
12723 + yaffs_gross_lock(dev);
12724 + goto out;
12727 + yaffs_gross_lock(dev);
12729 + offset++;
12730 + f->f_pos++;
12732 + yaffs_search_advance(sc);
12735 +out:
12736 + yaffs_search_end(sc);
12737 + yaffs_dev_to_lc(dev)->readdir_process = NULL;
12738 + yaffs_gross_unlock(dev);
12740 + return ret_val;
12742 +#endif
12744 +static const struct file_operations yaffs_dir_operations = {
12745 + .read = generic_read_dir,
12746 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
12747 + .iterate = yaffs_readdir,
12748 +#else
12749 + .readdir = yaffs_readdir,
12750 +#endif
12751 + .fsync = yaffs_sync_object,
12752 + .llseek = generic_file_llseek,
12755 +static void yaffs_fill_inode_from_obj(struct inode *inode,
12756 + struct yaffs_obj *obj)
12758 + if (inode && obj) {
12760 + /* Check mode against the variant type and attempt to repair if broken. */
12761 + u32 mode = obj->yst_mode;
12762 + switch (obj->variant_type) {
12763 + case YAFFS_OBJECT_TYPE_FILE:
12764 + if (!S_ISREG(mode)) {
12765 + obj->yst_mode &= ~S_IFMT;
12766 + obj->yst_mode |= S_IFREG;
12769 + break;
12770 + case YAFFS_OBJECT_TYPE_SYMLINK:
12771 + if (!S_ISLNK(mode)) {
12772 + obj->yst_mode &= ~S_IFMT;
12773 + obj->yst_mode |= S_IFLNK;
12776 + break;
12777 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12778 + if (!S_ISDIR(mode)) {
12779 + obj->yst_mode &= ~S_IFMT;
12780 + obj->yst_mode |= S_IFDIR;
12783 + break;
12784 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12785 + case YAFFS_OBJECT_TYPE_HARDLINK:
12786 + case YAFFS_OBJECT_TYPE_SPECIAL:
12787 + default:
12788 + /* TODO? */
12789 + break;
12792 + inode->i_flags |= S_NOATIME;
12794 + inode->i_ino = obj->obj_id;
12795 + inode->i_mode = obj->yst_mode;
12796 + i_uid_write(inode, obj->yst_uid);
12797 + i_gid_write(inode, obj->yst_gid);
12798 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
12799 + inode->i_blksize = inode->i_sb->s_blocksize;
12800 +#endif
12801 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12803 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
12804 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
12805 + inode->i_atime.tv_nsec = 0;
12806 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
12807 + inode->i_mtime.tv_nsec = 0;
12808 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
12809 + inode->i_ctime.tv_nsec = 0;
12810 +#else
12811 + inode->i_rdev = obj->yst_rdev;
12812 + inode->i_atime = obj->yst_atime;
12813 + inode->i_mtime = obj->yst_mtime;
12814 + inode->i_ctime = obj->yst_ctime;
12815 +#endif
12816 + inode->i_size = yaffs_get_obj_length(obj);
12817 + inode->i_blocks = (inode->i_size + 511) >> 9;
12819 + set_nlink(inode, yaffs_get_obj_link_count(obj));
12821 + yaffs_trace(YAFFS_TRACE_OS,
12822 + "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
12823 + inode->i_mode, i_uid_read(inode), i_gid_read(inode),
12824 + inode->i_size, atomic_read(&inode->i_count));
12826 + switch (obj->yst_mode & S_IFMT) {
12827 + default: /* fifo, device or socket */
12828 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12829 + init_special_inode(inode, obj->yst_mode,
12830 + old_decode_dev(obj->yst_rdev));
12831 +#else
12832 + init_special_inode(inode, obj->yst_mode,
12833 + (dev_t) (obj->yst_rdev));
12834 +#endif
12835 + break;
12836 + case S_IFREG: /* file */
12837 + inode->i_op = &yaffs_file_inode_operations;
12838 + inode->i_fop = &yaffs_file_operations;
12839 + inode->i_mapping->a_ops =
12840 + &yaffs_file_address_operations;
12841 + break;
12842 + case S_IFDIR: /* directory */
12843 + inode->i_op = &yaffs_dir_inode_operations;
12844 + inode->i_fop = &yaffs_dir_operations;
12845 + break;
12846 + case S_IFLNK: /* symlink */
12847 + inode->i_op = &yaffs_symlink_inode_operations;
12848 + break;
12851 + yaffs_inode_to_obj_lv(inode) = obj;
12853 + obj->my_inode = inode;
12855 + } else {
12856 + yaffs_trace(YAFFS_TRACE_OS,
12857 + "yaffs_fill_inode invalid parameters");
12865 + * yaffs background thread functions .
12866 + * yaffs_bg_thread_fn() the thread function
12867 + * yaffs_bg_start() launches the background thread.
12868 + * yaffs_bg_stop() cleans up the background thread.
12870 + * NB:
12871 + * The thread should only run after the yaffs is initialised
12872 + * The thread should be stopped before yaffs is unmounted.
12873 + * The thread should not do any writing while the fs is in read only.
12874 + */
12876 +static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
12878 + unsigned erased_chunks =
12879 + dev->n_erased_blocks * dev->param.chunks_per_block;
12880 + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
12881 + unsigned scattered = 0; /* Free chunks not in an erased block */
12883 + if (erased_chunks < dev->n_free_chunks)
12884 + scattered = (dev->n_free_chunks - erased_chunks);
12886 + if (!context->bg_running)
12887 + return 0;
12888 + else if (scattered < (dev->param.chunks_per_block * 2))
12889 + return 0;
12890 + else if (erased_chunks > dev->n_free_chunks / 2)
12891 + return 0;
12892 + else if (erased_chunks > dev->n_free_chunks / 4)
12893 + return 1;
12894 + else
12895 + return 2;
12898 +#ifdef YAFFS_COMPILE_BACKGROUND
12900 +void yaffs_background_waker(unsigned long data)
12902 + wake_up_process((struct task_struct *)data);
12905 +static int yaffs_bg_thread_fn(void *data)
12907 + struct yaffs_dev *dev = (struct yaffs_dev *)data;
12908 + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
12909 + unsigned long now = jiffies;
12910 + unsigned long next_dir_update = now;
12911 + unsigned long next_gc = now;
12912 + unsigned long expires;
12913 + unsigned int urgency;
12915 + int gc_result;
12916 + struct timer_list timer;
12918 + yaffs_trace(YAFFS_TRACE_BACKGROUND,
12919 + "yaffs_background starting for dev %p", (void *)dev);
12921 +#ifdef YAFFS_COMPILE_FREEZER
12922 + set_freezable();
12923 +#endif
12924 + while (context->bg_running) {
12925 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
12927 + if (kthread_should_stop())
12928 + break;
12930 +#ifdef YAFFS_COMPILE_FREEZER
12931 + if (try_to_freeze())
12932 + continue;
12933 +#endif
12934 + yaffs_gross_lock(dev);
12936 + now = jiffies;
12938 + if (time_after(now, next_dir_update) && yaffs_bg_enable) {
12939 + yaffs_update_dirty_dirs(dev);
12940 + next_dir_update = now + HZ;
12943 + if (time_after(now, next_gc) && yaffs_bg_enable) {
12944 + if (!dev->is_checkpointed) {
12945 + urgency = yaffs_bg_gc_urgency(dev);
12946 + gc_result = yaffs_bg_gc(dev, urgency);
12947 + if (urgency > 1)
12948 + next_gc = now + HZ / 20 + 1;
12949 + else if (urgency > 0)
12950 + next_gc = now + HZ / 10 + 1;
12951 + else
12952 + next_gc = now + HZ * 2;
12953 + } else {
12954 + /*
12955 + * gc not running so set to next_dir_update
12956 + * to cut down on wake ups
12957 + */
12958 + next_gc = next_dir_update;
12961 + yaffs_gross_unlock(dev);
12962 +#if 1
12963 + expires = next_dir_update;
12964 + if (time_before(next_gc, expires))
12965 + expires = next_gc;
12966 + if (time_before(expires, now))
12967 + expires = now + HZ;
12969 + Y_INIT_TIMER(&timer);
12970 + timer.expires = expires + 1;
12971 + timer.data = (unsigned long)current;
12972 + timer.function = yaffs_background_waker;
12974 + set_current_state(TASK_INTERRUPTIBLE);
12975 + add_timer(&timer);
12976 + schedule();
12977 + del_timer_sync(&timer);
12978 +#else
12979 + msleep(10);
12980 +#endif
12983 + return 0;
12986 +static int yaffs_bg_start(struct yaffs_dev *dev)
12988 + int retval = 0;
12989 + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
12991 + if (dev->read_only)
12992 + return -1;
12994 + context->bg_running = 1;
12996 + context->bg_thread = kthread_run(yaffs_bg_thread_fn,
12997 + (void *)dev, "yaffs-bg-%d",
12998 + context->mount_id);
13000 + if (IS_ERR(context->bg_thread)) {
13001 + retval = PTR_ERR(context->bg_thread);
13002 + context->bg_thread = NULL;
13003 + context->bg_running = 0;
13005 + return retval;
13008 +static void yaffs_bg_stop(struct yaffs_dev *dev)
13010 + struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
13012 + ctxt->bg_running = 0;
13014 + if (ctxt->bg_thread) {
13015 + kthread_stop(ctxt->bg_thread);
13016 + ctxt->bg_thread = NULL;
13019 +#else
13020 +static int yaffs_bg_thread_fn(void *data)
13022 + return 0;
13025 +static int yaffs_bg_start(struct yaffs_dev *dev)
13027 + return 0;
13030 +static void yaffs_bg_stop(struct yaffs_dev *dev)
13033 +#endif
13036 +static void yaffs_flush_inodes(struct super_block *sb)
13038 + struct inode *iptr;
13039 + struct yaffs_obj *obj;
13041 + list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
13042 + obj = yaffs_inode_to_obj(iptr);
13043 + if (obj) {
13044 + yaffs_trace(YAFFS_TRACE_OS,
13045 + "flushing obj %d",
13046 + obj->obj_id);
13047 + yaffs_flush_file(obj, 1, 0);
13052 +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
13054 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13055 + if (!dev)
13056 + return;
13058 + yaffs_flush_inodes(sb);
13059 + yaffs_update_dirty_dirs(dev);
13060 + yaffs_flush_whole_cache(dev);
13061 + if (do_checkpoint)
13062 + yaffs_checkpoint_save(dev);
13065 +static LIST_HEAD(yaffs_context_list);
13066 +struct mutex yaffs_context_lock;
13068 +static void yaffs_put_super(struct super_block *sb)
13070 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13071 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
13073 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
13074 + "yaffs_put_super");
13076 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
13077 + "Shutting down yaffs background thread");
13078 + yaffs_bg_stop(dev);
13079 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
13080 + "yaffs background thread shut down");
13082 + yaffs_gross_lock(dev);
13084 + yaffs_flush_super(sb, 1);
13086 + yaffs_deinitialise(dev);
13088 + yaffs_gross_unlock(dev);
13090 + mutex_lock(&yaffs_context_lock);
13091 + list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
13092 + mutex_unlock(&yaffs_context_lock);
13094 + if (yaffs_dev_to_lc(dev)->spare_buffer) {
13095 + kfree(yaffs_dev_to_lc(dev)->spare_buffer);
13096 + yaffs_dev_to_lc(dev)->spare_buffer = NULL;
13099 + kfree(dev);
13101 + yaffs_put_mtd_device(mtd);
13103 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
13104 + "yaffs_put_super done");
13108 +static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
13110 + return yaffs_gc_control;
13114 +#ifdef YAFFS_COMPILE_EXPORTFS
13116 +static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
13117 + uint32_t generation)
13119 + return Y_IGET(sb, ino);
13122 +static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
13123 + struct fid *fid, int fh_len,
13124 + int fh_type)
13126 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
13127 + yaffs2_nfs_get_inode);
13130 +static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
13131 + struct fid *fid, int fh_len,
13132 + int fh_type)
13134 + return generic_fh_to_parent(sb, fid, fh_len, fh_type,
13135 + yaffs2_nfs_get_inode);
13138 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
13141 + struct super_block *sb = dentry->d_inode->i_sb;
13142 + struct dentry *parent = ERR_PTR(-ENOENT);
13143 + struct inode *inode;
13144 + unsigned long parent_ino;
13145 + struct yaffs_obj *d_obj;
13146 + struct yaffs_obj *parent_obj;
13148 + d_obj = yaffs_inode_to_obj(dentry->d_inode);
13150 + if (d_obj) {
13151 + parent_obj = d_obj->parent;
13152 + if (parent_obj) {
13153 + parent_ino = yaffs_get_obj_inode(parent_obj);
13154 + inode = Y_IGET(sb, parent_ino);
13156 + if (IS_ERR(inode)) {
13157 + parent = ERR_CAST(inode);
13158 + } else {
13159 + parent = d_obtain_alias(inode);
13160 + if (!IS_ERR(parent)) {
13161 + parent = ERR_PTR(-ENOMEM);
13162 + iput(inode);
13168 + return parent;
13171 +/* Just declare a zero structure as a NULL value implies
13172 + * using the default functions of exportfs.
13173 + */
13175 +static struct export_operations yaffs_export_ops = {
13176 + .fh_to_dentry = yaffs2_fh_to_dentry,
13177 + .fh_to_parent = yaffs2_fh_to_parent,
13178 + .get_parent = yaffs2_get_parent,
13181 +#endif
13183 +static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
13185 + /* Clear the association between the inode and
13186 + * the struct yaffs_obj.
13187 + */
13188 + obj->my_inode = NULL;
13189 + yaffs_inode_to_obj_lv(inode) = NULL;
13191 + /* If the object freeing was deferred, then the real
13192 + * free happens now.
13193 + * This should fix the inode inconsistency problem.
13194 + */
13195 + yaffs_handle_defered_free(obj);
13198 +#ifdef YAFFS_HAS_EVICT_INODE
13199 +/* yaffs_evict_inode combines into one operation what was previously done in
13200 + * yaffs_clear_inode() and yaffs_delete_inode()
13202 + */
13203 +static void yaffs_evict_inode(struct inode *inode)
13205 + struct yaffs_obj *obj;
13206 + struct yaffs_dev *dev;
13207 + int deleteme = 0;
13209 + obj = yaffs_inode_to_obj(inode);
13211 + yaffs_trace(YAFFS_TRACE_OS,
13212 + "yaffs_evict_inode: ino %d, count %d %s",
13213 + (int)inode->i_ino, atomic_read(&inode->i_count),
13214 + obj ? "object exists" : "null object");
13216 + if (!inode->i_nlink && !is_bad_inode(inode))
13217 + deleteme = 1;
13218 + truncate_inode_pages(&inode->i_data, 0);
13219 + Y_CLEAR_INODE(inode);
13221 + if (deleteme && obj) {
13222 + dev = obj->my_dev;
13223 + yaffs_gross_lock(dev);
13224 + yaffs_del_obj(obj);
13225 + yaffs_gross_unlock(dev);
13227 + if (obj) {
13228 + dev = obj->my_dev;
13229 + yaffs_gross_lock(dev);
13230 + yaffs_unstitch_obj(inode, obj);
13231 + yaffs_gross_unlock(dev);
13234 +#else
13236 +/* clear is called to tell the fs to release any per-inode data it holds.
13237 + * The object might still exist on disk and is just being thrown out of the cache
13238 + * or else the object has actually been deleted and we're being called via
13239 + * the chain
13240 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
13241 + */
13243 +static void yaffs_clear_inode(struct inode *inode)
13245 + struct yaffs_obj *obj;
13246 + struct yaffs_dev *dev;
13248 + obj = yaffs_inode_to_obj(inode);
13250 + yaffs_trace(YAFFS_TRACE_OS,
13251 + "yaffs_clear_inode: ino %d, count %d %s",
13252 + (int)inode->i_ino, atomic_read(&inode->i_count),
13253 + obj ? "object exists" : "null object");
13255 + if (obj) {
13256 + dev = obj->my_dev;
13257 + yaffs_gross_lock(dev);
13258 + yaffs_unstitch_obj(inode, obj);
13259 + yaffs_gross_unlock(dev);
13264 +/* delete is called when the link count is zero and the inode
13265 + * is put (ie. nobody wants to know about it anymore, time to
13266 + * delete the file).
13267 + * NB Must call clear_inode()
13268 + */
13269 +static void yaffs_delete_inode(struct inode *inode)
13271 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
13272 + struct yaffs_dev *dev;
13274 + yaffs_trace(YAFFS_TRACE_OS,
13275 + "yaffs_delete_inode: ino %d, count %d %s",
13276 + (int)inode->i_ino, atomic_read(&inode->i_count),
13277 + obj ? "object exists" : "null object");
13279 + if (obj) {
13280 + dev = obj->my_dev;
13281 + yaffs_gross_lock(dev);
13282 + yaffs_del_obj(obj);
13283 + yaffs_gross_unlock(dev);
13285 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
13286 + truncate_inode_pages(&inode->i_data, 0);
13287 +#endif
13288 + clear_inode(inode);
13290 +#endif
13295 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13296 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
13298 + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
13299 + struct super_block *sb = dentry->d_sb;
13300 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13301 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
13303 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13304 +#else
13305 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
13307 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13308 +#endif
13310 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
13312 + yaffs_gross_lock(dev);
13314 + buf->f_type = YAFFS_MAGIC;
13315 + buf->f_bsize = sb->s_blocksize;
13316 + buf->f_namelen = 255;
13318 + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
13319 + /* Do this if chunk size is not a power of 2 */
13321 + uint64_t bytes_in_dev;
13322 + uint64_t bytes_free;
13324 + bytes_in_dev =
13325 + ((uint64_t)
13326 + ((dev->param.end_block - dev->param.start_block +
13327 + 1))) * ((uint64_t) (dev->param.chunks_per_block *
13328 + dev->data_bytes_per_chunk));
13330 + do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
13331 + buf->f_blocks = bytes_in_dev;
13333 + bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
13334 + ((uint64_t) (dev->data_bytes_per_chunk));
13336 + do_div(bytes_free, sb->s_blocksize);
13338 + buf->f_bfree = bytes_free;
13340 + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
13342 + buf->f_blocks =
13343 + (dev->param.end_block - dev->param.start_block + 1) *
13344 + dev->param.chunks_per_block /
13345 + (sb->s_blocksize / dev->data_bytes_per_chunk);
13346 + buf->f_bfree =
13347 + yaffs_get_n_free_chunks(dev) /
13348 + (sb->s_blocksize / dev->data_bytes_per_chunk);
13349 + } else {
13350 + buf->f_blocks =
13351 + (dev->param.end_block - dev->param.start_block + 1) *
13352 + dev->param.chunks_per_block *
13353 + (dev->data_bytes_per_chunk / sb->s_blocksize);
13355 + buf->f_bfree =
13356 + yaffs_get_n_free_chunks(dev) *
13357 + (dev->data_bytes_per_chunk / sb->s_blocksize);
13360 + buf->f_files = 0;
13361 + buf->f_ffree = 0;
13362 + buf->f_bavail = buf->f_bfree;
13364 + yaffs_gross_unlock(dev);
13365 + return 0;
13370 +static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
13373 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13374 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
13375 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
13376 + int do_checkpoint;
13377 + int dirty = yaffs_check_super_dirty(dev);
13379 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
13380 + "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
13381 + gc_urgent,
13382 + dirty ? "dirty" : "clean",
13383 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
13384 + oneshot_checkpoint ? " one-shot" : "");
13386 + yaffs_gross_lock(dev);
13387 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
13388 + oneshot_checkpoint) && !dev->is_checkpointed;
13390 + if (dirty || do_checkpoint) {
13391 + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
13392 + yaffs_clear_super_dirty(dev);
13393 + if (oneshot_checkpoint)
13394 + yaffs_auto_checkpoint &= ~4;
13396 + yaffs_gross_unlock(dev);
13398 + return 0;
13402 +#ifdef YAFFS_HAS_WRITE_SUPER
13403 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13404 +static void yaffs_write_super(struct super_block *sb)
13405 +#else
13406 +static int yaffs_write_super(struct super_block *sb)
13407 +#endif
13409 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
13411 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
13412 + "yaffs_write_super %s",
13413 + request_checkpoint ? " checkpt" : "");
13415 + yaffs_do_sync_fs(sb, request_checkpoint);
13417 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
13418 + return 0;
13419 +#endif
13421 +#endif
13423 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13424 +static int yaffs_sync_fs(struct super_block *sb, int wait)
13425 +#else
13426 +static int yaffs_sync_fs(struct super_block *sb)
13427 +#endif
13429 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
13431 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
13432 + "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
13434 + yaffs_do_sync_fs(sb, request_checkpoint);
13436 + return 0;
13441 +static const struct super_operations yaffs_super_ops = {
13442 + .statfs = yaffs_statfs,
13444 +#ifndef YAFFS_USE_OWN_IGET
13445 + .read_inode = yaffs_read_inode,
13446 +#endif
13447 +#ifdef YAFFS_HAS_PUT_INODE
13448 + .put_inode = yaffs_put_inode,
13449 +#endif
13450 + .put_super = yaffs_put_super,
13451 +#ifdef YAFFS_HAS_EVICT_INODE
13452 + .evict_inode = yaffs_evict_inode,
13453 +#else
13454 + .delete_inode = yaffs_delete_inode,
13455 + .clear_inode = yaffs_clear_inode,
13456 +#endif
13457 + .sync_fs = yaffs_sync_fs,
13458 +#ifdef YAFFS_HAS_WRITE_SUPER
13459 + .write_super = yaffs_write_super,
13460 +#endif
13463 +struct yaffs_options {
13464 + int inband_tags;
13465 + int skip_checkpoint_read;
13466 + int skip_checkpoint_write;
13467 + int no_cache;
13468 + int tags_ecc_on;
13469 + int tags_ecc_overridden;
13470 + int lazy_loading_enabled;
13471 + int lazy_loading_overridden;
13472 + int empty_lost_and_found;
13473 + int empty_lost_and_found_overridden;
13474 + int disable_summary;
13477 +#define MAX_OPT_LEN 30
13478 +static int yaffs_parse_options(struct yaffs_options *options,
13479 + const char *options_str)
13481 + char cur_opt[MAX_OPT_LEN + 1];
13482 + int p;
13483 + int error = 0;
13485 + /* Parse through the options which is a comma seperated list */
13487 + while (options_str && *options_str && !error) {
13488 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
13489 + p = 0;
13491 + while (*options_str == ',')
13492 + options_str++;
13494 + while (*options_str && *options_str != ',') {
13495 + if (p < MAX_OPT_LEN) {
13496 + cur_opt[p] = *options_str;
13497 + p++;
13499 + options_str++;
13502 + if (!strcmp(cur_opt, "inband-tags")) {
13503 + options->inband_tags = 1;
13504 + } else if (!strcmp(cur_opt, "tags-ecc-off")) {
13505 + options->tags_ecc_on = 0;
13506 + options->tags_ecc_overridden = 1;
13507 + } else if (!strcmp(cur_opt, "tags-ecc-on")) {
13508 + options->tags_ecc_on = 1;
13509 + options->tags_ecc_overridden = 1;
13510 + } else if (!strcmp(cur_opt, "lazy-loading-off")) {
13511 + options->lazy_loading_enabled = 0;
13512 + options->lazy_loading_overridden = 1;
13513 + } else if (!strcmp(cur_opt, "lazy-loading-on")) {
13514 + options->lazy_loading_enabled = 1;
13515 + options->lazy_loading_overridden = 1;
13516 + } else if (!strcmp(cur_opt, "disable-summary")) {
13517 + options->disable_summary = 1;
13518 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
13519 + options->empty_lost_and_found = 0;
13520 + options->empty_lost_and_found_overridden = 1;
13521 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
13522 + options->empty_lost_and_found = 1;
13523 + options->empty_lost_and_found_overridden = 1;
13524 + } else if (!strcmp(cur_opt, "no-cache")) {
13525 + options->no_cache = 1;
13526 + } else if (!strcmp(cur_opt, "no-checkpoint-read")) {
13527 + options->skip_checkpoint_read = 1;
13528 + } else if (!strcmp(cur_opt, "no-checkpoint-write")) {
13529 + options->skip_checkpoint_write = 1;
13530 + } else if (!strcmp(cur_opt, "no-checkpoint")) {
13531 + options->skip_checkpoint_read = 1;
13532 + options->skip_checkpoint_write = 1;
13533 + } else {
13534 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
13535 + cur_opt);
13536 + error = 1;
13540 + return error;
13544 +static struct dentry *yaffs_make_root(struct inode *inode)
13546 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
13547 + struct dentry *root = d_alloc_root(inode);
13549 + if (!root)
13550 + iput(inode);
13552 + return root;
13553 +#else
13554 + return d_make_root(inode);
13555 +#endif
13561 +static struct super_block *yaffs_internal_read_super(int yaffs_version,
13562 + struct super_block *sb,
13563 + void *data, int silent)
13565 + int n_blocks;
13566 + struct inode *inode = NULL;
13567 + struct dentry *root;
13568 + struct yaffs_dev *dev = 0;
13569 + char devname_buf[BDEVNAME_SIZE + 1];
13570 + struct mtd_info *mtd;
13571 + int err;
13572 + char *data_str = (char *)data;
13573 + struct yaffs_linux_context *context = NULL;
13574 + struct yaffs_param *param;
13576 + int read_only = 0;
13577 + int inband_tags = 0;
13579 + struct yaffs_options options;
13581 + unsigned mount_id;
13582 + int found;
13583 + struct yaffs_linux_context *context_iterator;
13584 + struct list_head *l;
13586 + if (!sb) {
13587 + printk(KERN_INFO "yaffs: sb is NULL\n");
13588 + return NULL;
13591 + sb->s_magic = YAFFS_MAGIC;
13592 + sb->s_op = &yaffs_super_ops;
13593 + sb->s_flags |= MS_NOATIME;
13595 + read_only = ((sb->s_flags & MS_RDONLY) != 0);
13597 +#ifdef YAFFS_COMPILE_EXPORTFS
13598 + sb->s_export_op = &yaffs_export_ops;
13599 +#endif
13601 + if (!sb->s_dev)
13602 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
13603 + else if (!yaffs_devname(sb, devname_buf))
13604 + printk(KERN_INFO "yaffs: devname is NULL\n");
13605 + else
13606 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
13607 + sb->s_dev,
13608 + yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
13610 + if (!data_str)
13611 + data_str = "";
13613 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
13615 + memset(&options, 0, sizeof(options));
13617 + if (yaffs_parse_options(&options, data_str)) {
13618 + /* Option parsing failed */
13619 + return NULL;
13622 + sb->s_blocksize = PAGE_CACHE_SIZE;
13623 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
13625 + yaffs_trace(YAFFS_TRACE_OS,
13626 + "yaffs_read_super: Using yaffs%d", yaffs_version);
13627 + yaffs_trace(YAFFS_TRACE_OS,
13628 + "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
13630 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13631 + "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
13632 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
13633 + yaffs_devname(sb, devname_buf));
13635 + /* Get the device */
13636 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
13637 + if (IS_ERR(mtd)) {
13638 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13639 + "yaffs: MTD device %u either not valid or unavailable",
13640 + MINOR(sb->s_dev));
13641 + return NULL;
13644 + if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
13645 + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
13646 + yaffs_version = 2;
13649 + /* Added NCB 26/5/2006 for completeness */
13650 + if (yaffs_version == 2 && !options.inband_tags
13651 + && WRITE_SIZE(mtd) == 512) {
13652 + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
13653 + yaffs_version = 1;
13656 + if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
13657 + options.inband_tags)
13658 + inband_tags = 1;
13660 + if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
13661 + return NULL;
13663 + /* OK, so if we got here, we have an MTD that's NAND and looks
13664 + * like it has the right capabilities
13665 + * Set the struct yaffs_dev up for mtd
13666 + */
13668 + if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
13669 + read_only = 1;
13670 + printk(KERN_INFO
13671 + "yaffs: mtd is read only, setting superblock read only\n"
13672 + );
13673 + sb->s_flags |= MS_RDONLY;
13676 + dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
13677 + context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
13679 + if (!dev || !context) {
13680 + kfree(dev);
13681 + kfree(context);
13682 + dev = NULL;
13683 + context = NULL;
13685 + /* Deep shit could not allocate device structure */
13686 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13687 + "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
13688 + );
13689 + return NULL;
13691 + memset(dev, 0, sizeof(struct yaffs_dev));
13692 + param = &(dev->param);
13694 + memset(context, 0, sizeof(struct yaffs_linux_context));
13695 + dev->os_context = context;
13696 + INIT_LIST_HEAD(&(context->context_list));
13697 + context->dev = dev;
13698 + context->super = sb;
13700 + dev->read_only = read_only;
13702 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13703 + sb->s_fs_info = dev;
13704 +#else
13705 + sb->u.generic_sbp = dev;
13706 +#endif
13709 + dev->driver_context = mtd;
13710 + param->name = mtd->name;
13712 + /* Set up the memory size parameters.... */
13715 + param->n_reserved_blocks = 5;
13716 + param->n_caches = (options.no_cache) ? 0 : 10;
13717 + param->inband_tags = inband_tags;
13719 + param->enable_xattr = 1;
13720 + if (options.lazy_loading_overridden)
13721 + param->disable_lazy_load = !options.lazy_loading_enabled;
13723 + param->defered_dir_update = 1;
13725 + if (options.tags_ecc_overridden)
13726 + param->no_tags_ecc = !options.tags_ecc_on;
13728 + param->empty_lost_n_found = 1;
13729 + param->refresh_period = 500;
13730 + param->disable_summary = options.disable_summary;
13733 +#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
13734 + param->disable_bad_block_marking = 1;
13735 +#endif
13736 + if (options.empty_lost_and_found_overridden)
13737 + param->empty_lost_n_found = options.empty_lost_and_found;
13739 + /* ... and the functions. */
13740 + if (yaffs_version == 2) {
13741 + param->is_yaffs2 = 1;
13742 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13743 + param->total_bytes_per_chunk = mtd->writesize;
13744 + param->chunks_per_block = mtd->erasesize / mtd->writesize;
13745 +#else
13746 + param->total_bytes_per_chunk = mtd->oobblock;
13747 + param->chunks_per_block = mtd->erasesize / mtd->oobblock;
13748 +#endif
13749 + n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
13751 + param->start_block = 0;
13752 + param->end_block = n_blocks - 1;
13753 + } else {
13754 + param->is_yaffs2 = 0;
13755 + n_blocks = YCALCBLOCKS(mtd->size,
13756 + YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
13758 + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
13759 + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
13762 + param->start_block = 0;
13763 + param->end_block = n_blocks - 1;
13765 + yaffs_mtd_drv_install(dev);
13767 + param->sb_dirty_fn = yaffs_set_super_dirty;
13768 + param->gc_control_fn = yaffs_gc_control_callback;
13770 + yaffs_dev_to_lc(dev)->super = sb;
13772 + param->use_nand_ecc = 1;
13774 + param->skip_checkpt_rd = options.skip_checkpoint_read;
13775 + param->skip_checkpt_wr = options.skip_checkpoint_write;
13777 + mutex_lock(&yaffs_context_lock);
13778 + /* Get a mount id */
13779 + found = 0;
13780 + for (mount_id = 0; !found; mount_id++) {
13781 + found = 1;
13782 + list_for_each(l, &yaffs_context_list) {
13783 + context_iterator =
13784 + list_entry(l, struct yaffs_linux_context,
13785 + context_list);
13786 + if (context_iterator->mount_id == mount_id)
13787 + found = 0;
13790 + context->mount_id = mount_id;
13792 + list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
13793 + &yaffs_context_list);
13794 + mutex_unlock(&yaffs_context_lock);
13796 + /* Directory search handling... */
13797 + INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
13798 + param->remove_obj_fn = yaffs_remove_obj_callback;
13800 + mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
13802 + yaffs_gross_lock(dev);
13804 + err = yaffs_guts_initialise(dev);
13806 + yaffs_trace(YAFFS_TRACE_OS,
13807 + "yaffs_read_super: guts initialised %s",
13808 + (err == YAFFS_OK) ? "OK" : "FAILED");
13810 + if (err == YAFFS_OK)
13811 + yaffs_bg_start(dev);
13813 + if (!context->bg_thread)
13814 + param->defered_dir_update = 0;
13816 + sb->s_maxbytes = yaffs_max_file_size(dev);
13818 + /* Release lock before yaffs_get_inode() */
13819 + yaffs_gross_unlock(dev);
13821 + /* Create root inode */
13822 + if (err == YAFFS_OK)
13823 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
13825 + if (!inode)
13826 + return NULL;
13828 + inode->i_op = &yaffs_dir_inode_operations;
13829 + inode->i_fop = &yaffs_dir_operations;
13831 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
13833 + root = yaffs_make_root(inode);
13835 + if (!root)
13836 + return NULL;
13838 + sb->s_root = root;
13839 + if(!dev->is_checkpointed)
13840 + yaffs_set_super_dirty(dev);
13842 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13843 + "yaffs_read_super: is_checkpointed %d",
13844 + dev->is_checkpointed);
13846 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
13847 + return sb;
13850 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13851 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
13852 + int silent)
13854 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
13857 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13858 +static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
13859 + const char *dev_name, void *data)
13861 + return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
13863 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13864 +static int yaffs_read_super(struct file_system_type *fs,
13865 + int flags, const char *dev_name,
13866 + void *data, struct vfsmount *mnt)
13869 + return get_sb_bdev(fs, flags, dev_name, data,
13870 + yaffs_internal_read_super_mtd, mnt);
13872 +#else
13873 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
13874 + int flags, const char *dev_name,
13875 + void *data)
13878 + return get_sb_bdev(fs, flags, dev_name, data,
13879 + yaffs_internal_read_super_mtd);
13881 +#endif
13883 +static struct file_system_type yaffs_fs_type = {
13884 + .owner = THIS_MODULE,
13885 + .name = "yaffs",
13886 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13887 + .mount = yaffs_mount,
13888 +#else
13889 + .get_sb = yaffs_read_super,
13890 +#endif
13891 + .kill_sb = kill_block_super,
13892 + .fs_flags = FS_REQUIRES_DEV,
13894 +#else
13895 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
13896 + int silent)
13898 + return yaffs_internal_read_super(1, sb, data, silent);
13901 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
13902 + FS_REQUIRES_DEV);
13903 +#endif
13906 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13907 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
13908 + int silent)
13910 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
13913 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13914 +static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
13915 + const char *dev_name, void *data)
13917 + return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
13919 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13920 +static int yaffs2_read_super(struct file_system_type *fs,
13921 + int flags, const char *dev_name, void *data,
13922 + struct vfsmount *mnt)
13924 + return get_sb_bdev(fs, flags, dev_name, data,
13925 + yaffs2_internal_read_super_mtd, mnt);
13927 +#else
13928 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
13929 + int flags, const char *dev_name,
13930 + void *data)
13933 + return get_sb_bdev(fs, flags, dev_name, data,
13934 + yaffs2_internal_read_super_mtd);
13936 +#endif
13938 +static struct file_system_type yaffs2_fs_type = {
13939 + .owner = THIS_MODULE,
13940 + .name = "yaffs2",
13941 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13942 + .mount = yaffs2_mount,
13943 +#else
13944 + .get_sb = yaffs2_read_super,
13945 +#endif
13946 + .kill_sb = kill_block_super,
13947 + .fs_flags = FS_REQUIRES_DEV,
13949 +#else
13950 +static struct super_block *yaffs2_read_super(struct super_block *sb,
13951 + void *data, int silent)
13953 + return yaffs_internal_read_super(2, sb, data, silent);
13956 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
13957 + FS_REQUIRES_DEV);
13958 +#endif
13961 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
13962 +static struct proc_dir_entry *my_proc_entry;
13964 +static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
13966 + struct yaffs_param *param = &dev->param;
13967 + int bs[10];
13969 + yaffs_count_blocks_by_state(dev,bs);
13971 + buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
13972 + buf += sprintf(buf, "end_block............ %d\n", param->end_block);
13973 + buf += sprintf(buf, "total_bytes_per_chunk %d\n",
13974 + param->total_bytes_per_chunk);
13975 + buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
13976 + buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
13977 + buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
13978 + buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
13979 + buf += sprintf(buf, "empty_lost_n_found... %d\n",
13980 + param->empty_lost_n_found);
13981 + buf += sprintf(buf, "disable_lazy_load.... %d\n",
13982 + param->disable_lazy_load);
13983 + buf += sprintf(buf, "disable_bad_block_mrk %d\n",
13984 + param->disable_bad_block_marking);
13985 + buf += sprintf(buf, "refresh_period....... %d\n",
13986 + param->refresh_period);
13987 + buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
13988 + buf += sprintf(buf, "n_reserved_blocks.... %d\n",
13989 + param->n_reserved_blocks);
13990 + buf += sprintf(buf, "always_check_erased.. %d\n",
13991 + param->always_check_erased);
13992 + buf += sprintf(buf, "\n");
13993 + buf += sprintf(buf, "block count by state\n");
13994 + buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
13995 + bs[0], bs[1], bs[2], bs[3], bs[4]);
13996 + buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
13997 + bs[5], bs[6], bs[7], bs[8], bs[9]);
13999 + return buf;
14002 +static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
14004 + buf += sprintf(buf, "max file size....... %lld\n",
14005 + (long long) yaffs_max_file_size(dev));
14006 + buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
14007 + dev->data_bytes_per_chunk);
14008 + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
14009 + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
14010 + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
14011 + buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
14012 + dev->blocks_in_checkpt);
14013 + buf += sprintf(buf, "\n");
14014 + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
14015 + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
14016 + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
14017 + buf += sprintf(buf, "\n");
14018 + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
14019 + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
14020 + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
14021 + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
14022 + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
14023 + buf += sprintf(buf, "passive_gc_count..... %u\n",
14024 + dev->passive_gc_count);
14025 + buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
14026 + dev->oldest_dirty_gc_count);
14027 + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
14028 + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
14029 + buf += sprintf(buf, "n_retried_writes..... %u\n",
14030 + dev->n_retried_writes);
14031 + buf += sprintf(buf, "n_retired_blocks..... %u\n",
14032 + dev->n_retired_blocks);
14033 + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
14034 + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
14035 + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
14036 + dev->n_tags_ecc_fixed);
14037 + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
14038 + dev->n_tags_ecc_unfixed);
14039 + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
14040 + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
14041 + buf += sprintf(buf, "n_unlinked_files..... %u\n",
14042 + dev->n_unlinked_files);
14043 + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
14044 + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
14045 + buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
14046 + buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
14048 + return buf;
14051 +static int yaffs_proc_read(char *page,
14052 + char **start,
14053 + off_t offset, int count, int *eof, void *data)
14055 + struct list_head *item;
14056 + char *buf = page;
14057 + int step = offset;
14058 + int n = 0;
14060 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
14061 + * We use 'offset' (*ppos) to indicate where we are in dev_list.
14062 + * This also assumes the user has posted a read buffer large
14063 + * enough to hold the complete output; but that's life in /proc.
14064 + */
14066 + *(int *)start = 1;
14068 + /* Print header first */
14069 + if (step == 0)
14070 + buf +=
14071 + sprintf(buf,
14072 + "Multi-version YAFFS built:" __DATE__ " " __TIME__
14073 + "\n");
14074 + else if (step == 1)
14075 + buf += sprintf(buf, "\n");
14076 + else {
14077 + step -= 2;
14079 + mutex_lock(&yaffs_context_lock);
14081 + /* Locate and print the Nth entry. Order N-squared but N is small. */
14082 + list_for_each(item, &yaffs_context_list) {
14083 + struct yaffs_linux_context *dc =
14084 + list_entry(item, struct yaffs_linux_context,
14085 + context_list);
14086 + struct yaffs_dev *dev = dc->dev;
14088 + if (n < (step & ~1)) {
14089 + n += 2;
14090 + continue;
14092 + if ((step & 1) == 0) {
14093 + buf +=
14094 + sprintf(buf, "\nDevice %d \"%s\"\n", n,
14095 + dev->param.name);
14096 + buf = yaffs_dump_dev_part0(buf, dev);
14097 + } else {
14098 + buf = yaffs_dump_dev_part1(buf, dev);
14101 + break;
14103 + mutex_unlock(&yaffs_context_lock);
14106 + return buf - page < count ? buf - page : count;
14109 +/**
14110 + * Set the verbosity of the warnings and error messages.
14112 + * Note that the names can only be a..z or _ with the current code.
14113 + */
14115 +static struct {
14116 + char *mask_name;
14117 + unsigned mask_bitfield;
14118 +} mask_flags[] = {
14119 + {"allocate", YAFFS_TRACE_ALLOCATE},
14120 + {"always", YAFFS_TRACE_ALWAYS},
14121 + {"background", YAFFS_TRACE_BACKGROUND},
14122 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
14123 + {"buffers", YAFFS_TRACE_BUFFERS},
14124 + {"bug", YAFFS_TRACE_BUG},
14125 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
14126 + {"deletion", YAFFS_TRACE_DELETION},
14127 + {"erase", YAFFS_TRACE_ERASE},
14128 + {"error", YAFFS_TRACE_ERROR},
14129 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
14130 + {"gc", YAFFS_TRACE_GC},
14131 + {"lock", YAFFS_TRACE_LOCK},
14132 + {"mtd", YAFFS_TRACE_MTD},
14133 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
14134 + {"os", YAFFS_TRACE_OS},
14135 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
14136 + {"scan", YAFFS_TRACE_SCAN},
14137 + {"mount", YAFFS_TRACE_MOUNT},
14138 + {"tracing", YAFFS_TRACE_TRACING},
14139 + {"sync", YAFFS_TRACE_SYNC},
14140 + {"write", YAFFS_TRACE_WRITE},
14141 + {"verify", YAFFS_TRACE_VERIFY},
14142 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
14143 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
14144 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
14145 + {"all", 0xffffffff},
14146 + {"none", 0},
14147 + {NULL, 0},
14150 +#define MAX_MASK_NAME_LENGTH 40
14151 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
14152 + unsigned long count, void *data)
14154 + unsigned rg = 0, mask_bitfield;
14155 + char *end;
14156 + char *mask_name;
14157 + const char *x;
14158 + char substring[MAX_MASK_NAME_LENGTH + 1];
14159 + int i;
14160 + int done = 0;
14161 + int add, len = 0;
14162 + int pos = 0;
14164 + rg = yaffs_trace_mask;
14166 + while (!done && (pos < count)) {
14167 + done = 1;
14168 + while ((pos < count) && isspace(buf[pos]))
14169 + pos++;
14171 + switch (buf[pos]) {
14172 + case '+':
14173 + case '-':
14174 + case '=':
14175 + add = buf[pos];
14176 + pos++;
14177 + break;
14179 + default:
14180 + add = ' ';
14181 + break;
14183 + mask_name = NULL;
14185 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
14187 + if (end > buf + pos) {
14188 + mask_name = "numeral";
14189 + len = end - (buf + pos);
14190 + pos += len;
14191 + done = 0;
14192 + } else {
14193 + for (x = buf + pos, i = 0;
14194 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
14195 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
14196 + substring[i] = *x;
14197 + substring[i] = '\0';
14199 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
14200 + if (strcmp(substring, mask_flags[i].mask_name)
14201 + == 0) {
14202 + mask_name = mask_flags[i].mask_name;
14203 + mask_bitfield =
14204 + mask_flags[i].mask_bitfield;
14205 + done = 0;
14206 + break;
14211 + if (mask_name != NULL) {
14212 + done = 0;
14213 + switch (add) {
14214 + case '-':
14215 + rg &= ~mask_bitfield;
14216 + break;
14217 + case '+':
14218 + rg |= mask_bitfield;
14219 + break;
14220 + case '=':
14221 + rg = mask_bitfield;
14222 + break;
14223 + default:
14224 + rg |= mask_bitfield;
14225 + break;
14230 + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
14232 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
14234 + if (rg & YAFFS_TRACE_ALWAYS) {
14235 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
14236 + char flag;
14237 + flag = ((rg & mask_flags[i].mask_bitfield) ==
14238 + mask_flags[i].mask_bitfield) ? '+' : '-';
14239 + printk(KERN_DEBUG "%c%s\n", flag,
14240 + mask_flags[i].mask_name);
14244 + return count;
14247 +/* Debug strings are of the form:
14248 + * .bnnn print info on block n
14249 + * .cobjn,chunkn print nand chunk id for objn:chunkn
14250 + */
14252 +static int yaffs_proc_debug_write(struct file *file, const char *buf,
14253 + unsigned long count, void *data)
14256 + char str[100];
14257 + char *p0;
14258 + char *p1;
14259 + long p1_val;
14260 + long p0_val;
14261 + char cmd;
14262 + struct list_head *item;
14264 + memset(str, 0, sizeof(str));
14265 + memcpy(str, buf, min(count, sizeof(str) -1));
14267 + cmd = str[1];
14269 + p0 = str + 2;
14271 + p1 = p0;
14273 + while (*p1 && *p1 != ',') {
14274 + p1++;
14276 + *p1 = '\0';
14277 + p1++;
14279 + p0_val = simple_strtol(p0, NULL, 0);
14280 + p1_val = simple_strtol(p1, NULL, 0);
14283 + mutex_lock(&yaffs_context_lock);
14285 + /* Locate and print the Nth entry. Order N-squared but N is small. */
14286 + list_for_each(item, &yaffs_context_list) {
14287 + struct yaffs_linux_context *dc =
14288 + list_entry(item, struct yaffs_linux_context,
14289 + context_list);
14290 + struct yaffs_dev *dev = dc->dev;
14292 + if (cmd == 'b') {
14293 + struct yaffs_block_info *bi;
14295 + bi = yaffs_get_block_info(dev,p0_val);
14297 + if(bi) {
14298 + printk("Block %d: state %d, retire %d, use %d, seq %d\n",
14299 + (int)p0_val, bi->block_state,
14300 + bi->needs_retiring, bi->pages_in_use,
14301 + bi->seq_number);
14303 + } else if (cmd == 'c') {
14304 + struct yaffs_obj *obj;
14305 + int nand_chunk;
14307 + obj = yaffs_find_by_number(dev, p0_val);
14308 + if (!obj)
14309 + printk("No obj %d\n", (int)p0_val);
14310 + else {
14311 + if(p1_val == 0)
14312 + nand_chunk = obj->hdr_chunk;
14313 + else
14314 + nand_chunk =
14315 + yaffs_find_chunk_in_file(obj,
14316 + p1_val, NULL);
14317 + printk("Nand chunk for %d:%d is %d\n",
14318 + (int)p0_val, (int)p1_val, nand_chunk);
14323 + mutex_unlock(&yaffs_context_lock);
14325 + return count;
14328 +static int yaffs_proc_write(struct file *file, const char *buf,
14329 + unsigned long count, void *data)
14331 + if (buf[0] == '.')
14332 + return yaffs_proc_debug_write(file, buf, count, data);
14333 + return yaffs_proc_write_trace_options(file, buf, count, data);
14335 +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
14337 +/* Stuff to handle installation of file systems */
14338 +struct file_system_to_install {
14339 + struct file_system_type *fst;
14340 + int installed;
14343 +static struct file_system_to_install fs_to_install[] = {
14344 + {&yaffs_fs_type, 0},
14345 + {&yaffs2_fs_type, 0},
14346 + {NULL, 0}
14349 +static int __init init_yaffs_fs(void)
14351 + int error = 0;
14352 + struct file_system_to_install *fsinst;
14354 + yaffs_trace(YAFFS_TRACE_ALWAYS,
14355 + "yaffs built " __DATE__ " " __TIME__ " Installing.");
14357 + mutex_init(&yaffs_context_lock);
14359 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
14360 + /* Install the proc_fs entries */
14361 + my_proc_entry = create_proc_entry("yaffs",
14362 + S_IRUGO | S_IFREG, YPROC_ROOT);
14364 + if (my_proc_entry) {
14365 + my_proc_entry->write_proc = yaffs_proc_write;
14366 + my_proc_entry->read_proc = yaffs_proc_read;
14367 + my_proc_entry->data = NULL;
14368 + } else {
14369 + return -ENOMEM;
14371 +#endif
14373 + /* Now add the file system entries */
14375 + fsinst = fs_to_install;
14377 + while (fsinst->fst && !error) {
14378 + error = register_filesystem(fsinst->fst);
14379 + if (!error)
14380 + fsinst->installed = 1;
14381 + fsinst++;
14384 + /* Any errors? uninstall */
14385 + if (error) {
14386 + fsinst = fs_to_install;
14388 + while (fsinst->fst) {
14389 + if (fsinst->installed) {
14390 + unregister_filesystem(fsinst->fst);
14391 + fsinst->installed = 0;
14393 + fsinst++;
14397 + return error;
14400 +static void __exit exit_yaffs_fs(void)
14403 + struct file_system_to_install *fsinst;
14405 + yaffs_trace(YAFFS_TRACE_ALWAYS,
14406 + "yaffs built " __DATE__ " " __TIME__ " removing.");
14408 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
14409 + remove_proc_entry("yaffs", YPROC_ROOT);
14410 +#endif
14412 + fsinst = fs_to_install;
14414 + while (fsinst->fst) {
14415 + if (fsinst->installed) {
14416 + unregister_filesystem(fsinst->fst);
14417 + fsinst->installed = 0;
14419 + fsinst++;
14423 +module_init(init_yaffs_fs)
14424 + module_exit(exit_yaffs_fs)
14426 + MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
14427 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
14428 +MODULE_LICENSE("GPL");
14429 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.4.90/fs/yaffs2/yaffs_yaffs1.c
14430 --- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
14431 +++ linux-3.4.90/fs/yaffs2/yaffs_yaffs1.c 2014-05-17 15:08:09.000000000 +0200
14432 @@ -0,0 +1,422 @@
14434 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
14436 + * Copyright (C) 2002-2011 Aleph One Ltd.
14437 + * for Toby Churchill Ltd and Brightstar Engineering
14439 + * Created by Charles Manning <charles@aleph1.co.uk>
14441 + * This program is free software; you can redistribute it and/or modify
14442 + * it under the terms of the GNU General Public License version 2 as
14443 + * published by the Free Software Foundation.
14444 + */
14446 +#include "yaffs_yaffs1.h"
14447 +#include "yportenv.h"
14448 +#include "yaffs_trace.h"
14449 +#include "yaffs_bitmap.h"
14450 +#include "yaffs_getblockinfo.h"
14451 +#include "yaffs_nand.h"
14452 +#include "yaffs_attribs.h"
14454 +int yaffs1_scan(struct yaffs_dev *dev)
14456 + struct yaffs_ext_tags tags;
14457 + int blk;
14458 + int result;
14459 + int chunk;
14460 + int c;
14461 + int deleted;
14462 + enum yaffs_block_state state;
14463 + LIST_HEAD(hard_list);
14464 + struct yaffs_block_info *bi;
14465 + u32 seq_number;
14466 + struct yaffs_obj_hdr *oh;
14467 + struct yaffs_obj *in;
14468 + struct yaffs_obj *parent;
14469 + int alloc_failed = 0;
14470 + struct yaffs_shadow_fixer *shadow_fixers = NULL;
14471 + u8 *chunk_data;
14473 + yaffs_trace(YAFFS_TRACE_SCAN,
14474 + "yaffs1_scan starts intstartblk %d intendblk %d...",
14475 + dev->internal_start_block, dev->internal_end_block);
14477 + chunk_data = yaffs_get_temp_buffer(dev);
14479 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
14481 + /* Scan all the blocks to determine their state */
14482 + bi = dev->block_info;
14483 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
14484 + blk++) {
14485 + yaffs_clear_chunk_bits(dev, blk);
14486 + bi->pages_in_use = 0;
14487 + bi->soft_del_pages = 0;
14489 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
14491 + bi->block_state = state;
14492 + bi->seq_number = seq_number;
14494 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
14495 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
14497 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
14498 + "Block scanning block %d state %d seq %d",
14499 + blk, state, seq_number);
14501 + if (state == YAFFS_BLOCK_STATE_DEAD) {
14502 + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
14503 + "block %d is bad", blk);
14504 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
14505 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
14506 + dev->n_erased_blocks++;
14507 + dev->n_free_chunks += dev->param.chunks_per_block;
14509 + bi++;
14512 + /* For each block.... */
14513 + for (blk = dev->internal_start_block;
14514 + !alloc_failed && blk <= dev->internal_end_block; blk++) {
14516 + cond_resched();
14518 + bi = yaffs_get_block_info(dev, blk);
14519 + state = bi->block_state;
14521 + deleted = 0;
14523 + /* For each chunk in each block that needs scanning.... */
14524 + for (c = 0;
14525 + !alloc_failed && c < dev->param.chunks_per_block &&
14526 + state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
14527 + /* Read the tags and decide what to do */
14528 + chunk = blk * dev->param.chunks_per_block + c;
14530 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
14531 + &tags);
14533 + /* Let's have a good look at this chunk... */
14535 + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
14536 + tags.is_deleted) {
14537 + /* YAFFS1 only...
14538 + * A deleted chunk
14539 + */
14540 + deleted++;
14541 + dev->n_free_chunks++;
14542 + } else if (!tags.chunk_used) {
14543 + /* An unassigned chunk in the block
14544 + * This means that either the block is empty or
14545 + * this is the one being allocated from
14546 + */
14548 + if (c == 0) {
14549 + /* We're looking at the first chunk in
14550 + *the block so the block is unused */
14551 + state = YAFFS_BLOCK_STATE_EMPTY;
14552 + dev->n_erased_blocks++;
14553 + } else {
14554 + /* this is the block being allocated */
14555 + yaffs_trace(YAFFS_TRACE_SCAN,
14556 + " Allocating from %d %d",
14557 + blk, c);
14558 + state = YAFFS_BLOCK_STATE_ALLOCATING;
14559 + dev->alloc_block = blk;
14560 + dev->alloc_page = c;
14561 + dev->alloc_block_finder = blk;
14565 + dev->n_free_chunks +=
14566 + (dev->param.chunks_per_block - c);
14567 + } else if (tags.chunk_id > 0) {
14568 + /* chunk_id > 0 so it is a data chunk... */
14569 + unsigned int endpos;
14571 + yaffs_set_chunk_bit(dev, blk, c);
14572 + bi->pages_in_use++;
14574 + in = yaffs_find_or_create_by_number(dev,
14575 + tags.obj_id,
14576 + YAFFS_OBJECT_TYPE_FILE);
14577 + /* PutChunkIntoFile checks for a clash
14578 + * (two data chunks with the same chunk_id).
14579 + */
14581 + if (!in)
14582 + alloc_failed = 1;
14584 + if (in) {
14585 + if (!yaffs_put_chunk_in_file
14586 + (in, tags.chunk_id, chunk, 1))
14587 + alloc_failed = 1;
14590 + endpos =
14591 + (tags.chunk_id - 1) *
14592 + dev->data_bytes_per_chunk +
14593 + tags.n_bytes;
14594 + if (in &&
14595 + in->variant_type ==
14596 + YAFFS_OBJECT_TYPE_FILE &&
14597 + in->variant.file_variant.scanned_size <
14598 + endpos) {
14599 + in->variant.file_variant.scanned_size =
14600 + endpos;
14601 + if (!dev->param.use_header_file_size) {
14602 + in->variant.
14603 + file_variant.file_size =
14604 + in->variant.
14605 + file_variant.scanned_size;
14609 + } else {
14610 + /* chunk_id == 0, so it is an ObjectHeader.
14611 + * Make the object
14612 + */
14613 + yaffs_set_chunk_bit(dev, blk, c);
14614 + bi->pages_in_use++;
14616 + result = yaffs_rd_chunk_tags_nand(dev, chunk,
14617 + chunk_data,
14618 + NULL);
14620 + oh = (struct yaffs_obj_hdr *)chunk_data;
14622 + in = yaffs_find_by_number(dev, tags.obj_id);
14623 + if (in && in->variant_type != oh->type) {
14624 + /* This should not happen, but somehow
14625 + * Wev'e ended up with an obj_id that
14626 + * has been reused but not yet deleted,
14627 + * and worse still it has changed type.
14628 + * Delete the old object.
14629 + */
14631 + yaffs_del_obj(in);
14632 + in = NULL;
14635 + in = yaffs_find_or_create_by_number(dev,
14636 + tags.obj_id,
14637 + oh->type);
14639 + if (!in)
14640 + alloc_failed = 1;
14642 + if (in && oh->shadows_obj > 0) {
14644 + struct yaffs_shadow_fixer *fixer;
14645 + fixer =
14646 + kmalloc(sizeof
14647 + (struct yaffs_shadow_fixer),
14648 + GFP_NOFS);
14649 + if (fixer) {
14650 + fixer->next = shadow_fixers;
14651 + shadow_fixers = fixer;
14652 + fixer->obj_id = tags.obj_id;
14653 + fixer->shadowed_id =
14654 + oh->shadows_obj;
14655 + yaffs_trace(YAFFS_TRACE_SCAN,
14656 + " Shadow fixer: %d shadows %d",
14657 + fixer->obj_id,
14658 + fixer->shadowed_id);
14664 + if (in && in->valid) {
14665 + /* We have already filled this one.
14666 + * We have a duplicate and need to
14667 + * resolve it. */
14669 + unsigned existing_serial = in->serial;
14670 + unsigned new_serial =
14671 + tags.serial_number;
14673 + if (((existing_serial + 1) & 3) ==
14674 + new_serial) {
14675 + /* Use new one - destroy the
14676 + * exisiting one */
14677 + yaffs_chunk_del(dev,
14678 + in->hdr_chunk,
14679 + 1, __LINE__);
14680 + in->valid = 0;
14681 + } else {
14682 + /* Use existing - destroy
14683 + * this one. */
14684 + yaffs_chunk_del(dev, chunk, 1,
14685 + __LINE__);
14689 + if (in && !in->valid &&
14690 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
14691 + tags.obj_id ==
14692 + YAFFS_OBJECTID_LOSTNFOUND)) {
14693 + /* We only load some info, don't fiddle
14694 + * with directory structure */
14695 + in->valid = 1;
14696 + in->variant_type = oh->type;
14698 + in->yst_mode = oh->yst_mode;
14699 + yaffs_load_attribs(in, oh);
14700 + in->hdr_chunk = chunk;
14701 + in->serial = tags.serial_number;
14703 + } else if (in && !in->valid) {
14704 + /* we need to load this info */
14706 + in->valid = 1;
14707 + in->variant_type = oh->type;
14709 + in->yst_mode = oh->yst_mode;
14710 + yaffs_load_attribs(in, oh);
14711 + in->hdr_chunk = chunk;
14712 + in->serial = tags.serial_number;
14714 + yaffs_set_obj_name_from_oh(in, oh);
14715 + in->dirty = 0;
14717 + /* directory stuff...
14718 + * hook up to parent
14719 + */
14721 + parent =
14722 + yaffs_find_or_create_by_number
14723 + (dev, oh->parent_obj_id,
14724 + YAFFS_OBJECT_TYPE_DIRECTORY);
14725 + if (!parent)
14726 + alloc_failed = 1;
14727 + if (parent && parent->variant_type ==
14728 + YAFFS_OBJECT_TYPE_UNKNOWN) {
14729 + /* Set up as a directory */
14730 + parent->variant_type =
14731 + YAFFS_OBJECT_TYPE_DIRECTORY;
14732 + INIT_LIST_HEAD(&parent->
14733 + variant.dir_variant.
14734 + children);
14735 + } else if (!parent ||
14736 + parent->variant_type !=
14737 + YAFFS_OBJECT_TYPE_DIRECTORY) {
14738 + /* Hoosterman, a problem....
14739 + * We're trying to use a
14740 + * non-directory as a directory
14741 + */
14743 + yaffs_trace(YAFFS_TRACE_ERROR,
14744 + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
14745 + );
14746 + parent = dev->lost_n_found;
14749 + yaffs_add_obj_to_dir(parent, in);
14751 + switch (in->variant_type) {
14752 + case YAFFS_OBJECT_TYPE_UNKNOWN:
14753 + /* Todo got a problem */
14754 + break;
14755 + case YAFFS_OBJECT_TYPE_FILE:
14756 + if (dev->param.
14757 + use_header_file_size)
14758 + in->variant.
14759 + file_variant.file_size
14760 + = yaffs_oh_to_size(oh);
14761 + break;
14762 + case YAFFS_OBJECT_TYPE_HARDLINK:
14763 + in->variant.
14764 + hardlink_variant.equiv_id =
14765 + oh->equiv_id;
14766 + list_add(&in->hard_links,
14767 + &hard_list);
14768 + break;
14769 + case YAFFS_OBJECT_TYPE_DIRECTORY:
14770 + /* Do nothing */
14771 + break;
14772 + case YAFFS_OBJECT_TYPE_SPECIAL:
14773 + /* Do nothing */
14774 + break;
14775 + case YAFFS_OBJECT_TYPE_SYMLINK:
14776 + in->variant.symlink_variant.
14777 + alias =
14778 + yaffs_clone_str(oh->alias);
14779 + if (!in->variant.
14780 + symlink_variant.alias)
14781 + alloc_failed = 1;
14782 + break;
14788 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
14789 + /* If we got this far while scanning,
14790 + * then the block is fully allocated. */
14791 + state = YAFFS_BLOCK_STATE_FULL;
14794 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
14795 + /* If the block was partially allocated then
14796 + * treat it as fully allocated. */
14797 + state = YAFFS_BLOCK_STATE_FULL;
14798 + dev->alloc_block = -1;
14801 + bi->block_state = state;
14803 + /* Now let's see if it was dirty */
14804 + if (bi->pages_in_use == 0 &&
14805 + !bi->has_shrink_hdr &&
14806 + bi->block_state == YAFFS_BLOCK_STATE_FULL)
14807 + yaffs_block_became_dirty(dev, blk);
14810 + /* Ok, we've done all the scanning.
14811 + * Fix up the hard link chains.
14812 + * We should now have scanned all the objects, now it's time to add
14813 + * these hardlinks.
14814 + */
14816 + yaffs_link_fixup(dev, &hard_list);
14818 + /*
14819 + * Fix up any shadowed objects.
14820 + * There should not be more than one of these.
14821 + */
14823 + struct yaffs_shadow_fixer *fixer;
14824 + struct yaffs_obj *obj;
14826 + while (shadow_fixers) {
14827 + fixer = shadow_fixers;
14828 + shadow_fixers = fixer->next;
14829 + /* Complete the rename transaction by deleting the
14830 + * shadowed object then setting the object header
14831 + to unshadowed.
14832 + */
14833 + obj = yaffs_find_by_number(dev, fixer->shadowed_id);
14834 + if (obj)
14835 + yaffs_del_obj(obj);
14837 + obj = yaffs_find_by_number(dev, fixer->obj_id);
14839 + if (obj)
14840 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
14842 + kfree(fixer);
14846 + yaffs_release_temp_buffer(dev, chunk_data);
14848 + if (alloc_failed)
14849 + return YAFFS_FAIL;
14851 + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
14853 + return YAFFS_OK;
14855 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.4.90/fs/yaffs2/yaffs_yaffs1.h
14856 --- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
14857 +++ linux-3.4.90/fs/yaffs2/yaffs_yaffs1.h 2014-05-17 15:08:09.000000000 +0200
14858 @@ -0,0 +1,22 @@
14860 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14862 + * Copyright (C) 2002-2011 Aleph One Ltd.
14863 + * for Toby Churchill Ltd and Brightstar Engineering
14865 + * Created by Charles Manning <charles@aleph1.co.uk>
14867 + * This program is free software; you can redistribute it and/or modify
14868 + * it under the terms of the GNU Lesser General Public License version 2.1 as
14869 + * published by the Free Software Foundation.
14871 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14872 + */
14874 +#ifndef __YAFFS_YAFFS1_H__
14875 +#define __YAFFS_YAFFS1_H__
14877 +#include "yaffs_guts.h"
14878 +int yaffs1_scan(struct yaffs_dev *dev);
14880 +#endif
14881 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.4.90/fs/yaffs2/yaffs_yaffs2.c
14882 --- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
14883 +++ linux-3.4.90/fs/yaffs2/yaffs_yaffs2.c 2014-05-17 15:08:09.000000000 +0200
14884 @@ -0,0 +1,1534 @@
14886 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
14888 + * Copyright (C) 2002-2011 Aleph One Ltd.
14889 + * for Toby Churchill Ltd and Brightstar Engineering
14891 + * Created by Charles Manning <charles@aleph1.co.uk>
14893 + * This program is free software; you can redistribute it and/or modify
14894 + * it under the terms of the GNU General Public License version 2 as
14895 + * published by the Free Software Foundation.
14896 + */
14898 +#include "yaffs_guts.h"
14899 +#include "yaffs_trace.h"
14900 +#include "yaffs_yaffs2.h"
14901 +#include "yaffs_checkptrw.h"
14902 +#include "yaffs_bitmap.h"
14903 +#include "yaffs_nand.h"
14904 +#include "yaffs_getblockinfo.h"
14905 +#include "yaffs_verify.h"
14906 +#include "yaffs_attribs.h"
14907 +#include "yaffs_summary.h"
14910 + * Checkpoints are really no benefit on very small partitions.
14912 + * To save space on small partitions don't bother with checkpoints unless
14913 + * the partition is at least this big.
14914 + */
14915 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
14916 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
14919 + * Oldest Dirty Sequence Number handling.
14920 + */
14922 +/* yaffs_calc_oldest_dirty_seq()
14923 + * yaffs2_find_oldest_dirty_seq()
14924 + * Calculate the oldest dirty sequence number if we don't know it.
14925 + */
14926 +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
14928 + int i;
14929 + unsigned seq;
14930 + unsigned block_no = 0;
14931 + struct yaffs_block_info *b;
14933 + if (!dev->param.is_yaffs2)
14934 + return;
14936 + /* Find the oldest dirty sequence number. */
14937 + seq = dev->seq_number + 1;
14938 + b = dev->block_info;
14939 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
14940 + if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
14941 + (b->pages_in_use - b->soft_del_pages) <
14942 + dev->param.chunks_per_block &&
14943 + b->seq_number < seq) {
14944 + seq = b->seq_number;
14945 + block_no = i;
14947 + b++;
14950 + if (block_no) {
14951 + dev->oldest_dirty_seq = seq;
14952 + dev->oldest_dirty_block = block_no;
14956 +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
14958 + if (!dev->param.is_yaffs2)
14959 + return;
14961 + if (!dev->oldest_dirty_seq)
14962 + yaffs_calc_oldest_dirty_seq(dev);
14966 + * yaffs_clear_oldest_dirty_seq()
14967 + * Called when a block is erased or marked bad. (ie. when its seq_number
14968 + * becomes invalid). If the value matches the oldest then we clear
14969 + * dev->oldest_dirty_seq to force its recomputation.
14970 + */
14971 +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
14972 + struct yaffs_block_info *bi)
14975 + if (!dev->param.is_yaffs2)
14976 + return;
14978 + if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
14979 + dev->oldest_dirty_seq = 0;
14980 + dev->oldest_dirty_block = 0;
14985 + * yaffs2_update_oldest_dirty_seq()
14986 + * Update the oldest dirty sequence number whenever we dirty a block.
14987 + * Only do this if the oldest_dirty_seq is actually being tracked.
14988 + */
14989 +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
14990 + struct yaffs_block_info *bi)
14992 + if (!dev->param.is_yaffs2)
14993 + return;
14995 + if (dev->oldest_dirty_seq) {
14996 + if (dev->oldest_dirty_seq > bi->seq_number) {
14997 + dev->oldest_dirty_seq = bi->seq_number;
14998 + dev->oldest_dirty_block = block_no;
15003 +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
15006 + if (!dev->param.is_yaffs2)
15007 + return 1; /* disqualification only applies to yaffs2. */
15009 + if (!bi->has_shrink_hdr)
15010 + return 1; /* can gc */
15012 + yaffs2_find_oldest_dirty_seq(dev);
15014 + /* Can't do gc of this block if there are any blocks older than this
15015 + * one that have discarded pages.
15016 + */
15017 + return (bi->seq_number <= dev->oldest_dirty_seq);
15021 + * yaffs2_find_refresh_block()
15022 + * periodically finds the oldest full block by sequence number for refreshing.
15023 + * Only for yaffs2.
15024 + */
15025 +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
15027 + u32 b;
15028 + u32 oldest = 0;
15029 + u32 oldest_seq = 0;
15030 + struct yaffs_block_info *bi;
15032 + if (!dev->param.is_yaffs2)
15033 + return oldest;
15035 + /*
15036 + * If refresh period < 10 then refreshing is disabled.
15037 + */
15038 + if (dev->param.refresh_period < 10)
15039 + return oldest;
15041 + /*
15042 + * Fix broken values.
15043 + */
15044 + if (dev->refresh_skip > dev->param.refresh_period)
15045 + dev->refresh_skip = dev->param.refresh_period;
15047 + if (dev->refresh_skip > 0)
15048 + return oldest;
15050 + /*
15051 + * Refresh skip is now zero.
15052 + * We'll do a refresh this time around....
15053 + * Update the refresh skip and find the oldest block.
15054 + */
15055 + dev->refresh_skip = dev->param.refresh_period;
15056 + dev->refresh_count++;
15057 + bi = dev->block_info;
15058 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
15060 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
15062 + if (oldest < 1 || bi->seq_number < oldest_seq) {
15063 + oldest = b;
15064 + oldest_seq = bi->seq_number;
15067 + bi++;
15070 + if (oldest > 0) {
15071 + yaffs_trace(YAFFS_TRACE_GC,
15072 + "GC refresh count %d selected block %d with seq_number %d",
15073 + dev->refresh_count, oldest, oldest_seq);
15076 + return oldest;
15079 +int yaffs2_checkpt_required(struct yaffs_dev *dev)
15081 + int nblocks;
15083 + if (!dev->param.is_yaffs2)
15084 + return 0;
15086 + nblocks = dev->internal_end_block - dev->internal_start_block + 1;
15088 + return !dev->param.skip_checkpt_wr &&
15089 + !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
15092 +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
15094 + int retval;
15095 + int n_bytes = 0;
15096 + int n_blocks;
15097 + int dev_blocks;
15099 + if (!dev->param.is_yaffs2)
15100 + return 0;
15102 + if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
15103 + /* Not a valid value so recalculate */
15104 + dev_blocks = dev->param.end_block - dev->param.start_block + 1;
15105 + n_bytes += sizeof(struct yaffs_checkpt_validity);
15106 + n_bytes += sizeof(struct yaffs_checkpt_dev);
15107 + n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
15108 + n_bytes += dev_blocks * dev->chunk_bit_stride;
15109 + n_bytes +=
15110 + (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
15111 + dev->n_obj;
15112 + n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
15113 + n_bytes += sizeof(struct yaffs_checkpt_validity);
15114 + n_bytes += sizeof(u32); /* checksum */
15116 + /* Round up and add 2 blocks to allow for some bad blocks,
15117 + * so add 3 */
15119 + n_blocks =
15120 + (n_bytes /
15121 + (dev->data_bytes_per_chunk *
15122 + dev->param.chunks_per_block)) + 3;
15124 + dev->checkpoint_blocks_required = n_blocks;
15127 + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
15128 + if (retval < 0)
15129 + retval = 0;
15130 + return retval;
15133 +/*--------------------- Checkpointing --------------------*/
15135 +static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
15137 + struct yaffs_checkpt_validity cp;
15139 + memset(&cp, 0, sizeof(cp));
15141 + cp.struct_type = sizeof(cp);
15142 + cp.magic = YAFFS_MAGIC;
15143 + cp.version = YAFFS_CHECKPOINT_VERSION;
15144 + cp.head = (head) ? 1 : 0;
15146 + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
15149 +static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
15151 + struct yaffs_checkpt_validity cp;
15152 + int ok;
15154 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
15156 + if (ok)
15157 + ok = (cp.struct_type == sizeof(cp)) &&
15158 + (cp.magic == YAFFS_MAGIC) &&
15159 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
15160 + (cp.head == ((head) ? 1 : 0));
15161 + return ok ? 1 : 0;
15164 +static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
15165 + struct yaffs_dev *dev)
15167 + cp->n_erased_blocks = dev->n_erased_blocks;
15168 + cp->alloc_block = dev->alloc_block;
15169 + cp->alloc_page = dev->alloc_page;
15170 + cp->n_free_chunks = dev->n_free_chunks;
15172 + cp->n_deleted_files = dev->n_deleted_files;
15173 + cp->n_unlinked_files = dev->n_unlinked_files;
15174 + cp->n_bg_deletions = dev->n_bg_deletions;
15175 + cp->seq_number = dev->seq_number;
15179 +static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
15180 + struct yaffs_checkpt_dev *cp)
15182 + dev->n_erased_blocks = cp->n_erased_blocks;
15183 + dev->alloc_block = cp->alloc_block;
15184 + dev->alloc_page = cp->alloc_page;
15185 + dev->n_free_chunks = cp->n_free_chunks;
15187 + dev->n_deleted_files = cp->n_deleted_files;
15188 + dev->n_unlinked_files = cp->n_unlinked_files;
15189 + dev->n_bg_deletions = cp->n_bg_deletions;
15190 + dev->seq_number = cp->seq_number;
15193 +static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
15195 + struct yaffs_checkpt_dev cp;
15196 + u32 n_bytes;
15197 + u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
15198 + int ok;
15200 + /* Write device runtime values */
15201 + yaffs2_dev_to_checkpt_dev(&cp, dev);
15202 + cp.struct_type = sizeof(cp);
15204 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
15205 + if (!ok)
15206 + return 0;
15208 + /* Write block info */
15209 + n_bytes = n_blocks * sizeof(struct yaffs_block_info);
15210 + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
15211 + if (!ok)
15212 + return 0;
15214 + /* Write chunk bits */
15215 + n_bytes = n_blocks * dev->chunk_bit_stride;
15216 + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
15218 + return ok ? 1 : 0;
15221 +static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
15223 + struct yaffs_checkpt_dev cp;
15224 + u32 n_bytes;
15225 + u32 n_blocks =
15226 + (dev->internal_end_block - dev->internal_start_block + 1);
15227 + int ok;
15229 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
15230 + if (!ok)
15231 + return 0;
15233 + if (cp.struct_type != sizeof(cp))
15234 + return 0;
15236 + yaffs_checkpt_dev_to_dev(dev, &cp);
15238 + n_bytes = n_blocks * sizeof(struct yaffs_block_info);
15240 + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
15242 + if (!ok)
15243 + return 0;
15245 + n_bytes = n_blocks * dev->chunk_bit_stride;
15247 + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
15249 + return ok ? 1 : 0;
15252 +static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
15253 + struct yaffs_obj *obj)
15255 + cp->obj_id = obj->obj_id;
15256 + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
15257 + cp->hdr_chunk = obj->hdr_chunk;
15258 + cp->variant_type = obj->variant_type;
15259 + cp->deleted = obj->deleted;
15260 + cp->soft_del = obj->soft_del;
15261 + cp->unlinked = obj->unlinked;
15262 + cp->fake = obj->fake;
15263 + cp->rename_allowed = obj->rename_allowed;
15264 + cp->unlink_allowed = obj->unlink_allowed;
15265 + cp->serial = obj->serial;
15266 + cp->n_data_chunks = obj->n_data_chunks;
15268 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
15269 + cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
15270 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
15271 + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
15274 +static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
15275 + struct yaffs_checkpt_obj *cp)
15277 + struct yaffs_obj *parent;
15279 + if (obj->variant_type != cp->variant_type) {
15280 + yaffs_trace(YAFFS_TRACE_ERROR,
15281 + "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
15282 + cp->obj_id, cp->variant_type, cp->hdr_chunk,
15283 + obj->variant_type);
15284 + return 0;
15287 + obj->obj_id = cp->obj_id;
15289 + if (cp->parent_id)
15290 + parent = yaffs_find_or_create_by_number(obj->my_dev,
15291 + cp->parent_id,
15292 + YAFFS_OBJECT_TYPE_DIRECTORY);
15293 + else
15294 + parent = NULL;
15296 + if (parent) {
15297 + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
15298 + yaffs_trace(YAFFS_TRACE_ALWAYS,
15299 + "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
15300 + cp->obj_id, cp->parent_id,
15301 + cp->variant_type, cp->hdr_chunk,
15302 + parent->variant_type);
15303 + return 0;
15305 + yaffs_add_obj_to_dir(parent, obj);
15308 + obj->hdr_chunk = cp->hdr_chunk;
15309 + obj->variant_type = cp->variant_type;
15310 + obj->deleted = cp->deleted;
15311 + obj->soft_del = cp->soft_del;
15312 + obj->unlinked = cp->unlinked;
15313 + obj->fake = cp->fake;
15314 + obj->rename_allowed = cp->rename_allowed;
15315 + obj->unlink_allowed = cp->unlink_allowed;
15316 + obj->serial = cp->serial;
15317 + obj->n_data_chunks = cp->n_data_chunks;
15319 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
15320 + obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
15321 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
15322 + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
15324 + if (obj->hdr_chunk > 0)
15325 + obj->lazy_loaded = 1;
15326 + return 1;
15329 +static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
15330 + struct yaffs_tnode *tn, u32 level,
15331 + int chunk_offset)
15333 + int i;
15334 + struct yaffs_dev *dev = in->my_dev;
15335 + int ok = 1;
15336 + u32 base_offset;
15338 + if (!tn)
15339 + return 1;
15341 + if (level > 0) {
15342 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
15343 + if (!tn->internal[i])
15344 + continue;
15345 + ok = yaffs2_checkpt_tnode_worker(in,
15346 + tn->internal[i],
15347 + level - 1,
15348 + (chunk_offset <<
15349 + YAFFS_TNODES_INTERNAL_BITS) + i);
15351 + return ok;
15354 + /* Level 0 tnode */
15355 + base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
15356 + ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
15357 + sizeof(base_offset));
15358 + if (ok)
15359 + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
15360 + dev->tnode_size);
15362 + return ok;
15365 +static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
15367 + u32 end_marker = ~0;
15368 + int ok = 1;
15370 + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
15371 + return ok;
15373 + ok = yaffs2_checkpt_tnode_worker(obj,
15374 + obj->variant.file_variant.top,
15375 + obj->variant.file_variant.
15376 + top_level, 0);
15377 + if (ok)
15378 + ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
15379 + sizeof(end_marker)) == sizeof(end_marker));
15381 + return ok ? 1 : 0;
15384 +static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
15386 + u32 base_chunk;
15387 + int ok = 1;
15388 + struct yaffs_dev *dev = obj->my_dev;
15389 + struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
15390 + struct yaffs_tnode *tn;
15391 + int nread = 0;
15393 + ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
15394 + sizeof(base_chunk));
15396 + while (ok && (~base_chunk)) {
15397 + nread++;
15398 + /* Read level 0 tnode */
15400 + tn = yaffs_get_tnode(dev);
15401 + if (tn)
15402 + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
15403 + dev->tnode_size);
15404 + else
15405 + ok = 0;
15407 + if (tn && ok)
15408 + ok = yaffs_add_find_tnode_0(dev,
15409 + file_stuct_ptr,
15410 + base_chunk, tn) ? 1 : 0;
15412 + if (ok)
15413 + ok = (yaffs2_checkpt_rd
15414 + (dev, &base_chunk,
15415 + sizeof(base_chunk)) == sizeof(base_chunk));
15418 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15419 + "Checkpoint read tnodes %d records, last %d. ok %d",
15420 + nread, base_chunk, ok);
15422 + return ok ? 1 : 0;
15425 +static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
15427 + struct yaffs_obj *obj;
15428 + struct yaffs_checkpt_obj cp;
15429 + int i;
15430 + int ok = 1;
15431 + struct list_head *lh;
15433 + /* Iterate through the objects in each hash entry,
15434 + * dumping them to the checkpointing stream.
15435 + */
15437 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
15438 + list_for_each(lh, &dev->obj_bucket[i].list) {
15439 + obj = list_entry(lh, struct yaffs_obj, hash_link);
15440 + if (!obj->defered_free) {
15441 + yaffs2_obj_checkpt_obj(&cp, obj);
15442 + cp.struct_type = sizeof(cp);
15444 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15445 + "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
15446 + cp.obj_id, cp.parent_id,
15447 + cp.variant_type, cp.hdr_chunk, obj);
15449 + ok = (yaffs2_checkpt_wr(dev, &cp,
15450 + sizeof(cp)) == sizeof(cp));
15452 + if (ok &&
15453 + obj->variant_type ==
15454 + YAFFS_OBJECT_TYPE_FILE)
15455 + ok = yaffs2_wr_checkpt_tnodes(obj);
15460 + /* Dump end of list */
15461 + memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
15462 + cp.struct_type = sizeof(cp);
15464 + if (ok)
15465 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
15467 + return ok ? 1 : 0;
15470 +static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
15472 + struct yaffs_obj *obj;
15473 + struct yaffs_checkpt_obj cp;
15474 + int ok = 1;
15475 + int done = 0;
15476 + LIST_HEAD(hard_list);
15479 + while (ok && !done) {
15480 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
15481 + if (cp.struct_type != sizeof(cp)) {
15482 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15483 + "struct size %d instead of %d ok %d",
15484 + cp.struct_type, (int)sizeof(cp), ok);
15485 + ok = 0;
15488 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15489 + "Checkpoint read object %d parent %d type %d chunk %d ",
15490 + cp.obj_id, cp.parent_id, cp.variant_type,
15491 + cp.hdr_chunk);
15493 + if (ok && cp.obj_id == ~0) {
15494 + done = 1;
15495 + } else if (ok) {
15496 + obj =
15497 + yaffs_find_or_create_by_number(dev, cp.obj_id,
15498 + cp.variant_type);
15499 + if (obj) {
15500 + ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
15501 + if (!ok)
15502 + break;
15503 + if (obj->variant_type ==
15504 + YAFFS_OBJECT_TYPE_FILE) {
15505 + ok = yaffs2_rd_checkpt_tnodes(obj);
15506 + } else if (obj->variant_type ==
15507 + YAFFS_OBJECT_TYPE_HARDLINK) {
15508 + list_add(&obj->hard_links, &hard_list);
15510 + } else {
15511 + ok = 0;
15516 + if (ok)
15517 + yaffs_link_fixup(dev, &hard_list);
15519 + return ok ? 1 : 0;
15522 +static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
15524 + u32 checkpt_sum;
15525 + int ok;
15527 + yaffs2_get_checkpt_sum(dev, &checkpt_sum);
15529 + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
15530 + sizeof(checkpt_sum));
15532 + if (!ok)
15533 + return 0;
15535 + return 1;
15538 +static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
15540 + u32 checkpt_sum0;
15541 + u32 checkpt_sum1;
15542 + int ok;
15544 + yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
15546 + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
15547 + sizeof(checkpt_sum1));
15549 + if (!ok)
15550 + return 0;
15552 + if (checkpt_sum0 != checkpt_sum1)
15553 + return 0;
15555 + return 1;
15558 +static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
15560 + int ok = 1;
15562 + if (!yaffs2_checkpt_required(dev)) {
15563 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15564 + "skipping checkpoint write");
15565 + ok = 0;
15568 + if (ok)
15569 + ok = yaffs2_checkpt_open(dev, 1);
15571 + if (ok) {
15572 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15573 + "write checkpoint validity");
15574 + ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
15576 + if (ok) {
15577 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15578 + "write checkpoint device");
15579 + ok = yaffs2_wr_checkpt_dev(dev);
15581 + if (ok) {
15582 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15583 + "write checkpoint objects");
15584 + ok = yaffs2_wr_checkpt_objs(dev);
15586 + if (ok) {
15587 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15588 + "write checkpoint validity");
15589 + ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
15592 + if (ok)
15593 + ok = yaffs2_wr_checkpt_sum(dev);
15595 + if (!yaffs_checkpt_close(dev))
15596 + ok = 0;
15598 + if (ok)
15599 + dev->is_checkpointed = 1;
15600 + else
15601 + dev->is_checkpointed = 0;
15603 + return dev->is_checkpointed;
15606 +static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
15608 + int ok = 1;
15610 + if (!dev->param.is_yaffs2)
15611 + ok = 0;
15613 + if (ok && dev->param.skip_checkpt_rd) {
15614 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15615 + "skipping checkpoint read");
15616 + ok = 0;
15619 + if (ok)
15620 + ok = yaffs2_checkpt_open(dev, 0); /* open for read */
15622 + if (ok) {
15623 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15624 + "read checkpoint validity");
15625 + ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
15627 + if (ok) {
15628 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15629 + "read checkpoint device");
15630 + ok = yaffs2_rd_checkpt_dev(dev);
15632 + if (ok) {
15633 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15634 + "read checkpoint objects");
15635 + ok = yaffs2_rd_checkpt_objs(dev);
15637 + if (ok) {
15638 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15639 + "read checkpoint validity");
15640 + ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
15643 + if (ok) {
15644 + ok = yaffs2_rd_checkpt_sum(dev);
15645 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15646 + "read checkpoint checksum %d", ok);
15649 + if (!yaffs_checkpt_close(dev))
15650 + ok = 0;
15652 + if (ok)
15653 + dev->is_checkpointed = 1;
15654 + else
15655 + dev->is_checkpointed = 0;
15657 + return ok ? 1 : 0;
15660 +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
15662 + if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
15663 + dev->is_checkpointed = 0;
15664 + yaffs2_checkpt_invalidate_stream(dev);
15666 + if (dev->param.sb_dirty_fn)
15667 + dev->param.sb_dirty_fn(dev);
15670 +int yaffs_checkpoint_save(struct yaffs_dev *dev)
15672 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15673 + "save entry: is_checkpointed %d",
15674 + dev->is_checkpointed);
15676 + yaffs_verify_objects(dev);
15677 + yaffs_verify_blocks(dev);
15678 + yaffs_verify_free_chunks(dev);
15680 + if (!dev->is_checkpointed) {
15681 + yaffs2_checkpt_invalidate(dev);
15682 + yaffs2_wr_checkpt_data(dev);
15685 + yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
15686 + "save exit: is_checkpointed %d",
15687 + dev->is_checkpointed);
15689 + return dev->is_checkpointed;
15692 +int yaffs2_checkpt_restore(struct yaffs_dev *dev)
15694 + int retval;
15696 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15697 + "restore entry: is_checkpointed %d",
15698 + dev->is_checkpointed);
15700 + retval = yaffs2_rd_checkpt_data(dev);
15702 + if (dev->is_checkpointed) {
15703 + yaffs_verify_objects(dev);
15704 + yaffs_verify_blocks(dev);
15705 + yaffs_verify_free_chunks(dev);
15708 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15709 + "restore exit: is_checkpointed %d",
15710 + dev->is_checkpointed);
15712 + return retval;
15715 +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
15717 + /* if new_size > old_file_size.
15718 + * We're going to be writing a hole.
15719 + * If the hole is small then write zeros otherwise write a start
15720 + * of hole marker.
15721 + */
15722 + loff_t old_file_size;
15723 + loff_t increase;
15724 + int small_hole;
15725 + int result = YAFFS_OK;
15726 + struct yaffs_dev *dev = NULL;
15727 + u8 *local_buffer = NULL;
15728 + int small_increase_ok = 0;
15730 + if (!obj)
15731 + return YAFFS_FAIL;
15733 + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
15734 + return YAFFS_FAIL;
15736 + dev = obj->my_dev;
15738 + /* Bail out if not yaffs2 mode */
15739 + if (!dev->param.is_yaffs2)
15740 + return YAFFS_OK;
15742 + old_file_size = obj->variant.file_variant.file_size;
15744 + if (new_size <= old_file_size)
15745 + return YAFFS_OK;
15747 + increase = new_size - old_file_size;
15749 + if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
15750 + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
15751 + small_hole = 1;
15752 + else
15753 + small_hole = 0;
15755 + if (small_hole)
15756 + local_buffer = yaffs_get_temp_buffer(dev);
15758 + if (local_buffer) {
15759 + /* fill hole with zero bytes */
15760 + loff_t pos = old_file_size;
15761 + int this_write;
15762 + int written;
15763 + memset(local_buffer, 0, dev->data_bytes_per_chunk);
15764 + small_increase_ok = 1;
15766 + while (increase > 0 && small_increase_ok) {
15767 + this_write = increase;
15768 + if (this_write > dev->data_bytes_per_chunk)
15769 + this_write = dev->data_bytes_per_chunk;
15770 + written =
15771 + yaffs_do_file_wr(obj, local_buffer, pos, this_write,
15772 + 0);
15773 + if (written == this_write) {
15774 + pos += this_write;
15775 + increase -= this_write;
15776 + } else {
15777 + small_increase_ok = 0;
15781 + yaffs_release_temp_buffer(dev, local_buffer);
15783 + /* If out of space then reverse any chunks we've added */
15784 + if (!small_increase_ok)
15785 + yaffs_resize_file_down(obj, old_file_size);
15788 + if (!small_increase_ok &&
15789 + obj->parent &&
15790 + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
15791 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
15792 + /* Write a hole start header with the old file size */
15793 + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
15796 + return result;
15799 +struct yaffs_block_index {
15800 + int seq;
15801 + int block;
15804 +static int yaffs2_ybicmp(const void *a, const void *b)
15806 + int aseq = ((struct yaffs_block_index *)a)->seq;
15807 + int bseq = ((struct yaffs_block_index *)b)->seq;
15808 + int ablock = ((struct yaffs_block_index *)a)->block;
15809 + int bblock = ((struct yaffs_block_index *)b)->block;
15811 + if (aseq == bseq)
15812 + return ablock - bblock;
15814 + return aseq - bseq;
15817 +static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
15818 + struct yaffs_block_info *bi,
15819 + int blk, int chunk_in_block,
15820 + int *found_chunks,
15821 + u8 *chunk_data,
15822 + struct list_head *hard_list,
15823 + int summary_available)
15825 + struct yaffs_obj_hdr *oh;
15826 + struct yaffs_obj *in;
15827 + struct yaffs_obj *parent;
15828 + int equiv_id;
15829 + loff_t file_size;
15830 + int is_shrink;
15831 + int is_unlinked;
15832 + struct yaffs_ext_tags tags;
15833 + int result;
15834 + int alloc_failed = 0;
15835 + int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
15836 + struct yaffs_file_var *file_var;
15837 + struct yaffs_hardlink_var *hl_var;
15838 + struct yaffs_symlink_var *sl_var;
15840 + if (summary_available) {
15841 + result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
15842 + tags.seq_number = bi->seq_number;
15845 + if (!summary_available || tags.obj_id == 0) {
15846 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
15847 + dev->tags_used++;
15848 + } else {
15849 + dev->summary_used++;
15852 + /* Let's have a good look at this chunk... */
15854 + if (!tags.chunk_used) {
15855 + /* An unassigned chunk in the block.
15856 + * If there are used chunks after this one, then
15857 + * it is a chunk that was skipped due to failing
15858 + * the erased check. Just skip it so that it can
15859 + * be deleted.
15860 + * But, more typically, We get here when this is
15861 + * an unallocated chunk and his means that
15862 + * either the block is empty or this is the one
15863 + * being allocated from
15864 + */
15866 + if (*found_chunks) {
15867 + /* This is a chunk that was skipped due
15868 + * to failing the erased check */
15869 + } else if (chunk_in_block == 0) {
15870 + /* We're looking at the first chunk in
15871 + * the block so the block is unused */
15872 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
15873 + dev->n_erased_blocks++;
15874 + } else {
15875 + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
15876 + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
15877 + if (dev->seq_number == bi->seq_number) {
15878 + /* Allocating from this block*/
15879 + yaffs_trace(YAFFS_TRACE_SCAN,
15880 + " Allocating from %d %d",
15881 + blk, chunk_in_block);
15883 + bi->block_state =
15884 + YAFFS_BLOCK_STATE_ALLOCATING;
15885 + dev->alloc_block = blk;
15886 + dev->alloc_page = chunk_in_block;
15887 + dev->alloc_block_finder = blk;
15888 + } else {
15889 + /* This is a partially written block
15890 + * that is not the current
15891 + * allocation block.
15892 + */
15893 + yaffs_trace(YAFFS_TRACE_SCAN,
15894 + "Partially written block %d detected. gc will fix this.",
15895 + blk);
15900 + dev->n_free_chunks++;
15902 + } else if (tags.ecc_result ==
15903 + YAFFS_ECC_RESULT_UNFIXED) {
15904 + yaffs_trace(YAFFS_TRACE_SCAN,
15905 + " Unfixed ECC in chunk(%d:%d), chunk ignored",
15906 + blk, chunk_in_block);
15907 + dev->n_free_chunks++;
15908 + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
15909 + tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
15910 + tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
15911 + (tags.chunk_id > 0 &&
15912 + tags.n_bytes > dev->data_bytes_per_chunk) ||
15913 + tags.seq_number != bi->seq_number) {
15914 + yaffs_trace(YAFFS_TRACE_SCAN,
15915 + "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
15916 + blk, chunk_in_block, tags.obj_id,
15917 + tags.chunk_id, tags.n_bytes);
15918 + dev->n_free_chunks++;
15919 + } else if (tags.chunk_id > 0) {
15920 + /* chunk_id > 0 so it is a data chunk... */
15921 + loff_t endpos;
15922 + loff_t chunk_base = (tags.chunk_id - 1) *
15923 + dev->data_bytes_per_chunk;
15925 + *found_chunks = 1;
15927 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
15928 + bi->pages_in_use++;
15930 + in = yaffs_find_or_create_by_number(dev,
15931 + tags.obj_id,
15932 + YAFFS_OBJECT_TYPE_FILE);
15933 + if (!in)
15934 + /* Out of memory */
15935 + alloc_failed = 1;
15937 + if (in &&
15938 + in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
15939 + chunk_base < in->variant.file_variant.shrink_size) {
15940 + /* This has not been invalidated by
15941 + * a resize */
15942 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
15943 + chunk, -1))
15944 + alloc_failed = 1;
15946 + /* File size is calculated by looking at
15947 + * the data chunks if we have not
15948 + * seen an object header yet.
15949 + * Stop this practice once we find an
15950 + * object header.
15951 + */
15952 + endpos = chunk_base + tags.n_bytes;
15954 + if (!in->valid &&
15955 + in->variant.file_variant.scanned_size < endpos) {
15956 + in->variant.file_variant.
15957 + scanned_size = endpos;
15958 + in->variant.file_variant.
15959 + file_size = endpos;
15961 + } else if (in) {
15962 + /* This chunk has been invalidated by a
15963 + * resize, or a past file deletion
15964 + * so delete the chunk*/
15965 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
15967 + } else {
15968 + /* chunk_id == 0, so it is an ObjectHeader.
15969 + * Thus, we read in the object header and make
15970 + * the object
15971 + */
15972 + *found_chunks = 1;
15974 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
15975 + bi->pages_in_use++;
15977 + oh = NULL;
15978 + in = NULL;
15980 + if (tags.extra_available) {
15981 + in = yaffs_find_or_create_by_number(dev,
15982 + tags.obj_id,
15983 + tags.extra_obj_type);
15984 + if (!in)
15985 + alloc_failed = 1;
15988 + if (!in ||
15989 + (!in->valid && dev->param.disable_lazy_load) ||
15990 + tags.extra_shadows ||
15991 + (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
15992 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
15994 + /* If we don't have valid info then we
15995 + * need to read the chunk
15996 + * TODO In future we can probably defer
15997 + * reading the chunk and living with
15998 + * invalid data until needed.
15999 + */
16001 + result = yaffs_rd_chunk_tags_nand(dev,
16002 + chunk,
16003 + chunk_data,
16004 + NULL);
16006 + oh = (struct yaffs_obj_hdr *)chunk_data;
16008 + if (dev->param.inband_tags) {
16009 + /* Fix up the header if they got
16010 + * corrupted by inband tags */
16011 + oh->shadows_obj =
16012 + oh->inband_shadowed_obj_id;
16013 + oh->is_shrink =
16014 + oh->inband_is_shrink;
16017 + if (!in) {
16018 + in = yaffs_find_or_create_by_number(dev,
16019 + tags.obj_id, oh->type);
16020 + if (!in)
16021 + alloc_failed = 1;
16025 + if (!in) {
16026 + /* TODO Hoosterman we have a problem! */
16027 + yaffs_trace(YAFFS_TRACE_ERROR,
16028 + "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
16029 + tags.obj_id, chunk);
16030 + return YAFFS_FAIL;
16033 + if (in->valid) {
16034 + /* We have already filled this one.
16035 + * We have a duplicate that will be
16036 + * discarded, but we first have to suck
16037 + * out resize info if it is a file.
16038 + */
16039 + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
16040 + ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
16041 + (tags.extra_available &&
16042 + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
16043 + )) {
16044 + loff_t this_size = (oh) ?
16045 + yaffs_oh_to_size(oh) :
16046 + tags.extra_file_size;
16047 + u32 parent_obj_id = (oh) ?
16048 + oh->parent_obj_id :
16049 + tags.extra_parent_id;
16051 + is_shrink = (oh) ?
16052 + oh->is_shrink :
16053 + tags.extra_is_shrink;
16055 + /* If it is deleted (unlinked
16056 + * at start also means deleted)
16057 + * we treat the file size as
16058 + * being zeroed at this point.
16059 + */
16060 + if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
16061 + parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
16062 + this_size = 0;
16063 + is_shrink = 1;
16066 + if (is_shrink &&
16067 + in->variant.file_variant.shrink_size >
16068 + this_size)
16069 + in->variant.file_variant.shrink_size =
16070 + this_size;
16072 + if (is_shrink)
16073 + bi->has_shrink_hdr = 1;
16075 + /* Use existing - destroy this one. */
16076 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
16079 + if (!in->valid && in->variant_type !=
16080 + (oh ? oh->type : tags.extra_obj_type)) {
16081 + yaffs_trace(YAFFS_TRACE_ERROR,
16082 + "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
16083 + oh ? oh->type : tags.extra_obj_type,
16084 + in->variant_type, tags.obj_id,
16085 + chunk);
16086 + in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
16089 + if (!in->valid &&
16090 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
16091 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
16092 + /* We only load some info, don't fiddle
16093 + * with directory structure */
16094 + in->valid = 1;
16096 + if (oh) {
16097 + in->yst_mode = oh->yst_mode;
16098 + yaffs_load_attribs(in, oh);
16099 + in->lazy_loaded = 0;
16100 + } else {
16101 + in->lazy_loaded = 1;
16103 + in->hdr_chunk = chunk;
16105 + } else if (!in->valid) {
16106 + /* we need to load this info */
16107 + in->valid = 1;
16108 + in->hdr_chunk = chunk;
16109 + if (oh) {
16110 + in->variant_type = oh->type;
16111 + in->yst_mode = oh->yst_mode;
16112 + yaffs_load_attribs(in, oh);
16114 + if (oh->shadows_obj > 0)
16115 + yaffs_handle_shadowed_obj(dev,
16116 + oh->shadows_obj, 1);
16118 + yaffs_set_obj_name_from_oh(in, oh);
16119 + parent = yaffs_find_or_create_by_number(dev,
16120 + oh->parent_obj_id,
16121 + YAFFS_OBJECT_TYPE_DIRECTORY);
16122 + file_size = yaffs_oh_to_size(oh);
16123 + is_shrink = oh->is_shrink;
16124 + equiv_id = oh->equiv_id;
16125 + } else {
16126 + in->variant_type = tags.extra_obj_type;
16127 + parent = yaffs_find_or_create_by_number(dev,
16128 + tags.extra_parent_id,
16129 + YAFFS_OBJECT_TYPE_DIRECTORY);
16130 + file_size = tags.extra_file_size;
16131 + is_shrink = tags.extra_is_shrink;
16132 + equiv_id = tags.extra_equiv_id;
16133 + in->lazy_loaded = 1;
16135 + in->dirty = 0;
16137 + if (!parent)
16138 + alloc_failed = 1;
16140 + /* directory stuff...
16141 + * hook up to parent
16142 + */
16144 + if (parent &&
16145 + parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
16146 + /* Set up as a directory */
16147 + parent->variant_type =
16148 + YAFFS_OBJECT_TYPE_DIRECTORY;
16149 + INIT_LIST_HEAD(&parent->
16150 + variant.dir_variant.children);
16151 + } else if (!parent ||
16152 + parent->variant_type !=
16153 + YAFFS_OBJECT_TYPE_DIRECTORY) {
16154 + /* Hoosterman, another problem....
16155 + * Trying to use a non-directory as a directory
16156 + */
16158 + yaffs_trace(YAFFS_TRACE_ERROR,
16159 + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
16160 + );
16161 + parent = dev->lost_n_found;
16163 + yaffs_add_obj_to_dir(parent, in);
16165 + is_unlinked = (parent == dev->del_dir) ||
16166 + (parent == dev->unlinked_dir);
16168 + if (is_shrink)
16169 + /* Mark the block */
16170 + bi->has_shrink_hdr = 1;
16172 + /* Note re hardlinks.
16173 + * Since we might scan a hardlink before its equivalent
16174 + * object is scanned we put them all in a list.
16175 + * After scanning is complete, we should have all the
16176 + * objects, so we run through this list and fix up all
16177 + * the chains.
16178 + */
16180 + switch (in->variant_type) {
16181 + case YAFFS_OBJECT_TYPE_UNKNOWN:
16182 + /* Todo got a problem */
16183 + break;
16184 + case YAFFS_OBJECT_TYPE_FILE:
16185 + file_var = &in->variant.file_variant;
16186 + if (file_var->scanned_size < file_size) {
16187 + /* This covers the case where the file
16188 + * size is greater than the data held.
16189 + * This will happen if the file is
16190 + * resized to be larger than its
16191 + * current data extents.
16192 + */
16193 + file_var->file_size = file_size;
16194 + file_var->scanned_size = file_size;
16197 + if (file_var->shrink_size > file_size)
16198 + file_var->shrink_size = file_size;
16200 + break;
16201 + case YAFFS_OBJECT_TYPE_HARDLINK:
16202 + hl_var = &in->variant.hardlink_variant;
16203 + if (!is_unlinked) {
16204 + hl_var->equiv_id = equiv_id;
16205 + list_add(&in->hard_links, hard_list);
16207 + break;
16208 + case YAFFS_OBJECT_TYPE_DIRECTORY:
16209 + /* Do nothing */
16210 + break;
16211 + case YAFFS_OBJECT_TYPE_SPECIAL:
16212 + /* Do nothing */
16213 + break;
16214 + case YAFFS_OBJECT_TYPE_SYMLINK:
16215 + sl_var = &in->variant.symlink_variant;
16216 + if (oh) {
16217 + sl_var->alias =
16218 + yaffs_clone_str(oh->alias);
16219 + if (!sl_var->alias)
16220 + alloc_failed = 1;
16222 + break;
16226 + return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
16229 +int yaffs2_scan_backwards(struct yaffs_dev *dev)
16231 + int blk;
16232 + int block_iter;
16233 + int start_iter;
16234 + int end_iter;
16235 + int n_to_scan = 0;
16236 + enum yaffs_block_state state;
16237 + int c;
16238 + int deleted;
16239 + LIST_HEAD(hard_list);
16240 + struct yaffs_block_info *bi;
16241 + u32 seq_number;
16242 + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
16243 + u8 *chunk_data;
16244 + int found_chunks;
16245 + int alloc_failed = 0;
16246 + struct yaffs_block_index *block_index = NULL;
16247 + int alt_block_index = 0;
16248 + int summary_available;
16250 + yaffs_trace(YAFFS_TRACE_SCAN,
16251 + "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
16252 + dev->internal_start_block, dev->internal_end_block);
16254 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
16256 + block_index =
16257 + kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
16259 + if (!block_index) {
16260 + block_index =
16261 + vmalloc(n_blocks * sizeof(struct yaffs_block_index));
16262 + alt_block_index = 1;
16265 + if (!block_index) {
16266 + yaffs_trace(YAFFS_TRACE_SCAN,
16267 + "yaffs2_scan_backwards() could not allocate block index!"
16268 + );
16269 + return YAFFS_FAIL;
16272 + dev->blocks_in_checkpt = 0;
16274 + chunk_data = yaffs_get_temp_buffer(dev);
16276 + /* Scan all the blocks to determine their state */
16277 + bi = dev->block_info;
16278 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
16279 + blk++) {
16280 + yaffs_clear_chunk_bits(dev, blk);
16281 + bi->pages_in_use = 0;
16282 + bi->soft_del_pages = 0;
16284 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
16286 + bi->block_state = state;
16287 + bi->seq_number = seq_number;
16289 + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
16290 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
16291 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
16292 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
16294 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
16295 + "Block scanning block %d state %d seq %d",
16296 + blk, bi->block_state, seq_number);
16298 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
16299 + dev->blocks_in_checkpt++;
16301 + } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
16302 + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
16303 + "block %d is bad", blk);
16304 + } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
16305 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
16306 + dev->n_erased_blocks++;
16307 + dev->n_free_chunks += dev->param.chunks_per_block;
16308 + } else if (bi->block_state ==
16309 + YAFFS_BLOCK_STATE_NEEDS_SCAN) {
16310 + /* Determine the highest sequence number */
16311 + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
16312 + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
16313 + block_index[n_to_scan].seq = seq_number;
16314 + block_index[n_to_scan].block = blk;
16315 + n_to_scan++;
16316 + if (seq_number >= dev->seq_number)
16317 + dev->seq_number = seq_number;
16318 + } else {
16319 + /* TODO: Nasty sequence number! */
16320 + yaffs_trace(YAFFS_TRACE_SCAN,
16321 + "Block scanning block %d has bad sequence number %d",
16322 + blk, seq_number);
16325 + bi++;
16328 + yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
16330 + cond_resched();
16332 + /* Sort the blocks by sequence number */
16333 + sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
16334 + yaffs2_ybicmp, NULL);
16336 + cond_resched();
16338 + yaffs_trace(YAFFS_TRACE_SCAN, "...done");
16340 + /* Now scan the blocks looking at the data. */
16341 + start_iter = 0;
16342 + end_iter = n_to_scan - 1;
16343 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
16345 + /* For each block.... backwards */
16346 + for (block_iter = end_iter;
16347 + !alloc_failed && block_iter >= start_iter;
16348 + block_iter--) {
16349 + /* Cooperative multitasking! This loop can run for so
16350 + long that watchdog timers expire. */
16351 + cond_resched();
16353 + /* get the block to scan in the correct order */
16354 + blk = block_index[block_iter].block;
16355 + bi = yaffs_get_block_info(dev, blk);
16356 + deleted = 0;
16358 + summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
16360 + /* For each chunk in each block that needs scanning.... */
16361 + found_chunks = 0;
16362 + if (summary_available)
16363 + c = dev->chunks_per_summary - 1;
16364 + else
16365 + c = dev->param.chunks_per_block - 1;
16367 + for (/* c is already initialised */;
16368 + !alloc_failed && c >= 0 &&
16369 + (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
16370 + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
16371 + c--) {
16372 + /* Scan backwards...
16373 + * Read the tags and decide what to do
16374 + */
16375 + if (yaffs2_scan_chunk(dev, bi, blk, c,
16376 + &found_chunks, chunk_data,
16377 + &hard_list, summary_available) ==
16378 + YAFFS_FAIL)
16379 + alloc_failed = 1;
16382 + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
16383 + /* If we got this far while scanning, then the block
16384 + * is fully allocated. */
16385 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
16388 + /* Now let's see if it was dirty */
16389 + if (bi->pages_in_use == 0 &&
16390 + !bi->has_shrink_hdr &&
16391 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
16392 + yaffs_block_became_dirty(dev, blk);
16396 + yaffs_skip_rest_of_block(dev);
16398 + if (alt_block_index)
16399 + vfree(block_index);
16400 + else
16401 + kfree(block_index);
16403 + /* Ok, we've done all the scanning.
16404 + * Fix up the hard link chains.
16405 + * We have scanned all the objects, now it's time to add these
16406 + * hardlinks.
16407 + */
16408 + yaffs_link_fixup(dev, &hard_list);
16410 + yaffs_release_temp_buffer(dev, chunk_data);
16412 + if (alloc_failed)
16413 + return YAFFS_FAIL;
16415 + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
16417 + return YAFFS_OK;
16419 diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.4.90/fs/yaffs2/yaffs_yaffs2.h
16420 --- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
16421 +++ linux-3.4.90/fs/yaffs2/yaffs_yaffs2.h 2014-05-17 15:08:09.000000000 +0200
16422 @@ -0,0 +1,39 @@
16424 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16426 + * Copyright (C) 2002-2011 Aleph One Ltd.
16427 + * for Toby Churchill Ltd and Brightstar Engineering
16429 + * Created by Charles Manning <charles@aleph1.co.uk>
16431 + * This program is free software; you can redistribute it and/or modify
16432 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16433 + * published by the Free Software Foundation.
16435 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16436 + */
16438 +#ifndef __YAFFS_YAFFS2_H__
16439 +#define __YAFFS_YAFFS2_H__
16441 +#include "yaffs_guts.h"
16443 +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
16444 +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
16445 +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
16446 + struct yaffs_block_info *bi);
16447 +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
16448 + struct yaffs_block_info *bi);
16449 +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
16450 +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
16451 +int yaffs2_checkpt_required(struct yaffs_dev *dev);
16452 +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
16454 +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
16455 +int yaffs2_checkpt_save(struct yaffs_dev *dev);
16456 +int yaffs2_checkpt_restore(struct yaffs_dev *dev);
16458 +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
16459 +int yaffs2_scan_backwards(struct yaffs_dev *dev);
16461 +#endif
16462 diff -Nur linux-3.4.90.orig/fs/yaffs2/yportenv.h linux-3.4.90/fs/yaffs2/yportenv.h
16463 --- linux-3.4.90.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
16464 +++ linux-3.4.90/fs/yaffs2/yportenv.h 2014-05-17 15:08:09.000000000 +0200
16465 @@ -0,0 +1,85 @@
16467 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16469 + * Copyright (C) 2002-2011 Aleph One Ltd.
16470 + * for Toby Churchill Ltd and Brightstar Engineering
16472 + * Created by Charles Manning <charles@aleph1.co.uk>
16474 + * This program is free software; you can redistribute it and/or modify
16475 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16476 + * published by the Free Software Foundation.
16478 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16479 + */
16481 +#ifndef __YPORTENV_H__
16482 +#define __YPORTENV_H__
16485 + * Define the MTD version in terms of Linux Kernel versions
16486 + * This allows yaffs to be used independantly of the kernel
16487 + * as well as with it.
16488 + */
16490 +#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
16492 +#ifdef YAFFS_OUT_OF_TREE
16493 +#include "moduleconfig.h"
16494 +#endif
16496 +#include <linux/version.h>
16497 +#define MTD_VERSION_CODE LINUX_VERSION_CODE
16499 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
16500 +#include <linux/config.h>
16501 +#endif
16502 +#include <linux/version.h>
16503 +#include <linux/kernel.h>
16504 +#include <linux/mm.h>
16505 +#include <linux/sched.h>
16506 +#include <linux/string.h>
16507 +#include <linux/slab.h>
16508 +#include <linux/vmalloc.h>
16509 +#include <linux/xattr.h>
16510 +#include <linux/list.h>
16511 +#include <linux/types.h>
16512 +#include <linux/fs.h>
16513 +#include <linux/stat.h>
16514 +#include <linux/sort.h>
16515 +#include <linux/bitops.h>
16517 +/* These type wrappings are used to support Unicode names in WinCE. */
16518 +#define YCHAR char
16519 +#define YUCHAR unsigned char
16520 +#define _Y(x) x
16522 +#define YAFFS_LOSTNFOUND_NAME "lost+found"
16523 +#define YAFFS_LOSTNFOUND_PREFIX "obj"
16526 +#define YAFFS_ROOT_MODE 0755
16527 +#define YAFFS_LOSTNFOUND_MODE 0700
16529 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
16530 +#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
16531 +#define Y_TIME_CONVERT(x) (x).tv_sec
16532 +#else
16533 +#define Y_CURRENT_TIME CURRENT_TIME
16534 +#define Y_TIME_CONVERT(x) (x)
16535 +#endif
16537 +#define compile_time_assertion(assertion) \
16538 + ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
16541 +#define yaffs_printf(msk, fmt, ...) \
16542 + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
16544 +#define yaffs_trace(msk, fmt, ...) do { \
16545 + if (yaffs_trace_mask & (msk)) \
16546 + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
16547 +} while (0)
16550 +#endif